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 alt testlerle (table-driven tests bunların üzerine kurulur), 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
Bir çekirdek Go'da 14.330, PHP-FPM'de 5.152 OAuth2 isteği taşıyor
Her istekte RS256 bearer token doğrulayıp PostgreSQL'e bir satır yazan ya da okuyan aynı API, bir, iki ve dört çekirdekte Go, PHP-FPM ve FrankenPHP worker ile saniyede kaç karma istek taşıyor?
Bulgu
Dört çekirdekte Go 57.321, FrankenPHP 25.659, PHP-FPM 20.606 karma istek taşıdı; çekirdek başına 14.330, 6.415 ve 5.152. Kapasite planına giren sayı bu değil, istek başına uygulama CPU'su: Go 66,8, FrankenPHP 110,7, PHP-FPM 187,7 mikrosaniye. FrankenPHP doyduğunda dört çekirdeğin ancak 2,84'ünü kullanabiliyor — Go 3,83, PHP-FPM 3,87. Darboğaz veritabanı değil: aynı dört çekirdekte PostgreSQL tek başına saniyede 68.212 satır yazıyor, yani en hızlı adayın karma tavanının üstünde.
17 gün önce ölçüldü
Bu konudaki deneyler
Uygulama ile sağlayıcı arasında duran, tek OpenAI uyumlu API sunan ve isteğe RAG bağlamını kendisi ekleyen self-hosted Go gateway.
Şu an ne yapıyor
Uygulamanın tek bir OpenAI uyumlu uca konuşmasını, isteğin hangi modele gideceğini ve — bir doküman havuzu bağlıysa — hangi dokümanlardan bağlam alacağını projenin ayarının belirlemesini sağlıyor. Sağlayıcı anahtarını uygulamalara dağıtmak istemeyen ve harcamayı proje başına sınırlamak isteyen herkes kendi sunucusunda çalıştırabilir.
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.
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.