"Go, geleceğin sunucu dili olacak." — Shopify Kurucusu ve CEO'su Tobias Lütke


Son birkaç senedir yükselen yeni bir programlama dili var: Go (veya GoLang). Bir yazılımcıyı, yeni bir programlama dilinden daha çok ne heyecanlandırabilir ki? Ben de bu yüzden 4-5 ay önce Go öğrenmeye başladım ve şimdi de size neden bu yeni dili öğrenmeniz gerektiğini açıklayacağım.

Bu konuda nasıl “Hello World!!” yazabileceğinizi anlatmayacağım. Bunun için zaten birçok kaynak bulabilirsiniz. Bu konuda asıl olarak bilgisayardaki donanım-yazılım dengesinin şu anki noktasını ve neden Go gibi yeni bir dile ihtiyaç duyduğumuzu açıklayacağım. Eğer ortada bir sorun olmasaydı, çözüme de ihtiyaç duymazdık.


Donanım Kısıtlamaları

Moore Yasası çöküyor.

İlk olarak; 3.0 GHz hızlı Pentium 4, Intel tarafından 2004'de tanıtılmıştı. Bugün ise, benim kullandığım Macbook Pro 2016'nın çalışma hızı 2.9 GHz. Hemen hemen 10 küsur senedir ilk günkü işlemci gücünden pek bir ilerleme olmamış. Aşağıdaki çizelgede zamanla artan işlemci gücünün karşılaştırmasını görebilirsiniz:


Yukarıdaki çizelgede tek çekirdek performansını ve 10 küsur senedir istikrarlı bir şekilde kalan işlemci frekansını görebilirsiniz. Eğer, daha fazla transistör eklemenin çözüm olduğunu düşünüyorsanız o zaman yanılıyorsunuz. Bunun nedenleri ise en küçük ölçekte bazı kuantum özelliklerinin ortaya çıkmaya çıkması (tünelleme gibi), fazladan transistör ekleme yolundan daha pahalıya mal olması ve dolar başına ekleyebileceğiniz transistör sayısı düşmeye başlamasıdır.

Demek ki, yukarıdaki sorunun çözümü için;


  • İmalatçılar işlemciye gittikçe daha fazla çekirdek koydu.
    Şu sıralar mevcutta sadece quad-core (4) ve octa-core (8) işlemciler var.
    (Lakin şu sıralar dediği yani makalenin orijinalinin yayınlanma tarihi 2017 Ocak, bu tarihten sonra 16 çekirdekli işlemciler çıktı ve hatta yolda 32 çekirdekli işlemciler de var.)

  • Hyper-threading denilen bir kavram da tanıtıldı. Türkçe anlamı biri bitmeden diğerine başlamak şeklindedir. Teknolojideki bu ismin nedeni ise normalde bir çekirdek sadece bir thread işleyebilirken bununla birlikte birden fazla thread'in tek bir çekirdekte işlenebilmesidir.

  • Performansı yükseltmek maksatlı işlemciye daha fazla önbellek eklendi.



Ama yukarıdaki her bir çözüm önerisinin kendince bir kısıtlaması da var. Performansı yükseltmek maksatlı işlemciye daha da fazla önbellek ekleyemezsin çünkü önbelleklerin fiziksel sınırları var: ne kadar büyük önbellek, o kadar yavaşlık. İşlemciye daha fazla çekirdek eklemek de maliyetini arttırır.

Böylecene; eğer donanımdaki gelişime güvenemiyorsak, performansı arttırmak için yapılacak tek şey daha etkili yazılımlardır. Ama ne yazık ki günümüz programlama dilleri bu denli etkili değiller.

"Bugünkü işlemciler, nitro yakıtlı güçlü motor takılmış yarış otomobili gibiler; 400 metrede harikalar.
Maalesef günümüz programlama dilleri Monte Carlo gibiler, girdi çıktılarla dolular.
"

— Apple'da Yazılım Mühendisi David Ungar


Go'nun Goroutine'i Var!

Yukarıda da bahsi geçtiği üzere, donanım imalatçıları performansı arttırmak için işlemciye gittikçe daha fazla çekirdek ekliyorlar. Tüm veri merkezleri bu işlemcilerde yürütülüyor, bu nedenle gelecek yıllarda çekirdek sayısının artmasını bekleyebiliriz. Buna ek olarak günümüz uygulamaları, veritabanı bağlantılarını sağlama, mesaj kuyrukları ve önbellek sağlama için birçok mikroservis kullanıyor. Bu yüzden, geliştirdiğimiz yazılım ve programlama dili rahatlıkla aynı anda kullanımı desteklemeli ve artan çekirdek sayısıyla ölçeklenebilir olmalı.

Lakin çoğu günümüz programlama dilleri (Java, Python vb. gibi), 90'ların tek thread'li zamanlarından kalma. Bu programlama dillerinin çoğu multi-threading'i destekliyor. Ama asıl sorun, eş zamanlı çalışma, threading kilitleme, yarışma durumu ve ölümcül kilitlenme ile beraber geliyor. Bu saydıklarım, o dillerde multi-threading uygulamalarını oluşturmayı zorlaştırıyor.

Örneğin, Java'da yeni bir thread oluşturmak belleği çok etkilemez. Her bir thread yaklaşık heap'ten 1 mb. bellek boyutu kullanır ve nihayetinde binlerce thread'i döndürmeye başlarsanız heap üstüne koskoca bir yük bindirmiş olursunuz ve bu da yetersiz bellek yüzünden çökmeye sebep olacaktır. Ayrıca, iki veya daha fazla thread arasında iletişim sağlamak isterseniz bu da çok güç olacaktır.

Bunun yanısıra Go, çok çekirdekli işlemcilerin çoktan var olduğu 2009 yılında çıkmıştı. Go işte bu yüzden aynı anda kullanım terimini akılda tutarak oluşturuldu. Go'da thread yerine goroutine var. Heap'ten yaklaşık 2 kb. bellek harcar. Bu yüzden her ne zaman istersen goroutine'den milyonlarcasını birden döndürebilirsin.


Diğer yararları şöyledir:


  • Goroutine'de büyütülebilir bölünmüş stack'ler var. Bu demek oluyor ki sadece ihtiyaç halinde daha fazla bellek kullanacak.

  • Goroutine, thread'e göre daha hızlı bir başlatıma sahip.

  • Goroutine, kendileri (kanallar) arasında güvenli iletişim için yerleşik temellerle gelir.

  • Goroutine, veri yapılarını paylaşırken muteks kilitlemeye başvurmaktan kaçınmanıza izin verir.

  • Ayriyeten Goroutine'de ve OS thread'lerinde 1:1 eşleştirme yoktur. Yalnız bir Goroutine, çoklu thread'lerde yürütülebilir. Goroutine, birkaç OS thread'inin çoğullamalı halidir.



Yukarıdaki tüm noktalar; Erlang gibi, aynı anda kullanım çalıştırma kodunu dümdüz ve güzelken Go'yu (Java, C ve C++ gibi) aynı anda kullanımı idare etme açısından çok güçlü yapıyor.


Go, donanıma öncelikli olarak erişir.

Java ve Python gibi diğer günümüz yüksek seviyeli dillere nazaran C ve C++ kullanmanın en faydalı kısmı, performanslarıdır. Çünkü C ve C++ yorumlanan değil derlenen dillerdir.

İşlemciler, sadece ikililerden anlarlar. Genelde, Java veya JVM tabanlı diğer dillerden uygulama yaparken projeni derlediğinde bizlerin okuyabildiği kodları JVM veya diğer sanal makineler tarafından anlaşılabilen bayt kodlarına derler. Çalıştırma esnasında sanal makine bu byte kodları yorumlar ve işlemcilerin anlayabileceği ikililere dönüştürür.

Öte yandan C ve C++, sanal makinede çalıştırılmaz. Bu ise komut çevriminde bir adımı kaldırır ve performansı arttırır. Bizlerin okuyabildiği kodları direkt olarak ikililere derler.


Çoğu programlama dilleri nesne kaldırmayı Garbage Collector (Çöp Toplama) veya Reference Counting (Referans Sayacı) algoritmaları ile hallediyor.

Go, her ikisinin de en iyisini getiriyor. Düşük seviyeli diller gibi (örneğin C ve C++) Go da derlenen bir dildir. Bu demektir ki performansı, düşük seviyeli dillerinkine çok yakındır. Ayriyeten nesneyi kaldırmak için de Garbage Collector'ı kullanır. Bu yüzden, artık malloc() ve free() komutlarına gerek yok.

Go'da yazılmış kodları devam ettirmesi kolaydır.

Size şunu söyleyeyim. Go'da, diğer dillerinde olduğu gibi o manyak programlama syntax'ı yoktur. Bu syntax gayet tertipli ve temizdir.

Google'daki Go'nun tasarımcıları, bu dili oluştururken şunu her zaman akıllarında tutmuşlar. Google'ın çok geniş bir kod temeli olduğundan ve aynı kod temelinde binlerce geliştirici çalıştığından, diğer geliştiricilerin anlaması için kod yapısı basit tutulmalı ve kodun bir parçasında, başka bir parça kod için olabilecek en düşük yan etki olmalı. İşte bu, bir kodu kolayca bakılabilir ve düzenlemesi zahmetsiz yapar.

Go'da, bilerek günümüz nesne yönelimli programlama dillerinden bazı özellikleri dahil edilmemiştir:


  • Sınıf (class) denen bir şey yok. Her şey sadece paketlere bölünmüştür. Go'da sınıf yerine sadece structs vardır.

  • Kalıtımı desteklemez. Bu, kodunuzu düzenlemeyi zahmetsiz yapar. Java veya Python gibi diğer dillerde eğer ABC sınıfı XYZ sınıfını kalıtıyorsa ve siz de XYZ sınıfında bazı değişiklikler yaparsanız XYZ'yi kalıtan diğer sınıflarda bazı yan etkilere sebep olabilir. Kalıtımı kaldırarak (bir parça koda bakarken, dikkat etmemiz gereken bir süper sınıf olmadığından) Go, kodu anlamayı kolaylaştırıyor.

  • Yapılandırıcılar yok.

  • Annotations yok.

  • Jenerikler yok.

  • İstisnalar yok.


Yukarıdaki değişiklikler Go'yu diğer dillerden çok farklı ve Go'da programlamayı da diğerlerinden farklı yapıyor. Yukarıdaki maddelerden bazıları hoşunuza gitmemiş olabilir. Ama yukarıda saydığım özellikler olmadan uygulamanızı kodlayamazsınız gibi bir durum da yok. Tek yapmanız gereken fazladan 2-3 satır kod eklemek. Ama olumlu yönü ise kodunuzu daha temiz yapması ve kodunuza anlaşılırlık katması.


Yukarıdaki çizelge Go'nun kod syntax'ını Ruby, Python ve diğer diller gibi basit tutarken, neredeyse C ve C++ kadar da etkili olduğunu gösteriyor. Bu, hem insanlar hem de işlemciler için kazan kazan stratejisi demektir.

Swift gibi yeni dillere nazaran Go'nun syntax'ı çok stabildir. 2012'de ilk yayınlandığı 1.0 sürümünden beri aynı kaldı. Bu, onun öncesiyle uyumlu olma özelliğidir.

Go, Google desteklidir.

Bunun direkt bir teknik avantaj olmadığını biliyorum lakin Go, Google tarafından tasarlanmış ve desteklenmiştir. Google, dünyadaki en büyük bulut altyapılarından birine sahip. Go, Google tarafından ölçeklenebilirliği ve etkililiği destekleme sorunlarını çözmek için tasarlanmıştır. Bunlar, kendi sunucularınızı oluştururken karşılaşacağınız sorunların aynısıdır.

Adobe, BBC, IBM ve Intel gibi büyük firmaların da içinde olduğu, Go'yu kullanan firmaların listei:
https://github.com/golang/go/wiki/GoUsers

Sonuç olarak:

Go, diğer nesne yönelimli dillerden çok farklı olsa bile gayet iyi. Go size, C ve C++ gibi yüksek performans, Java gibi süper etkili derecede aynı anda kullanımı idare etmeyi ve Python ve Perl gibi kodlarken eğlenmeyi sağlar.

Eğer Go'yu öğrenmek için herhangi bir planınız yoksa, yine de donanım kısıtlamalarının biz yazılım geliştiricilerine süper etkili kod yazma üzerine baskı yaptığını söyleyeceğim. Geliştirici, donanımdan anlamalı ve programını bu doğrultuda en uygun hale getirmeli. Uygun hale getirilmiş yazılımlar (IoT cihazlar gibi) en ucuz ve yavaş donanımlarda bile çalışabilir.