1 puan yazan GN⁺ 2 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • Go, backend geliştirmenin aşırı karmaşıklığını azaltan bir seçenek olup; hızlı derleme, tek binary dağıtımı ve güvenilir bağımlılık yönetimi temel avantajlarıdır
  • Go; decorator, metaclass, macro, trait, monad gibi karmaşık soyutlamalar yerine struct, fonksiyon, interface, goroutine ve channel merkezli sade bir dil tasarımını seçer
  • embed, html/template, net/http, database/sql, encoding/json, go test, pprof gibi standart kütüphane ve temel araçlarla web uygulaması, veritabanı, test, benchmark ve profiling işlemleri yapılabilir
  • goroutine, yaklaşık 2KB maliyete sahip stackful bir yürütme birimidir; channel, sync.Mutex, race detector ve context.Context sayesinde eşzamanlılık ve iptal yayılımı basitçe ele alınabilir
  • go mod init, go build, scp, systemctl restart akışı; node_modules, karmaşık Docker·Kubernetes kurulumları ve aşırı mikroservisler yerine tek bir Go binary’si ve Postgres merkezli sade dağıtımı önerir

Neden Go’yu seçmelisiniz?

  • Go, backend geliştirmenin aşırı karmaşıklığını azaltan bir seçenek olup; hızlı derleme, tek binary dağıtımı ve güvenilir bağımlılık yönetimi temel avantajlarıdır
  • Frontend tarafında HTML nasıl aşırı karmaşıklığa karşı bir alternatif olarak kaldıysa, Go da 10 yıldan uzun süredir backend sadeleştirmesi için bir seçenek olarak varlığını sürdürüyor
  • Basit bir form sunmak ya da saniyede yaklaşık 40 istek düzeyindeki bir CRUD uygulaması için bir sürü Node paketi, TypeScript build araçları, Kubernetes, Rails platform ekibi ve hatta Rust ile yeniden yazım kullanmak fazladır
  • Go’nun odağı “zekice soyutlamalar”dan çok okunması kolay kod, dağıtılabilir çıktı ve düşük operasyonel yüktür

Kasıtlı olarak sıkıcı tasarlanmış bir dil

  • Go’nun sıkıcı hissettirmesinin nedeni kasıtlı tasarımıdır; decorator, metaclass, macro, trait, monad gibi karmaşık soyutlamalar sunmaz
  • Temel yapı taşları kabaca struct, fonksiyon, interface, goroutine ve channel ile sınırlıdır
  • Amaç, dil özelliklerini kısa sürede okuyup aynı gün üretken biçimde kod yazabilecek kadar sade kalmaktır
  • Sıkıcılık, ekip kod tabanında bir avantaja dönüşür
    • Geçen ay işe giren bir junior, 2 yıl önce principal tarafından yazılmış kodu okuyabilir
    • gofmt tek bir formatı zorunlu kıldığı için kod stili tartışmaları azalır
    • Dilin kendisi, aşırı karmaşık soyutlamaların kod tabanına sokulmasını zorlaştırır

Standart kütüphane framework gibi davranır

  • Go’da ayrı bir web framework’ü olmadan da yalnızca standart kütüphane ile web uygulaması geliştirilebilir
  • embed, html/template, net/http kullanarak HTML template’lerini binary’ye gömüp HTTP handler’larıyla render eden bir uygulama kurulabilir
package main

import (
    "embed"
    "html/template"
    "net/http"
)

//go:embed templates/*.html
var files embed.FS

var tmpl = template.Must(template.ParseFS(files, "templates/*.html"))

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        tmpl.ExecuteTemplate(w, "index.html", map[string]string{
            "Name": "asshole",
        })
    })

    http.ListenAndServe(":8080", nil)
}
  • Bu örnek çalışan bir web uygulamasıdır ve HTML template’leri derlenip binary’ye dahil edilir
  • webpack, Vite, development server ya da devasa node_modules olmadan go build sonrası tek bir dosya dağıtılabilir
  • Standart kütüphane ve temel araçlarla başlıca backend işleri yapılabilir
    • Veritabanı: database/sql
    • JSON: encoding/json
    • Diğer servis çağrıları: net/http client
    • Eşzamanlı çalışma: go anahtar sözcüğü
    • Test: go test
    • Benchmark: go test -bench
    • Profiling: pprof

Derinlikli bir standart kütüphane yapısı

  • io.Reader ve io.Writer

    • io.Reader ve io.Writer, her biri yalnızca tek metoda sahip interface’lerdir ama Go ekosisteminin genelinde önemli bir temel oluştururlar
    • HTTP response body’sini bir gzip writer’a bağlayıp oradan disk dosyasına aktarma gibi bileşimler az kodla kurulabilir
    • Temel paketler bu iki interface’i paylaştığı için aynı kalıplar birçok yerde tekrar tekrar kullanılabilir
  • context.Context

    • context.Context, iptal yayılımı için standart yöntemdir
    • Kullanıcı tarayıcı sekmesini kapattığında request context iptal olur ve ardından veritabanı sorgusu ile alt HTTP çağrıları da iptal edilebilir
    • goroutine sızıntılarından veya connection pool tüketen zombi sorgulardan kaçınmak için context’i ilk argüman olarak geçirip buna saygı göstermek gerekir
  • Encoding paketleri

    • encoding/json, encoding/xml, encoding/csv, encoding/binary paketlerinin tamamı standart kütüphanede yer alır
    • struct tag kalıbı ve pointer ile decode etme deneyimi benzer olduğu için birini öğrenince diğerlerini kullanmak da kolaylaşır

Acıyı azaltan eşzamanlılık modeli

  • goroutine, doğrudan bir OS thread değildir; runtime’ın OS thread’leri üzerinde çokladığı stackful bir yürütme birimidir
  • goroutine başlatma maliyeti yaklaşık 2KB’dır ve bir laptop’ta bile 100 bin tane oluşturulabilir
  • channel, goroutine’ler arasında tür güvenli bir boru gibi çalışır; bir taraf gönderip diğer taraf aldığında senkronizasyonu runtime halleder
  • Paylaşılan durum gerektiğinde sync.Mutex kullanılabilir ve race detector veri yarışlarını bulur
  • Paralel bir HTTP fetcher da ayrı kütüphane, framework veya async/await ritüelleri olmadan yazılabilir
results := make(chan string, len(urls))
for _, url := range urls {
    go func(u string) {
        resp, _ := http.Get(u)
        results <- resp.Status
    }(url)
}
for range urls {
    fmt.Println(<-results)
}

Gerçek bir CRUD route örneği

  • Postgres’ten gönderileri okuyup HTML render eden CRUD tarzı bir route da tek ekrana sığacak kadar sade kurulabilir
//go:embed templates/*.html
var tmplFS embed.FS

var tmpl = template.Must(template.ParseFS(tmplFS, "templates/*.html"))

type Post struct {
    ID    int
    Title string
    Body  string
}

func postsHandler(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        rows, err := db.QueryContext(r.Context(),
            "SELECT id, title, body FROM posts ORDER BY id DESC LIMIT 50")
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        defer rows.Close()

        var posts []Post
        for rows.Next() {
            var p Post
            if err := rows.Scan(&p.ID, &p.Title, &p.Body); err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
            posts = append(posts, p)
        }

        tmpl.ExecuteTemplate(w, "posts.html", posts)
    }
}
  • Bu örnek veritabanını, template’i ve HTTP handler’ı tek yerde gösterir
  • r.Context() SQL sorgusuna aktarıldığı için bağlantı kapanırsa sorgu da iptal edilebilir
  • ORM, DI container, service layer ya da soyut taban sınıflarla dolu controllers/ dizini olmadan yukarıdan aşağı okuyarak davranış anlaşılabilir

Hafta sonunu mahvetmeyen bağımlılık yönetimi

  • go mod init ile modül başlatıldığında bağımlılıklar go.mod ve go.sum içine kaydedilir
  • go.sum, gerçekten indirilen öğelerin kriptografik kaydıdır; böylece beklenenden farklı bir bağımlılığın gelmesi tespit edilebilir
  • node_modules dizini, geliştirme ortamı ile CI arasında lockfile drift, peer dependencies, optional dependencies, devDependencies, peerDependenciesMeta gibi karmaşıklıklar yoktur
  • Offline build gerekirse go mod vendor, bağımlılıkları vendor/ dizinine indirir ve toolchain bunu otomatik kullanır
  • Tüm proje ve bağımlılıklar tek bir tarball içine konabilir; bu da operasyon ve güvenlik incelemesi açısından avantaj sağlar

Derleyiciyle birlikte gelen araçlar

  • Go’nun temel araçları, third-party plugin’ler veya ayrı yapılandırma dosyaları olmadan gelir
  • gofmt, kod formatını standartlaştırır ve format tartışmalarını, ayrıca boşluk değişimlerinden doğan diff artışını azaltır
  • go vet, bariz hataları yakalamak için kullanılır
  • go test, testleri çalıştırır
  • go test -race, testleri race detector ile birlikte çalıştırıp veri yarışlarını bulur
  • go test -bench, benchmark’ları çalıştırır
  • go test -cover, test coverage durumunu gösterir
  • go tool pprof, çalışan production servisinin HTTP endpoint’i üzerinden CPU ve bellek kullanımının flame graph’ını almayı sağlar

Dağıtım bir kopyalama komutuyla biter

  • Go dağıtımının temel akışı binary’yi derlemek, sunucuya kopyalamak ve çalıştırmaktır
GOOS=linux GOARCH=amd64 go build -o myapp ./cmd/myapp
scp myapp user@server:/usr/local/bin/
ssh user@server 'systemctl restart myapp'
  • Bu akış; Dockerfile, multi-stage build, base image CVE uyarıları, Kubernetes manifest’leri, Helm chart, ArgoCD, service mesh ve sidecar olmadan dağıtıma izin verir
  • Yaklaşık 12MB boyutunda statik linklenmiş bir binary ve 20 satırlık bir systemd unit dosyası ile production dağıtımı yapılabilir
  • Docker gerçekten gerekiyorsa Go binary’sini FROM scratch imajına koymak yeterlidir

Framework’lerle karşılaştırma

  • Rails, Django, Express, Next.js gibi framework’lerin her birinin kendi dağıtım süreci, ORM’i, admin paneli, middleware’i, npm uyarıları ve değişen routing konvansiyonları gibi yükleri vardır
  • Go binary’si derlenir ve çalıştırılır; 5 yıl sonra bile çalışabilecek istikrarı bir avantaj olarak sunar
  • Framework’lerin daha hızlı terk edilmesi ya da bakımcılarının tükenmişlik yaşaması ihtimaline kıyasla, Go’nun sade çalışma modeli öne çıkar

Mikroservis yerine tek bir Go binary’si

  • Mikroservisler varsayılan tercih olmamalıdır; önce bir monolith yazmak daha iyidir
  • Önerilen yapı; tek bir Go binary’si, tek bir Postgres ve yalnızca gerçekten gerektiğinde tek bir Redis’tir
  • HTML ile JSON API aynı porttan sunulabilir ve her şey tek bir VPS üzerinde çalışabilir
  • Go, düşük goroutine maliyeti ve güçlü eşzamanlılık yapısı sayesinde saniyede 10 bin isteğe kadar zorlanmadan ölçeklenebilir
  • Gerçekten ayırma ihtiyacı doğarsa, Go monolith içindeki paketler ayrı repository’lere taşınarak bölünebilir
  • Interface’ler zaten mevcut olduğu için dil, ayrıştırmayı doğal olarak düşünen bir yapı kurmaya yardımcı olur

Generics ve hata işleme

  • if err != nil bir bug değil, bir özelliktir
  • Her hata noktasında ne yapılacağına doğrudan karar vermeyi sağlar ve hataları gizlemez
  • try/catch iç içeliği hataları ortadan kaldırmaz; sadece onları production arızası yaşanana kadar saklayabilir
  • Generics, Go 1.18 ile geldi ve gerektiğinde kullanılabilir

Sonuç

  • Framework’ler, mikroservisler, Rust ile yeniden yazım ya da yeni bir JavaScript meta-framework her zaman gerekli değildir
  • go mod init çalıştırıp main.go yazmak, template’leri embed etmek, sonra derleyip dağıtmak gibi sade bir akış önerilir
  • Sıkıcı seçim doğru seçimdir ve Go da o seçimdir

1 yorum

 
GN⁺ 2 시간 전
Lobste.rs görüşleri
  • Elçiyi suçlamak istemem ama bu tür blog üslubu yorucu ve çocukça. İlk başta komik gelmiş olabilir ama tekrarlandıkça rahatsızlık katlanarak artıyor
    Yine de Go iyi. Yakın zamanda bir TypeScript projesinden bir Go projesine geçtim; ruh sağlığım ve iş motivasyonum hızla iyileşiyor
    if err != nil ifadesinin bir bug değil, özellik olduğunu kabul ediyorum ama yine de Go’nun en büyük kusuru olduğunu düşünüyorum. Toplam tipler (sum types) olsaydı, çalışma zamanı tip doğrulamalarına bel bağlamadan bunu çok daha ergonomik hale getirmek mümkün olurdu

    • Her konuda iki tarafa da oynayıp aslında hiçbir pozisyon almayan AI zırvaları yerine bunu tercih ederim
    • Okuması eğlenceliydi ama bu tür yazılardan çok görmedim. Yine de “dipshit” yerine “walnut” demesi daha komik olduğu için daha çok hoşuma gitti
      Böyle yazacaksan en azından hakaretlerin biraz zekice olsun
    • Katılıyorum. Bunu raporlamanın bir yolu var mı? Hiçbir raporlama kategorisine uymuyor
  • Diğer yorumlara bakınca popüler olmayan bir düşünce gibi görünüyor ve kaba gelmek istemem ama Go’dan gerçekten nefret ediyorum
    Go, eşzamanlılık için verimli bir runtime’ın üstüne şöyle böyle fena olmayan bir sözdizimi koyup Google’ın gücüyle ekosistemi ittiren bir dil. Onun dışında bana göre korkunç
    En büyük sorun, onlarca yıllık programlama dili tasarımı araştırmasını hatta pratikteki iyi yöntemleri bile bilerek yok saymak için tasarlanmış gibi görünmesi. On yıllar sonra generics geldi gerçi
    Her zaman dependent types kullanmak gerektiğini söylemiyorum ama bunun da bir ölçüsü var. Go’da modern bir dilde olması gereken veri modelleme, değişmez koşulları modelleme ve kodu yapılandırma özelliklerinin neredeyse hiçbiri yok. Rust’ın öğrenme eğrisi daha dik ama bu açılardan çok daha iyi; üstelik Rust kadar sofistike bir tip sistemi olmasa da gayet yeterli olunabilir. Derleme süresi dertse, basit ama işe yarayan özelliklerle hem hızlı hem de ifade gücü yüksek, sağlam bir tip sistemi yapılabilir
    Ayrıca if err != nil, kodu hata işleme gürültüsüyle kaplamanın olabilecek en kötü yolu bence. Go tarafının toplam tiplere neden bu kadar alerjisi olduğunu bilmiyorum. Bu konuda Java exception’ları bile daha iyi. Gerçekte olan şu: dilde hataları daha iyi ele alacak özellikler olmadığı için insanlar mümkün olan en kötü yamanın bir özellik olduğunu sanıyor
    Zaten orijinal yazı ukalalık yapmasaydı ben de böyle bir yorum yazmazdım. “Sadece X kullan” aptalca bir laf. Kullanım durumuna uyan, rahat ve üretken olduğun aracı kullanırsın. Bu Go ise Go kullanırsın, değilse başka bir şey seçersin

    • Go’nun tasarım alanındaki yeri, büyük kod tabanlarında ve büyük organizasyonlarda çalışan junior geliştiricilerin sadeliğini neredeyse her şeyin önüne koyan bir seçim gibi geliyor. Bu yüzden daha az deneyimli geliştiriciler, çok fazla bağlam biriktirmeden kodu okuyup yerel değişiklikler yapabiliyor
      Özellikle Google gibi, binlerce geliştiricinin olduğu ve insanların belirli bir ekipte ya da şirkette kısa süre kalabildiği organizasyonlarda bu işe yarıyor
      Bu bağlamda, özellikle daha toy geliştiriciler için gelişmiş tip sisteminin yokluğu bir noktaya kadar avantaj bile olabiliyor. Çünkü temel tipler ya da struct’lar gibi en basit kavramların ötesinde tipler üzerine neredeyse hiç düşünmek gerekmiyor. Veri modellemek için neredeyse hiç araç vermiyor ama öte yandan fazla düşünmeden çok sayıda kod yazabiliyorsun
      Dil seviyesinde doğruluk açısından pek iyi değil bence. Ama büyük organizasyonlarda insanlar monorepo analizi, CI/CD, canary testleri, gözlemlenebilirlik araçları gibi çevresel altyapılara daha fazla güveniyor. Bu altyapı, küçük organizasyonlara göre çok daha fazla yük taşıyor
      Ben de benzer biçimde düşük bilişsel yük yüzünden Go’yu bir ölçüde seviyorum. Belirli projelere sadece arada bir kod yazıyorum ve şu an her gün uzun soluklu projelere derinlemesine dahil olmuyorum. Bir aydır bakmadığım bir kod tabanına girip bir saatten kısa sürede iş yapabilmek büyük avantaj. Ama karmaşık bir projede tam zamanlı geliştirici olsaydım muhtemelen daha az severdim
    • Dart da onlarca yıllık araştırmayı yok sayıyor gibi görünmeyen bir Google dili ama Flutter dışında kimse kullanmıyor. Go idare eder
    • Bu yazı saldırgan ve ukala bir meme biçimini taklit ediyor. O yüzden insanları kışkırtacağı belli ve yazının ana fikrinin alev savaşı çıkarmaktan ziyade düzgün bir tartışmayı hak ettiğini düşündüğüm için bunu pek iyi bulmuyorum
      Go geliştiricileri temelleri doğru kurmaya odaklandı diye düşünüyorum. Çünkü bugüne kadarki dillerle programlama dili teorisi araştırma topluluğu temelleri ihmal etti. İnsanlar en kapsamlı tip sistemine saplanıp kalıyor ama tip sistemi ne kadar karmaşık ve ifade gücü yüksek olursa getirisi de o kadar azalıyor; ayrıca tip sistemine ne kadar emek verilirse verilsin korkunç paket yönetimi, ekibin yeni DSL’ler öğrenmesini gerektiren build araçları, tip bilgisine ya da üçüncü taraf paket dokümantasyon bağlantılarına otomatik link üretmeyen dokümantasyon sistemleri, zayıf standart kütüphane, ciddi performans sorunları, statik derleme stratejisinin yokluğu, acı veren build süreleri, dik öğrenme eğrisi, cezalandırıcı tip sistemi, okunması zor sözdizimi ve berbat editör entegrasyonu telafi edilemez
      Go’da hiç veri modelleme özelliği yok demek açıkça yanlış. Her dilde veri ve değişmez koşullar modellenebilir; Go da bu modeli zorlayacak epey tip sistemi sunuyor
      Rust harika ve yineleme hızının önemli olmadığı, bare metal’e dağıtım yapılan ya da doğruluk ve performans gereksinimlerinin çok güçlü olduğu durumlarda iyi bir seçim. Ama genel amaçlı uygulama geliştirme için, özellikle de ekip geliştirmesinde varsayılan tercih olarak iyi değil. if err != nil çok yazılıyor olabilir ama saniye başına tuş vuruş sayısı yüzünden darboğaza giren kimse yoktur sanırım
    • Rust dışında bu tür özelliklere sahip modern dil neredeyse yok. Gleam ya da Swift ile programlamak istemen başka ama o kadar nişse, bari Haskell kullanmış olursun
  • if err != nil ifadesinin bir bug değil özellik olduğu ve sorun çıkabilecek her noktayı görünür kıldığı iddiası yanlış
    Gerçekte zorunlu değil. Kendin kontrol etmezsen hatayı yok saymak daha kolay
    Hataları ele alma ya da yayma biçimi konusunda Rust hâlâ parlayan örnek

    • Evet. errcheck gibi bir şey yoksa hataları görmezden gelmek fazla kolay ve bu düpedüz saçmalık. En azından hatayı açıkça çöpe atmayı zorunlu kılmalı
      Neyse ki son birkaç yılda üzerinde çalıştığım tüm Go projeleri, Go’nun zayıf yerleşik statik kontrollerinin üstüne golangci-lint koyuyordu. Açıkçası her Go projesinde zorunlu olmalı
    • Bu konuda Swift daha iyi. İşlevsel olarak aynı model ama Swift tarafında farklı kütüphaneler arasında hata yayılımı daha kolay. Yine de bu daha iyi ya da daha kötü meselesinden çok artı-eksi ve tasarım tercihi farkı
  • Bu yazım modasından gerçekten nefret ediyorum ama yazının vermek istediği mesaja katılıyorum
    “Volkswagen büyüklüğünde node_modules yok” demesi doğru ama bu, proje yerelindeki node_modules yerine ~/go altındaki genel paket önbelleği demek sadece

    • Üstelik home dizinini kirletiyor. Başında nokta bile yok. Buna nasıl göz yumuluyor anlamıyorum
    • Başka dil ekosistemlerinin bağımlılık ağacının boyutuyla dalga geçmeden önce insanın wc -l go.sum çalıştırası geliyor
  • Sayfayı açar açmaz “Hey, dipshit.” gördüm ve hemen kapattım

  • Programlama dillerini öven yazıların çoğundaki aynı sorunu taşıyor. Mevcut dilin ne kadar harika olduğundan çok, daha önce kullandığı dilin ne kadar korkunç olduğuna odaklanıyor
    Yazar belli ki Ruby ve TypeScript, belki de Python yüzünden ciddi acı çekmiş ve Go bunu çözmüş. Ama ben Ruby ya da TypeScript kullanmadığım için yazı bana pek bir şey ifade etmedi
    Yıllardır bunun düzinelerce varyasyonunu okumuşum gibi hissediyorum. Python ve JavaScript’ten farklı olarak statik tipleri var diye Haskell kullan. Perl ve Erlang’dan farklı olarak tek binary olarak dağıtılabiliyor diye Rust kullan. Ruby ve Tcl’den farklı olarak düzgün eşzamanlılık ve channel’ları var diye Elixir kullan
    Yazarın kendine uyan dili bulmasına sevindim ama tavsiyesini izlemeyeceğim

    • Burada Go’yu Lobsters okurlarına satması gerektiğini düşünen epey kişi var gibi. Bazı insanlarda bu tam tersine geri tepebilir
  • Go’nun sıfır değeri bana hep kusur gibi gelmiştir. Kullanıcıyı varsayılanları açıkça belirtmeye zorlamak daha iyi olurdu bence. Onun dışında OCaml olmamasını hesaba katarsak oldukça iyi bir dil

    • Sıfır değerini seviyorum ve bence oldukça zekice. Ama varsayılan değer atama özelliğinin eksikliği gerçekten kötü. Mesela eksik bool alanının true olması gereken bir JSON nesnesini marshal etmek çok zor
  • Dağıtım ve derleme deneyimi harika ama dilin kendisinde kod yazmaktan gerçekten nefret ediyorum. Her kullandığımda kötü bir deneyim oluyor. Go kadar kısıtlayıcı olmayan ama dağıtım deneyimi iyi olan başka diller var mı?
    Go’da bir şeyi mi kaçırıyorum?
    Yakın zamanda küçük bir Rails uygulaması dağıttım; o kadar çok ayar gerekiyordu ki Go’nun avantajını ister istemez daha çok takdir ettim

    • Yakın zamanda Rust projelerini x86_64-unknown-linux-musl için derlemeye başladım. Böylece tüm 64 bit Linux makinelerde doğrudan çalışan statik binary elde ediyorum. Sonra scp ile kopyalayıp çalıştırıyorum
      Hâlâ port atamak ve elle başlatmak gibi işler var ama biraz systemd büyüsüyle çözeceğim
    • Dağıtım deneyimi açısından şirkette nix bundler ile şaşırtıcı derecede büyük başarı elde ettik. Bağlam vermek gerekirse Qt6 GUI uygulaması geliştiriyoruz
      Bundler ile tek bir çalıştırılabilir dosya üretilebiliyor; bunu başka dağıtımlardaki Linux makinelere atsan bile, hatta Qt kurulu olmasa bile, kullanıcı sadece yürütülebilir dosyayı çalıştırarak tüm GUI’yi kullanabiliyor
      Ama OpenGL sürücüleri konusunda bazı pürüzler olduğu notunu düşmek gerekir. Hâlâ mümkün ama “kopyala ve çalıştır” kadar basit değil
  • Go’nun eşzamanlılık için tasarlandığını iddia ederken, yanlışlıkla kolayca paylaşılabilen ham pointer’ları yerleşik olarak sunması en büyük sorun bence

  • Sıkıcı olması tek başına sorun değil ama Go, gerçekten sıkıcı bir dil olmayı tuhaf biçimde başaramıyor bence
    “Decorator yok” deniyor ama struct tags ve reflection var. Bunların nasıl etkileştiğini çalıştırmadan anlamak zor
    Yapısal interface’ler ve reflection, davranışın uzaktan değişmesine yol açan korkutucu kaynaklar. Sadece bir struct’a yanlış bir metot ekledin diye bir kütüphanenin davranışı tamamen değişebilir
    Dokümantasyon açısından da tuhaf. Bir tipin hangi interface’i karşılamasının amaçlandığını açıkça göstermek istememek için bir sebep var mı?
    Goroutine’lere neden doğrudan thread denmediğini anlamıyorum
    Channel’lar neden dil özelliği olmak zorunda? Bence bunun sebebi, generics’in yalnızca üç kadar tip için değil daha genel olarak faydalı olduğunu kabul etmelerinin 10 yıl sürmesi

    • Goroutine’ler thread değil; thread havuzu üstünde çalışan daha hafif bir soyutlama. Bu yüzden binlercesini kolayca oluşturabiliyorsun
      Channel’ların runtime’ın bir parçası olması da muhtemelen goroutine scheduler’ının channel’ları bilmesi sayesinde, bir channel boş olmaktan çıktığında alıcı goroutine’i daha kolay uyandırabilmesi için. Muhtemelen böyle yapmak daha kolaydı
    • Çünkü goroutine’ler, üzerine çeşitli ek araçlar eklenmiş green thread’lerdir