go-gopher-go-programming-language-by-google.webp

Selamlar dostlar 🤗
Bugün sizlerle son birkaç aydır hayatımın resmen merkezine oturan, elimden düşüremediğim bir programlama dilinden bahsedeceğim. Go piyasada Golang diye de geçer. Bu rehberde size neden Go öğrenmeniz lazım, hangi alanlarda işinize yarar ve bu dil neden durup dururken bu kadar patladı, hepsini tek tek anlatacağım. Çayınızı kahvenizi alın, başlıyoruz.

Go Nedir ve Nerden Çıktı Bu?

Şimdi bu Go olayı 2009 yılında Google tarafından geliştirildi. Arkasındaki ekip şampiyonlar ligi gibi. Robert Griesemer, Rob Pike ve Ken Thompson. Bu adamlar C dilini ve Unix'i yaratan efsaneler biliyorsunuz, yani ne yaptıklarını gayet iyi biliyolar, boş adam değiller :)

Peki durduk yere niye "hadi yeni dil yapalım" dediler? Çünkü Google'da milyonlarca satır kod var ve o zamanlar derleme süreleri saatler sürüyormuş. İllallah etmişler yani. Mevcut diller de ya çok karmaşık ya da modern donanımı, işlemcileri verimli kullanamıyor. Go, tam da bu dertlere derman olsun, işler hızlansın diye tasarlandı.

Go'nun Güçlü Yanları

Go'nun en hasta olduğum özelliği sadeliği abi. Dilin topu topu 25 tane anahtar kelimesi var. Şöyle bi kıyaslayalım da farkı görün:
  • C++ → 80+ anahtar kelime
  • Java → 50+ anahtar kelime
  • Python → 35 anahtar kelime
  • Go → 25 anahtar kelime
Bu ne anlama geliyor? Dili öğrenmesi çocuk oyuncağı. Ben daha önce az buçuk Python ve JavaScript ile uğraşıyodum, Go'yu temel seviyede kavramam 2-3 haftamı aldı almadı. Syntax'ı (sözdizimi) o kadar temiz ki, başkasının yazdığı kodu okumak bile keyifli, bulmaca çözer gibi uğraşmıyosunuz.

2. Derleme Hızı

Go'nun derleme hızı şaka gibi arkadaşlar. Milyonlarca satır kod saniyeler içinde derleniyor. Bu özellik özellikle büyük projelerde çalışırken hayat kurtarıyor. Eskiden C++ projelerinde derlemeye basıp kahve molasına çıkardım, Go'da gözümü kırpana kadar işlem bitiyor.

3. Yerleşik Eşzamanlılık (Concurrency)

İşte Go'nun en parladığı nokta burası. Goroutine'ler. Eşzamanlı programlama yapmak hiç bu kadar kolay olmamıştı valla. Bi fonksiyonun başına go yazıyosunuz ve boom, o fonksiyon artık ayrı bi thread'de çalışıyo (teknik olarak goroutine ama siz anladınız).
Kod:
go fonksiyonAdi() // Bu kadar basit işte.
Goroutine'ler normal thread'lere göre tüy gibi hafif. Bir thread sistemde yaklaşık 1 MB yer kaplarken, bir goroutine sadece 2 KB ile başlıyor. Yani binlerce goroutine'i aynı anda çalıştırın, bana mısın demez.

4. Garbage Collection (Çöp Toplama)

Go'da bellek yönetimi otomatik. C'deki o meşhur malloc/free belasıyla uğraşmıyorsunuz. Garbage Collector arka planda sessiz sedasız çalışıyor ve kullanılmayan bellekleri temizliyor.

Meraklısına detay vereyim, Go'nun GC'si üç renkli işaretleme algoritması kullanıyor:
  • Beyaz: Henüz bakılmamış nesneler
  • Gri: İnceleniyo, referanslarına bakılıyo
  • Siyah: İncelendi, hala kullanılıyo
GC, "stop-the-world" denilen donma olayını minimuma indirecek şekilde tasarlanmış, yani çöp toplanırken uygulamanız takılmıyor.

5. Statik Tipleme Ama Akıllıca

Go statik tipli bir dil ama "tip çıkarımı" (type inference) sayesinde her yere amele gibi tip yazmak zorunda değilsiniz:
Kod:
// İkisi de aynı kapıya çıkıyo
var isim string = "Kaan"
isim := "Kaan" // Go burda tipi kendi anlıyo, canını yerim :)


Go mu Python mu?

Çok kafa karıştırıyor bu mevzu, o yüzden şuna bi açıklık getireyim detaylıca:
Performans
Python yorumlanan (interpreted) bir dil, Go ise derlenen (compiled) bir dil. Pratikte bu ne demek?
  • Go: Doğrudan makine koduna derlenir, C'ye yakın performans verir.
  • Python: Satır satır yorumlanır, Go'dan 10-100 kat daha yavaş kalabilir.
Özellikle CPU-bound işlerde Go açık ara önde. Ben bi keresinde veri işleme scriptini Python'dan Go'ya çevirdim, abartmıyorum 40 kat hız artışı gördüm. Gözlerime inanamadım.

Eşzamanlılık
  • Go: Goroutine'ler ve channel'lar ile doğal bir eşzamanlılık var.
  • Python: GIL belası yüzünden gerçek paralellik çok zor.
Python'da threading kullanmaya kalktığınızda GIL kafanıza binerken, Go'da sadece go yazıyosunuz bitiyor.

Kullanım Alanları

Python nerde daha iyi:
  • Veri bilimi ve makine öğrenmesi AI
  • Hızlı prototip çıkarma
  • Script yazımı
  • Geniş kütüphane gerektiren projeler
Go nerde daha iyi:
  • Web servisleri ve API'ler
  • Mikroservisler
  • Sistem programlama
  • CLI araçları
  • Yüksek performans gerektiren uygulamalar

Benim Tavsiyem

İkisini de öğrenin abi, ikisinin yeri ayrı. Ben genelde şöyle yapıyorum:
  • Hızlı bi script mi lazım? → Python
  • Production'a çıkacak sağlam bi API mi? → Go
  • Veri analizi mi? → Python
  • Performans kritik mi? → Go

Go ile Web API Geliştirme

Go, web API geliştirmek için biçilmiş kaftan. Standart kütüphanesiyle bile ciddi işler yaparsınız ama ben Fiber gibi framework'leri kullanıyorum, işi bayağı kolaylaştırıyor.
Basit Bir API Örneği (Fiber ile)
Kod:
package main
import (
    "github.com/gofiber/fiber/v2"
)
func main() {
    app := fiber.New()
    app.Get("/", func(c *fiber.Ctx) error {
        return c.SendString("Merhaba Dünya!")
    })
    app.Get("/kullanici/:id", func(c *fiber.Ctx) error {
        id := c.Params("id")
        return c.JSON(fiber.Map{
            "id": id,
            "isim": "Kaan",
        })
    })
    app.Listen(":3000")
}
Bu kadar basit. Express.js kullananlara tanıdık gelmiştir kesin ama performansı kıyaslanamaz bile.

Neden Go Web API için İdeal?

  • Hız. Fiber saniyede yüz binlerce isteği rahatlıkla karşılar.
  • Düşük Bellek. Her istek için goroutine açıldığı için çok az RAM yer.
  • Tek Binary. Tüm uygulama tek bir çalıştırılabilir dosya (.exe gibi) olur, Docker image'ları küçücük kalır.
  • Kolay Dağıtım. Bağımlılık derdi yok (node_modules cehennemi yok), binary'yi al at sunucuya çalışsın.

Mikroservis Mimarisi ve Go

Mikroservisler konusunda Go artık standart oldu. Neden mi?
Go'nun Mikroservis Avantajları
  • Hafif Binary'ler: Her servis küçük bi dosya olarak derlenir (genelde 10-20MB falan).
  • Hızlı Başlatma: Milisaniyeler içinde servis ayağa kalkar.
  • Düşük Kaynak Tüketimi: Az RAM, az CPU harcar.
  • Kolay Container'laştırma: Docker image'ları minimal boyutta olur.

Basit Bir Mikroservis Yapısı

Kod:
// Kullanıcı servisi
package main
import (
    "encoding/json"
    "net/http"
)
type Kullanici struct {
    ID int `json:"id"`
    Isim string `json:"isim"`
    Email string `json:"email"`
}
func kullanicilariGetir(w http.ResponseWriter, r *http.Request) {
    kullanicilar := []Kullanici{
        {ID: 1, Isim: "Ali", Email: "[email protected]"},
        {ID: 2, Isim: "Ayşe", Email: "[email protected]"},
    }
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(kullanicilar)
}
func main() {
    http.HandleFunc("/kullanicilar", kullanicilariGetir)
    http.ListenAndServe(":8080", nil)
}
Gördüğünüz gibi harici kütüphane bile kullanmadan çalışan bi API yazdık.

Servisler Arası İletişim

Mikroservislerin birbiriyle konuşması lazım tabi. Go'da bunun için gRPC çok popüler:
Kod:
// gRPC ile yüksek performanslı iletişim
// Proto dosyasından otomatik kod üretiliyor
client := pb.NewKullaniciServiceClient(conn)
kullanici, err := client.KullaniciGetir(ctx, &pb.KullaniciIstegi{Id: 1})
gRPC, REST'e göre çok daha hızlı çünkü binary protokol kullanıyor.

İdiomatik Go: Kod Yazma Sanatı

Go'da sadece "çalışan" kod yazmak yetmez arkadaşlar, "idiomatik" kod yazmanız lazım. Yani dilin felsefesine, raconuna uygun, okunabilir kod demek bu.

Temel Prensipler

1. Basitlik Her Şeyden Önce
Kod:
// KÖTÜ - Gereksiz karmaşık, kafa karıştırıcı
func topla(sayilar []int) int {
    sonuc := 0
    for i := 0; i < len(sayilar); i++ {
        sonuc = sonuc + sayilar[i]
    }
    return sonuc
}

// İYİ - Basit ve anlaşılır
func topla(sayilar []int) int {
    toplam := 0
    for _, sayi := range sayilar {
        toplam += sayi
    }
    return toplam
}
2. Hataları Hemen Ele Alın
Kod:
// KÖTÜ
sonuc, err := birSeyYap()
if err == nil {
    // başarılı durumu işle
    // ...uzun kod...
} else {
    return err
}

// İYİ - Early return candır (Hatayı başta yakala dön)
sonuc, err := birSeyYap()
if err != nil {
    return err
}
// başarılı durumu işle
// ...uzun kod...
3. İsimlendirme Kuralları
Kod:
// Kısa, anlamlı değişken isimleri
for i, v := range values { } // döngülerde kısa isimler OK

// Fonksiyon isimleri ne yaptığını anlatsın
func KullaniciOlustur() { } // Export edilecekse (dışarı açılacaksa) büyük harf
func kullaniciDogrula() { } // İç kullanım içinse küçük harf

// Interface isimleri genelde -er ile biter
type Reader interface { }
type Writer interface { }
type Closer interface { }
4. Küçük Interface'ler
Kod:
// KÖTÜ - Çok büyük interface, her şeyi doldurmuş
type Veritabani interface {
    Ekle(veri interface{}) error
    Sil(id int) error
    Guncelle(id int, veri interface{}) error
    Getir(id int) (interface{}, error)
    Listele() ([]interface{}, error)
    // ...daha onlarca metod
}

// İYİ - Küçük, odaklı interface'ler
type Okuyucu interface {
    Oku(p []byte) (n int, err error)
}
type Yazici interface {
    Yaz(p []byte) (n int, err error)
}
Kod Formatlama
Go'da gofmt diye bi nimet var ve bu tartışmasız kullanılıyor. "Tab mı space mi" kavgası yok çünkü herkes aynı formatı kullanıyor:
Kod:
go fmt ./... # Tüm projeyi formatlar, çiçek gibi yapar
Bu kadar basit, herkesin kodu aynı görünüyo. Code review'larda "burada boşluk eksik" muhabbeti dönmüyor artık.


Pratik Bilgiler ve İpuçları

Go Kurulumu
  1. golang.org adresinden indirin.
  2. Kurun.
  3. Terminali açın ve go version yazın.
  4. Tebrikler, hazırsınız!
İlk Programınız
Kod:
package main
import "fmt"
func main() {
    fmt.Println("Merhaba, Go dünyasına hoş geldin!")
}
Çalıştırmak için: go run main.go
Önemli Komutlar
Kod:
go run main.go   # Derle ve çalıştır
go build         # Derle (binary/exe oluştur)
go test          # Testleri çalıştır
go mod init proje # Yeni modül başlat
go get paket/adi  # Paket indir
go fmt ./...      # Kodu formatla
go vet ./...      # Olası hataları bul

VS Code Kurulumu

  1. VS Code'u açın.
  2. Extensions'a (Eklentiler) gidin.
  3. "Go" aratın ve "Go Team at Google"ın eklentisini kurun.
  4. İlk .go dosyasını açtığınızda gerekli araçları kurmanızı isteyecek, hepsine "Yes" deyin geçin.

Go ile Neler Yapabilirsiniz?

1. Web Servisleri ve API'ler
Docker, Kubernetes, hatta Go'nun kendisi bile Go ile yazılmış. Web API geliştirmede Go artık standart haline geldi.

2. CLI Araçları
Cobra kütüphanesiyle çok profesyonel CLI araçları yapabilirsiniz. Kubernetes'in kubectli, Hugo, GitHub CLI falan hep Go ile yazıldı.

3. Sistem Programlama
Container runtime'ları (Docker, containerd), orchestration araçları (Kubernetes), monitoring sistemleri (Prometheus, Grafana) hep Go imzalı.

4. Veritabanı Araçları
CockroachDB, InfluxDB, TiDB gibi sağlam veritabanları Go ile yazılmış.

5. Blockchain
Ethereum'un ana implementasyonu (go-ethereum) Go ile yazılmış.


Öğrenme Kaynakları

Türkçe Kaynaklar
  • Go Programlama Dili - Türkçe Kitap- ksckaan1 arkadaşımızın hazırladığı harika kapsamlı bi kaynak.
    • GitHub'da 191 yıldız almış, topluluk tarafından da destekleniyo.
    • PDF ve EPUB formatlarında da var.
İngilizce Kaynaklar
  • A Tour of Go - Resmi interaktif tur, kesin bakın.
  • Go by Example - Örneklerle öğrenmek isteyenlere birebir.
  • Effective Go - İdiomatik Go yazmak için şart.

Sonuç

Go öğrenmeli misiniz? Bence kesinlikle evet, eğer şunları istiyosanız:
  • Web servisleri ve API'ler geliştirmek.
  • Mikroservis mimarisi kullanmak.
  • Performans sizin için önemliyse.
  • DevOps/SRE alanında çalışıyosanız.
  • CLI araçları geliştirmek istiyosanız.
  • Cloud-native teknolojilerle ilgileniyosanız.
Go, modern yazılım geliştirmenin birçok problemine pratik çözümler sunan, öğrenmesi kolay ama ustalaşması zaman alan bi dil. Şahsen ben Go'ya geçtikten sonra production'daki birçok performans sorunumdan kurtuldum ve kod yazmaktan daha çok keyif almaya başladım. Umarım yararlı olmuştur, iyi forumlar.
 
Son düzenleyen: Moderatör:
Electron bu aralar çok eleştiri yiyor hocam zaten. Tauri'ye, Wails'e falan geçişler artacaktır.
Aynı fikirdeyim. Milletin bilgisayarı resmen "Chrome sekmesi" çöplüğüne döndü Electron yüzünden.

Sen basit bir "To-Do List" uygulaması yapıcam diyorsun Electron'la, o gidiyor uygulamanın içine koskoca Chromium tarayıcısı gömüyor. Kullanıcı senin uygulamayı açtığında aslında arkada gizli bir Chrome penceresi açmış oluyor. Eeee kullanıcıda zaten Discord açık, Spotify açık, VS Code açık..... PC arka planda 50 tane Chrome sekmesi çalıştırmaya çalışıyor, RAM'ler ağlıyor sonra :)

Rust bilen veya öğrenmeyi göze alanlar Tauri tarafına, Go'nun basitliğini sevenler Wails tarafına akıor genelde. Özellikle Tauri v2 ile mobil desteği de geldi, baya gaza bastılar.

Bence de önümüzdeki 2-3 sene içinde yeni başlayan projelerde Electron'u anca "mecburiyetten" (çok spesifik Node.js paketlerine ihtiyaç varsa) görürüz, yoksa devir hafif sıklet framework devri....
 
Bu ne anlama geliyor? Dili öğrenmesi çocuk oyuncağı. Ben daha önce az buçuk Python ve JavaScript ile uğraşıyodum, Go'yu temel seviyede kavramam 2-3 haftamı aldı almadı. Syntax'ı (sözdizimi) o kadar temiz ki, başkasının yazdığı kodu okumak bile keyifli, bulmaca çözer gibi uğraşmıyosunuz.
Cok uzun bi ek yazdim, okumak istemeyenler icin TLDR; Go geleneksel concurrency'den farkli bi yapiya sahip ve eger geleneksel concurrency'ye alisik biriyseniz saglam bi kafa yapisi degisikligi gerekecek. Concurrency'nin kendisi zaten zor bi sey ama go spesifik olarak konusuyorsak, geleneksel sistemlere alisik biri icin basta bazi kisimlar sasirtici gelebilir. Hic concurrency bilmeyen kisiler icin o kadar zor olmayacagini dusunuyorum. Yine de tabii ki belli basli zorluklari olacak. Ama fikrimce geleneksel concurrency'den bi miktar daha kolay oldugu.

Bu dilin zor kismi concurrency modeli. Go'nun concurrency modeli geleneksel parellelism yada geleneksel asynchronous programming'den siddetli olcude farkli. Concurrency genel olarak zor ama go'da biraz daha farkli bi anlayis gerektiriyor geleneksel concurrency'ye kiyasla.

Go'nun concurrency modeli geleneksel multithreading'e daha yakin. Ancak iletisim sistemi birincil olarak channellar uzerinden gerceklestiriliyor ve context aracaligiyla bi routine'in (task'in) calisma sureci kontrol edilebiliyor.

Normalde, geleneksel C++'da paylasilmis bir bellek uzerinden iletisim saglanir. Bu paylasilmis bellek bi queue olabilir, bi list olabilir yada buyuk bir obje icin referans olabilir. Ancak go icin bellegi iletisim uzerinden paylasiriz. Dolayisiyla eger bir pointer paylasmiyorsak channellar uzerinden, neredeyse tum yazma ve okuma islemleri thread-safe bi sekilde gerceklesir. (Burda pointer paylasimlarina dikkat etmek gerek, cunku pointerlar, dogalari geregi ayni bellek adresine isaret edecekleri icin tek objenin iki farkli routine tarafindan kullanilmasi anlamina gelir. Bu da race condition veya bellek kaynakli problemlerle sonuclanabilir. Eger paylasilan objede bi pointer tasiyorsa, yine ayni kurallar gecerli. Slice ve Map'de iclerinde pointer tasiyan birer descriptor/header'dir, onlarin da bu sistemde paylasilmalari aslinda tasidiklari pointerlarin paylasilmasi anlamina gelir. Aman dikkat.)

Geleneksel multithreading sistemlerinde, ornegin C++'ta elinizde bi thread objesi, C'de bi thread id'si, Java'da yine bir thread objesi elinizde olur. Daha sonrasinda bu objeyi kullanarak bu threadin sagligini takip edebilir, disaridan thread'i durdurabilirsiniz (interrupt). Ayni durum golang icin gecerli degil. Go buna izin vermiyor. Durdurulabilirlik icin go saglanmis olan context objesiyle cancel (iptal) gerceklestirilmesini istiyor. Ve goroutine'lerde bu objeye itaat edilecek sekilde yazilmis olmali. Belirli guvenli noktalarda iptal edilebilir olmalilar.

Ayrica goruntime goroutineleri ayni bir isletim sistemi gibi zamanliyor. Isletim sistemleri dogal olarak preemptive zamanlama becerisine ihtiyac duyarlar. Preemptive zamanlamanin arkasindaki temel mantik bir isin uzun bir sure bir islemci kaynagini somurup, diger islerinde ayni kaynagi kullanabilmesine olanak saglamaktir.

Zamanlayicinin kendisinin de ayrica bu kaynaga ihtiyaci oldugu icin, zamanlayici elinden geldigince oncelik siralamasina gore butun islemlere zaman ayirmaya calisir ve cok uzun calisani gecici askiya alip bi sureligine de olsa baska bi kac ise sure verip, tekrar askiya aldigini geri yukler boylece her sey bi miktar ilerlemis olur. Go 1.14'ten beri bu mantik yardimiyla, cpu-bound logic icin bile neredeyse sifir block mantigiyla ilerleme saglayabiliyor.

Ondan oncesinde cooperative scheduling kullaniyorlardi, bu da cok uzun calisan cpu bound logiclerin bi go processorunu komple kiliteleyebilecegi anlamina geliyordu, simdi durum boyle degil. Tabii ki milyonlarca uzun calisan isin varligi, tum islerin hep beraber ciddi anlamda yavaslamasina sebep olabilir hala, cunku bu seferde resource starvation yasanacak genel anlamda.