Go'nun standart kütüphanesiyle ne kadar uzağa gidilir
Go'nun zengin standart kütüphanesinin gerçekte ne kadar yol kat ettirdiğini, harici bağımlılık ekleme kararını somut örneklerle tartıyorum.
Go öğrenmeye başlayanların erken fark ettiği şeylerden biri: dilin standart kütüphanesi (standard library) alışılmadık derecede zengin. HTTP sunucusu, JSON işleme, şifreleme, dosya sistemi, şablon motoru, test altyapısı — bunların hepsi üçüncü parti paket olmadan kullanılabiliyor.
PHP dünyasından gelince bu bir kültür şoku. PHP’de üçüncü parti paket kurmadan neredeyse hiçbir şeyi “modern” biçimde yapamıyorsunuz. Composer olmadan çalışmak teorik olarak mümkün ama pratik olarak tercih edilmiyor. Go’da ise standart kütüphane gerçekten kendi başına bir üretim tercihi.
Standart kütüphane neyi kapsıyor
Go’da import ifadesinin ardında github.com görmeden yapabileceklerinize kısaca bakalım:
HTTP servisi: net/http paketi hem client hem server tarafı sağlıyor. Basit bir servis için router kütüphanesi gerekmez:
package main
import (
"encoding/json"
"net/http"
)
type Response struct {
Message string `json:"message"`
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(Response{Message: "ok"})
}
func main() {
http.HandleFunc("/health", healthHandler)
http.ListenAndServe(":8080", nil)
}
Bu kod, bir üretim servisinin sağlık kontrol ucu için yeterli. Ek bağımlılık yok.
JSON işleme: encoding/json ile hem serialization hem deserialization mümkün. Büyük veri setlerinde ya da özel dönüşüm senaryolarında başka paketlere bakıyorum, ama standart kullanım durumları için encoding/json yeterli.
Veritabanı erişimi: database/sql arayüzünü driver’lar gerçekleştiriyor. Sürücü paketini dışarıdan alıyorsunuz, ama ORM zorunluluğu yok. Saf SQL’i standart kütüphane üzerinden çalıştırmak doğal.
Şablon motoru: html/template paketi XSS (Cross-Site Scripting) korumasını yerleşik olarak sunuyor. Sunucu taraflı HTML üretimi için başka bir şeye ihtiyaç yok.
Test altyapısı: testing paketi table-driven tests, benchmark ve fuzz test desteğiyle geliyor. Go’nun test kültürü büyük ölçüde bu paketin üzerine kurulu.
Nerede sınıra geliyorsunuz
Standart kütüphane her şeyi karşılamıyor ve bu bilinçli bir tasarım kararı. En çok sınıra geldiğim yerler:
Routing. net/http’nin varsayılan router’ı path parametrelerini (:id gibi) desteklemiyor. Go 1.22 ile bu kısıtlama kısmen giderildi — pattern sözdizimi eklendi:
// Go 1.22+
http.HandleFunc("GET /users/{id}", getUserHandler)
Ama karmaşık yönlendirme senaryolarında, özellikle middleware zinciri ve grup yapılandırması gerektiğinde chi ya da gorilla/mux gibi paketlere başvuruyorum.
ORM. database/sql ile saf SQL yazmak bir süre sonra tekrarlı oluyor. sqlx gibi hafif bir kütüphane standart arayüzü korurken struct taramasını kolaylaştırıyor. Ağır bir ORM almadan yapabildiğim durumlar çok daha fazla.
Doğrulama. Standart kütüphanede doğrulama kütüphanesi yok. go-playground/validator bu ihtiyacın fiili standardı haline geldi.
Loglama. log/slog paketi Go 1.21’de geldi ve structured loglama için artık standart kütüphane yeterli. Önceki sürümlerde zap ya da zerolog zorunluydu.
Az bağımlılığın değeri
Go topluluğunun “vendor her şeyi kontrol edin” yaklaşımı ve minimal bağımlılık kültürü birbiriyle bağlantılı. Daha az bağımlılık şu anlama geliyor: derleme süresi daha kısa, güvenlik açığı yüzeyi daha küçük, bağımlılık güncelleme yükü daha az.
Bir paketi eklemeden önce şu soruyu soruyorum: bu paketi standart kütüphaneyle ya da birkaç yardımcı fonksiyonla karşılayabilir miyim? Çoğu zaman cevap evet. Yanıt hayır olduğunda paket ekliyorum, ama bu bir karar — varsayılan değil.
PHP’de Composer olmadan yazmayı düşünmüyorum; ekosistem o şekilde kurulu. Go’da ise standart kütüphane bir başlangıç noktası değil, uzun süre yeterli olan gerçek bir seçenek. Bu fark, bağımlılıklara bakış açımı da biçimlendirdi.
Bu yazının arkasındaki araştırmalar
PHP ile Go'yu aynı OAuth2 API'de ölçtüm: 10.000 yazmada fark yok, 50.000 okumada var
Her istekte OAuth2 token'ı doğrulayıp PostgreSQL'e yazan ya da okuyan aynı API, dört çekirdekte PHP-FPM, FrankenPHP worker ve Go ile saniyede 10.000 yazmayı ve 50.000 okumayı kaç CPU'yla karşılıyor?
Bulgu
Saniyede 10.000 yazmada üç aday da hedefi beş tekrarın beşinde tutturdu, p99 üçünde de 2,5 ms'yi aşmadı: bu yükte dil bir kapasite kalemi değil. Saniyede 50.000 okumayı dört çekirdekte yalnız Go tutturdu (p99 6,45 ms); PHP-FPM 23.528'de, FrankenPHP 22.859'da kaldı. İstek başına CPU okumada Go'da 64, FrankenPHP'de 117, PHP-FPM'de 168 mikrosaniye. 50.000 okuma için instance hesabı Go'ya 3,4, iki PHP adayına 8,2–8,8 çekirdek yazdırıyor. FrankenPHP'nin CPU tasarrufu kapasiteye dönmüyor: doygunken dört çekirdeğin birini boşta bırakıyor.
bugün ölçüldü
Bu konudaki deneyler
Dile özgü serileştirme yerine dondurulmuş bir JSON zarfı; polyglot kuyruk standardı BabelQueue'ya dönüştü.
Şu an ne yapıyor
Dondurulmuş JSON zarfı dört dilde — PHP, Python, Go, Node.js — aynı baytları okutuyor; sidecar ya da broker eklentisi gerekmiyor. Polyglot kuyruk kuran ekipler spesifikasyonu ve SDK'ları bugün kullanabilir.
Diff'i makineden çıkarmadan bir modele denetleten, sağlayıcıdan bağımsız Go CLI; CommitBrief ürününe dönüştü.
Şu an ne yapıyor
Diff hiç makineden çıkmadan yerel kod incelemesi yapıyor; `Provider` arayüzü sayesinde Anthropic, OpenAI, Gemini ve Ollama aynı sözleşmeyle takılıyor. İmzalı binary'ler yayında — diff'ini bir bulut sağlayıcısına vermek istemeyen herkes kurabilir.
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.