Yazılım

Golang Mülakat Soruları: Concurrency, Goroutine ve Channel Yapıları

Talha AslanTalha Aslan 15 dk okuma 1 görüntülenme

Golang mülakat soruları, Go geliştirici adaylarının dilin temellerini ve özellikle goroutine, channel, select, sync paketi ve context gibi eşzamanlılık araçlarını ne kadar doğru kullandığını ölçen soru setidir. 2012'den beri web projeleri yönetiyorum ve arka uç ekibine geliştirici alırken bu soruları masanın öbür tarafından soruyorum.

Bu yazıda genel Go sorularını kısa tutup ağırlığı eşzamanlılığa veriyorum. Her sorunun altında mülakatçının aslında neyi ölçtüğünü ve kısa bir kod örneğini bulacaksınız. Yazılımla ilgili diğer içeriklere yazılım kategorisinden ulaşabilirsiniz.

Golang mülakat soruları nelerdir ve hangi konulara odaklanır?

Golang mülakat soruları dört katmanı kapsar: dil temelleri, goroutine ve zamanlayıcı mantığı, channel ile select kullanımı, sync ve context ile gerçek hayat desenleri. Orta seviye bir pozisyonda soruların yarısından fazlası eşzamanlılık üzerinedir, çünkü Go'yu tercih eden ekipler dili genellikle yüksek trafikli servisler için seçer.

Bu nedenle hazırlanırken tanım ezberlemek yerine küçük programlar yazmanızı öneririm. Örneğin bir işçi havuzu, zaman aşımlı bir HTTP çağrısı ve veri yarışı içeren bir sayaç yazıp düzeltirseniz, mülakattaki soruların büyük kısmını zaten deneyimlemiş olursunuz. Ayrıca kodu sesli anlatma alışkanlığı kazanırsınız.

Mülakatçı Go sorularıyla aslında neyi ölçer?

Mülakatçı Go sorularıyla üç şeye bakar: kavramı doğru tanımlayabiliyor musunuz, riskini görebiliyor musunuz ve gerçek kodda nasıl kullandığınızı anlatabiliyor musunuz. Tanımı bilen aday çoktur; ancak bir goroutine sızıntısının üretimde nasıl fark edildiğini anlatan aday azdır.

Benim masada en çok değer verdiğim şey, adayın "bilmiyorum, ama şöyle test ederdim" diyebilmesidir. Örneğin sync.Map ile kilitli map arasındaki performans farkını ezbere bilmeyen biri, bunu benchmark yazarak ölçeceğini söylerse güçlü bir sinyal verir. Kısacası süreci yanıt kadar önemsiyorum.

  • Kavram doğruluğu: goroutine, channel ve mutex arasındaki farkı net anlatmak.
  • Risk farkındalığı: deadlock, veri yarışı ve sızıntıyı tanımak.
  • Pratik: race detector, pprof ve test araçlarını kullanmış olmak.
  • İletişim: tasarım kararını gerekçesiyle savunmak.

Goroutine nedir ve işletim sistemi thread'inden farkı nedir?

Goroutine, Go çalışma zamanının yönettiği hafif bir yürütme birimidir. Bir fonksiyonun önüne go anahtar kelimesini yazarsanız o fonksiyon aynı adres alanında eşzamanlı çalışmaya başlar. İşletim sistemi thread'inden farkı, zamanlamayı çekirdeğin değil Go çalışma zamanının yapmasıdır.

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        selamla("Ayşe")
    }()
    wg.Wait()
}

Go 1.4 sürüm notlarına göre bir goroutine yığını 2048 bayt ile başlar ve gerektiğinde büyür. Bu yüzden on binlerce goroutine açmak mümkündür. Ancak iyi bir yanıt burada durmaz: goroutine ucuzdur ama bedava değildir. Dolayısıyla sınırsız goroutine açan bir kod, bellek ve bağlantı havuzunu yine tüketebilir.

Bu örnekte beklemeyi bilerek WaitGroup ile yaptım. Mülakatlarda sık gösterilen tuzak, aynı kodu time.Sleep ile bekletmektir; süre ya yetmez ya da boşa bekletir. Mülakatçı genellikle "bunu nasıl düzeltirsiniz?" diye sorar. Doğru yanıt, beklemeyi zamana değil WaitGroup veya channel gibi bir senkronizasyon aracına bağlamaktır.

Go zamanlayıcısı G, M ve P modeliyle nasıl çalışır?

Go zamanlayıcısını üç kavramla anlatırsınız: G goroutine'dir, M işletim sistemi thread'idir, P ise çalıştırma bağlamıdır. Bir G'nin çalışması için bir M'nin bir P tutması gerekir. Böylece aynı anda Go kodu çalıştıran thread sayısı P sayısıyla, yani GOMAXPROCS değerine eşit kalır.

Her P'nin kendi yerel çalışma kuyruğu vardır. Kuyruğu boşalan bir P, başka P'lerin kuyruğundan iş çalar; buna work stealing denir. Ayrıca bir goroutine sistem çağrısında bloklanırsa zamanlayıcı P'yi başka bir M'ye devreder, böylece diğer goroutine'ler beklemez.

Bu soruda mülakatçı ezber değil sezgi arar. Örneğin "GOMAXPROCS'u 1 yaparsam eşzamanlılık biter mi?" sorusuna doğru yanıt hayırdır: eşzamanlılık devam eder, yalnızca paralellik ortadan kalkar. Bu ayrım, bir sonraki sorunun da temelidir.

Concurrency ile parallelism arasındaki fark nedir?

Concurrency, birden fazla işi aynı zaman diliminde yönetebilecek şekilde programı yapılandırmaktır. Parallelism ise bu işlerin fiziksel olarak aynı anda, farklı çekirdeklerde çalışmasıdır. Tek çekirdekli bir makinede eşzamanlı bir program yazabilirsiniz; ancak paralel çalıştıramazsınız.

Go ekibinin sık alıntılanan yaklaşımı da budur: eşzamanlılık bir tasarım biçimidir, paralellik ise çalıştırma biçimidir. Bu nedenle iyi bir yanıt, Go'nun size eşzamanlı tasarım araçları verdiğini, paralelliği ise çalışma zamanının ve donanımın sağladığını vurgular.

KavramAnlamıGo'daki karşılığı
Concurrencyİşleri iç içe yönetmegoroutine, channel, select
Parallelismİşleri aynı anda çalıştırmaGOMAXPROCS, çok çekirdek
SenkronizasyonPaylaşılan veriyi korumasync.Mutex, sync/atomic
İptalİşi zamanında durdurmacontext.Context

Channel nedir, buffered ve unbuffered channel farkı nedir?

Channel, goroutine'ler arasında tür güvenli veri taşıyan bir iletişim hattıdır. Effective Go belgesindeki ilke bunu özetler: belleği paylaşarak iletişim kurmayın, iletişim kurarak belleği paylaşın. Yani veriyi kilitle korumak yerine sahipliğini channel üzerinden devredersiniz.

ch := make(chan int)      // unbuffered
bch := make(chan int, 3)  // buffered, kapasite 3

Unbuffered channel'da gönderen, alıcı hazır olana kadar bekler; dolayısıyla gönderme ile alma aynı anda gerçekleşir ve iki goroutine senkronize olur. Buffered channel'da ise gönderen, tampon dolana kadar beklemez. Öte yandan tampon doluysa gönderen yine bloklanır.

Mülakatta sık gelen tuzak şudur: "Tampon koyarsam deadlock çözülür mü?" Çoğu zaman çözülmez, yalnızca ertelenir. Bu yüzden tampon boyutunu performans için değil, tasarımın gerektirdiği kadar seçtiğinizi anlatmanız iyi bir izlenim bırakır.

Kapalı bir channel'dan okursanız ya da ona yazarsanız ne olur?

Kapalı bir channel'dan okumak panik üretmez; tampondaki değerler bittikten sonra türün sıfır değeri döner. Öte yandan kapalı bir channel'a yazmak panik üretir. Aynı channel'ı ikinci kez kapatmak da panik verir. Mülakatçılar bu üç davranışı neredeyse her zaman sorar.

v, ok := <-ch
if !ok {
    // channel kapalı ve boş
}

İkinci dönüş değeri ok, değerin gerçek bir gönderimden mi yoksa kapanıştan mı geldiğini söyler. Ayrıca range ile bir channel üzerinde dönerseniz döngü, channel kapanıp boşaldığında kendiliğinden biter. Bu nedenle üretici tarafın işi bitince channel'ı kapatması gerekir.

Kuralın pratik özeti şudur: channel'ı yalnızca gönderen taraf kapatır, alıcı kapatmaz. Birden fazla gönderen varsa kapanışı bir WaitGroup ile koordine eden ayrı bir goroutine üstlenir. Örneğin fan-in deseninde bu yaklaşımı sıkça görürsünüz.

Nil channel nasıl davranır ve select içinde neden işe yarar?

Nil bir channel'a gönderme de, ondan okuma da sonsuza kadar bloklanır. İlk bakışta bu bir hata gibi görünür; ancak select içinde bilinçli olarak kullanılan bir tekniktir. Bir kolu kapatmak istediğinizde channel değişkenini nil yaparsınız ve select o kolu artık seçmez.

for a != nil || b != nil {
    select {
    case v, ok := <-a:
        if !ok { a = nil; continue }
        fmt.Println(v)
    case v, ok := <-b:
        if !ok { b = nil; continue }
        fmt.Println(v)
    }
}

Bu örnekte iki kaynak bağımsız olarak kapanabilir. Kapanan kaynağı nil yaptığınızda döngü, diğer kaynaktan okumaya devam eder. Böylece kapalı channel'dan gelen sıfır değerlerle döngüyü meşgul etmezsiniz. Bu soruyu doğru yanıtlayan aday, genellikle channel'larla gerçekten iş yapmış biridir.

Select ifadesi nasıl çalışır ve default kolu ne işe yarar?

Select, birden fazla channel işlemini aynı anda bekler ve hazır olan kollardan birini çalıştırır. Birden fazla kol hazırsa Go rastgele birini seçer, yani sıralamaya güvenemezsiniz. Hiçbir kol hazır değilse ve default kolu yoksa select bloklanır.

select {
case msg := <-gelen:
    isle(msg)
case <-time.After(2 * time.Second):
    log.Println("zaman aşımı")
}

Default kolu, beklemeden denemek içindir. Örneğin tampon doluysa mesajı düşürmek isteyen bir log yazıcısında işe yarar. Ancak default'u bir for döngüsünün içine koyarsanız boşta dönen bir döngü yazmış olursunuz ve işlemci boşuna yanar. Mülakatçı bu hatayı özellikle arar.

Ayrıca uzun süre çalışan döngülerde time.After yerine yeniden kullanılabilir bir time.Timer tercih etmenizi beklerler. Böylece her turda yeni bir zamanlayıcı üretmezsiniz.

WaitGroup ve Mutex ne zaman kullanılır?

WaitGroup ile bir grup goroutine'in bitmesini beklersiniz. Mutex ise paylaşılan veriye aynı anda tek goroutine'in erişmesini sağlar. Kısacası WaitGroup "ne zaman bitti" sorusunu, Mutex ise "kim dokunabilir" sorusunu yanıtlar.

var wg sync.WaitGroup
var mu sync.Mutex
toplam := 0
for i := 1; i <= 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        mu.Lock()
        toplam += i
        mu.Unlock()
    }()
}
wg.Wait()

Go 1.25 sürüm notlarına göre WaitGroup'a yeni bir Go metodu eklendi; bu metot goroutine başlatma ve sayma desenini tek çağrıya indirir. Yeni sürümle çalışan bir ekipte bunu bilmeniz artı puandır. Öte yandan eski desenin mantığını da anlatabilmelisiniz, çünkü mevcut kod tabanlarının çoğu Add ve Done ile yazılmıştır.

Sık yapılan hata, wg.Add çağrısını goroutine'in içine koymaktır. Bu durumda Wait, Add'den önce çalışabilir ve program erken biter.

RWMutex ve sync/atomic ne zaman tercih edilmeli?

RWMutex, okumaların yazmalardan çok daha sık olduğu durumlar içindir; birden fazla okuyucu aynı anda kilidi tutabilir, yazıcı ise tek başına tutar. sync/atomic ise tek bir sayaç veya bayrak gibi basit değerleri kilit olmadan güvenle günceller.

Ancak her okuma ağırlıklı yapıda RWMutex otomatik olarak hızlı değildir. Kritik bölge çok kısaysa RWMutex'in ek yükü, düz Mutex'ten daha pahalı olabilir. Bu nedenle mülakatta "ölçmeden karar vermem, benchmark yazarım" demeniz doğru bir yaklaşımdır.

  • Tek sayaç veya bayrak: atomic.Int64 veya atomic.Bool.
  • Birkaç alanı birlikte güncelleyen yapı: sync.Mutex.
  • Çok okuma, seyrek yazma ve uzun kritik bölge: sync.RWMutex.
  • Tek seferlik başlatma: sync.Once.

Veri yarışı (data race) nedir ve race detector ile nasıl yakalarsınız?

Veri yarışı, iki goroutine'in aynı bellek konumuna eşzamanlı eriştiği ve en az birinin yazdığı, arada da senkronizasyon olmadığı durumdur. Go bellek modeli belgesi, yarış içeren programların davranışının öngörülemez olabileceğini açıkça belirtir. Dolayısıyla "bende çalışıyor" yanıtı yeterli değildir.

go test -race ./...
go run -race main.go

Race detector, -race bayrağıyla derlenen programda gerçekleşen erişimleri izler ve yarışı yığın izleriyle raporlar. Ancak yalnızca çalışan kod yollarını görür; test etmediğiniz yoldaki yarışı yakalayamaz. Bu yüzden CI hattında testleri -race ile koşturmanızı öneririm.

Belgelere göre race detector bellek kullanımını ve çalışma süresini belirgin şekilde artırır. Bu nedenle üretimde sürekli açık tutmazsınız, ancak yük testlerinde ve CI'da kullanırsınız. Mülakatta bu dengeyi anlatmanız, aracı gerçekten kullandığınızı gösterir.

Deadlock nasıl oluşur ve nasıl önlersiniz?

Deadlock, goroutine'lerin birbirini beklediği ve hiçbirinin ilerleyemediği durumdur. Tüm goroutine'ler bloklanırsa Go çalışma zamanı "all goroutines are asleep - deadlock!" hatasıyla programı durdurur. Ancak yalnızca bir kısmı bloklanırsa program çalışmaya devam eder ve sorun sessizce büyür.

func main() {
    ch := make(chan int)
    ch <- 1          // alıcı yok, sonsuza kadar bekler
    fmt.Println(<-ch)
}

Önlemek için birkaç kural uygularsınız. Birincisi, kilitleri her zaman aynı sırayla alırsınız. İkincisi, channel işlemlerine zaman aşımı veya context ekleyerek sonsuz beklemeyi engellersiniz. Üçüncüsü, kilidi tutarken dış bir fonksiyon çağırmaktan kaçınırsınız. Örneğin kilit içindeki bir channel gönderimi, klasik bir deadlock kaynağıdır.

Goroutine sızıntısı nedir ve nasıl tespit edersiniz?

Goroutine sızıntısı, işi bittiği hâlde asla sonlanmayan goroutine'lerin birikmesidir. En yaygın nedeni, kimsenin okumadığı bir channel'a yazmaya çalışan ya da hiç kapanmayacak bir channel'ı bekleyen goroutine'lerdir. Sonuçta bellek kullanımı yavaşça artar ve servis günler sonra yavaşlar.

func ilkYanit(urls []string) string {
    ch := make(chan string, len(urls)) // tampon sızıntıyı önler
    for _, u := range urls {
        go func() { ch <- getir(u) }()
    }
    return <-ch
}

Bu örnekte tampon olmasaydı, ilk yanıttan sonra kalan goroutine'ler sonsuza kadar bloklanırdı. Tespit için runtime.NumGoroutine değerini metrik olarak izler, pprof ile goroutine profilini alırsınız. Ayrıca testlerde goroutine sayısının test sonunda başlangıca döndüğünü kontrol edebilirsiniz.

Servis performansı yalnızca kodla ilgili değildir; ancak ön yüzde hissedilen hız, site hızının SEO'yu nasıl etkilediği sorusuyla doğrudan bağlantılıdır.

Context paketi iptal ve zaman aşımını nasıl yönetir?

Context, bir isteğin iptal sinyalini, son tarihini ve istek kapsamlı değerlerini goroutine'ler arasında taşır. Bir HTTP isteği iptal edildiğinde, o isteğe bağlı veritabanı sorgusu ve dış servis çağrısı da aynı sinyalle durur. Böylece boşa çalışan goroutine kalmaz.

ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
select {
case sonuc := <-isle(ctx):
    yaz(w, sonuc)
case <-ctx.Done():
    http.Error(w, ctx.Err().Error(), http.StatusGatewayTimeout)
}

Mülakatçının burada aradığı üç ayrıntı vardır. Birincisi, cancel fonksiyonunu defer ile çağırmanız gerekir; aksi hâlde kaynak sızar. İkincisi, context'i yapı alanı olarak değil ilk parametre olarak geçirirsiniz. Üçüncüsü, WithValue'yu isteğe bağlı parametreler için değil, izleme kimliği gibi istek kapsamlı veriler için kullanırsınız.

Worker pool deseni nasıl kurulur?

Worker pool, sabit sayıda goroutine'in ortak bir iş kuyruğundan iş çektiği desendir. Amaç, eşzamanlılığı sınırlamak ve dış kaynakları, örneğin veritabanı bağlantılarını, taşırmamaktır. Canlı kodlama bölümünde en çok istenen görevlerden biridir.

func havuz(isler <-chan int, n int) <-chan int {
    sonuc := make(chan int)
    var wg sync.WaitGroup
    for w := 0; w < n; w++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for j := range isler {
                sonuc <- j * j
            }
        }()
    }
    go func() { wg.Wait(); close(sonuc) }()
    return sonuc
}

Bu kodda dikkat edilecek nokta, sonuc channel'ını ayrı bir goroutine'in kapatmasıdır. Tüm işçiler bitince kapanış gerçekleşir, dolayısıyla tüketici range ile güvenle okur. Ayrıca yön belirten channel türleri, yani <-chan ve chan<-, derleyicinin yanlış kullanımı yakalamasını sağlar.

Fan-out, fan-in ve pipeline desenleri nedir?

Pipeline, her aşaması channel ile bağlanan bir işlem zinciridir. Fan-out, bir aşamanın işini birden fazla goroutine'e dağıtmaktır. Fan-in ise birden fazla channel'ı tek channel'da birleştirmektir. Mülakatçılar bu üç deseni genellikle birlikte sorar.

Örneğin bir görsel işleme servisini düşünün: dosyaları okuyan aşama, küçülten aşama ve kaydeden aşama. Küçültme en yavaş adımsa onu fan-out ile dört işçiye dağıtır, çıktıları fan-in ile tek kanalda toplarsınız. Böylece darboğazı yalnızca gereken yerde genişletirsiniz.

  1. Her aşama bir giriş channel'ı alır ve bir çıkış channel'ı döndürür.
  2. Aşama işi bitince kendi çıkış channel'ını kapatır.
  3. Her aşama context'i dinler ve iptalde erken çıkar.
  4. Fan-in, kapanışı WaitGroup ile koordine eder.

Mülakatta bu listeyi kodla gösterirseniz, iptal edilen bir pipeline'da neden sızıntı olmadığını da açıklamanız beklenir.

errgroup ve semaphore ile hata yönetimi nasıl yapılır?

errgroup paketi, golang.org/x/sync altında bulunur ve bir grup goroutine'i çalıştırıp ilk hatayı döndürür. WithContext ile oluşturduğunuzda, bir goroutine hata verirse ortak context iptal edilir ve diğerleri de durur. Yani WaitGroup artı hata yönetimi artı iptal tek pakette gelir.

g, ctx := errgroup.WithContext(ctx)
g.SetLimit(5)
for _, u := range urls {
    g.Go(func() error { return indir(ctx, u) })
}
if err := g.Wait(); err != nil {
    return err
}

SetLimit, aynı anda çalışan goroutine sayısını sınırlar; bu yüzden basit durumlarda ayrı bir semaphore yazmanıza gerek kalmaz. Ancak ağırlıklı kaynak paylaşımı gerekiyorsa aynı modüldeki semaphore paketini kullanırsınız. Mülakatta bu iki aracı ayırt edebilmeniz, gerçek servis kodu yazdığınızı gösterir.

Döngü değişkeni ve closure tuzağı Go 1.22 ile nasıl değişti?

Go 1.22 öncesinde for döngüsü değişkeni tüm turlar boyunca tek bir değişkendi. Bu nedenle goroutine içinde yakalanan döngü değişkeni, çoğu zaman son değeri gösterirdi. Go ekibinin blog yazısına göre Go 1.22 ile her tur kendi değişkenini alır ve bu klasik hata ortadan kalkar.

for _, v := range []string{"a", "b", "c"} {
    go func() { fmt.Println(v) }() // Go 1.22+: a, b, c
}

Ancak mülakatçı eski davranışı da sorabilir, çünkü go.mod dosyasında daha eski bir go sürümü tanımlı modüllerde eski anlamsal kurallar geçerli kalır. İyi bir yanıt hem yeni kuralı hem de eski kodda neden v := v satırlarını gördüğünüzü açıklar.

Bu tür sürüm ayrıntıları, kod tabanını düzenli güncelleyen ekiplerde önemlidir. Kendi projelerimde de sürüm yükseltmeyi takvime bağlarım; aynı disiplini micro frontend mimarisi yazısında ön yüz tarafı için anlatmıştım.

GOMAXPROCS konteyner ortamında neden önemlidir?

GOMAXPROCS, aynı anda Go kodu çalıştırabilen P sayısını belirler. Uzun süre varsayılan değer makinedeki mantıksal çekirdek sayısıydı. Kubernetes gibi ortamlarda bu, konteynere verilen CPU limitinden çok daha yüksek bir değer anlamına gelebiliyordu ve gereksiz kısıtlamaya yol açıyordu.

Go 1.25 sürüm notlarına göre çalışma zamanı artık Linux'ta cgroup CPU bant genişliği limitini dikkate alır. Limit mantıksal çekirdek sayısından düşükse GOMAXPROCS varsayılan olarak bu limite iner. Üstelik çalışma zamanı değeri periyodik olarak günceller; ancak GOMAXPROCS'u elle ayarlarsanız bu davranış devre dışı kalır.

Mülakatta bu soruya yanıt verirken Go sürümünü sormanız bile olgunluk göstergesidir. Eski sürümde çalışan bir servis için ayarın elle yapılması gerektiğini söylemek doğru bir yanıttır.

Eşzamanlı kodu nasıl test edersiniz?

Eşzamanlı kodu test ederken üç araca yaslanırsınız: -race bayrağı, zaman aşımlı testler ve deterministik zaman. Go 1.25 ile genel kullanıma açılan testing/synctest paketi, testi izole bir "baloncuk" içinde çalıştırır ve bu baloncukta zamanı sanal hâle getirir. Böylece time.Sleep içeren testler anında biter.

Ayrıca testte uyku süresine güvenmek yerine senkronizasyon noktalarına güvenmelisiniz. Örneğin bir goroutine'in başladığını anlamak için Sleep değil bir channel sinyali kullanırsınız. Bu küçük fark, CI'da ara sıra kırılan testlerin çoğunu ortadan kaldırır.

  • Her testi go test -race ile en az bir kez çalıştırın.
  • Kararsız testleri -count bayrağıyla tekrar tekrar koşturun.
  • Zamana bağlı mantık için synctest veya enjekte edilebilir saat kullanın.
  • Goroutine sayısının test sonunda başlangıca döndüğünü doğrulayın.

Performansı ölçmeden yorumlamamak burada da geçerlidir. Web tarafında aynı ilkeyi Lighthouse ile performans testi yazısında anlatmıştım.

Canlı kodlama turunda hangi görevler çıkar?

Canlı kodlama turunda genellikle 30 ile 45 dakikalık küçük görevler gelir; bu aralık benim masadaki gözlemimdir, garanti değildir. En sık gördüğüm görevler, sınırlı eşzamanlılıkla URL indirme, zaman aşımlı bir istek toplayıcı ve güvenli bir önbellek yazmaktır.

  1. Soruyu kendi cümlelerinizle tekrar edin ve sınırları sorun.
  2. Önce çalışan en basit sürümü yazın.
  3. Ardından eşzamanlılığı ekleyin ve iptal yolunu gösterin.
  4. Son olarak yarış ve sızıntı risklerini sesli değerlendirin.

Bu sırayı izlerseniz süre dolsa bile çalışan bir kod bırakırsınız. Öte yandan doğrudan karmaşık bir çözüme atlayan aday, çoğu zaman yarım kalmış bir kodla turu bitirir. Kısacası mülakatçı mükemmel koddan çok düşünce düzenini puanlar.

Golang mülakat soruları için hazırlık planı nasıl olmalı?

Golang mülakat soruları için iki haftalık bir plan çoğu aday için yeterli başlangıçtır; bu süre saha tecrübesine dayalı bir öneridir, garanti değildir. İlk hafta dil temellerini ve eşzamanlılık kavramlarını, ikinci hafta ise desenleri ve canlı kodlamayı çalışırsınız.

GünKonuÇıktı
1-3Slice, map, interface, hata yönetimiKüçük bir CLI aracı
4-7Goroutine, channel, select, syncYarışlı sayaç ve düzeltmesi
8-10Context, worker pool, errgroupSınırlı eşzamanlı indirici
11-14Test, race detector, pprof, deneme mülakatıTestli küçük bir servis

Bu plandaki her çıktıyı bir GitHub deposunda tutarsanız, mülakatta göstereceğiniz somut bir portföyünüz olur. Ayrıca README dosyalarını düzgün yazmak, yazılı iletişim becerinizi de gösterir. Kod dışı işlerde benimle çalışmak isterseniz web tasarım hizmetime göz atabilirsiniz.

Golang mülakat sorularında en sık yapılan hatalar nelerdir?

Golang mülakat sorularında en sık gördüğüm hata, her problemi channel ile çözmeye çalışmaktır. Bazen basit bir Mutex, hem daha anlaşılır hem daha hızlıdır. Go'nun kendi belgeleri de iki aracı rakip değil tamamlayıcı olarak sunar; dolayısıyla doğru aracı seçme gerekçesini anlatmanız beklenir.

  • Beklemeyi time.Sleep ile yapmak.
  • Channel'ı alıcı taraftan kapatmak.
  • cancel fonksiyonunu çağırmayı unutmak.
  • Sınırsız goroutine başlatıp kaynakları tüketmek.
  • Race detector'ı hiç çalıştırmamış olmak.

Bir diğer hata da hatayı yutmaktır. Goroutine içinde oluşan hatayı loglayıp geçmek yerine errgroup veya bir sonuç channel'ı ile yukarı taşımanız gerekir. Mülakatçı, hatanın nereye gittiğini sorduğunda net bir yanıtınız olmalı.

Son olarak özgeçmişinizi ve portföy sayfanızı da özenle hazırlayın. Ben hakkımda sayfamda nasıl çalıştığımı açıkça yazıyorum; aday olarak sizin de aynı açıklıkla kendinizi anlatmanızı öneririm. Sorularınız için iletişim sayfasından bana ulaşabilirsiniz.

Resmi kaynaklardan nasıl çalışmalısınız?

En sağlam kaynak Go ekibinin kendi belgeleridir. Effective Go eşzamanlılık bölümüyle temel ilkeleri verir. Go bellek modeli ise senkronizasyonun resmi tanımını yapar ve ileri seviye soruların kaynağıdır.

Ayrıca race detector belgesi aracın sınırlarını anlatır. Sürüm değişiklikleri için Go 1.25 sürüm notlarını ve döngü değişkeni değişikliğini anlatan Go blog yazısını okumanızı öneririm. Böylece mülakatta güncel ve doğrulanabilir bilgiyle konuşursunuz.

#Golang#Go#Mülakat#Concurrency#Goroutine#Backend
Paylaş:
Talha Aslan
Talha Aslan

Google Partner dijital pazarlama uzmanı. 2012’den beri SEO, Google Ads, web tasarım ve e-ticaret projelerinde sahada; bu blogda gördüğünüz her yazı o deneyimden çıkar.

Sıradaki proje

Projenizi konuşalım.

Aracı yok, katman yok: doğrudan işi yapacak uzmanla konuşursunuz. İlk istişare ücretsizdir; hedefinizi dinler, net bir yol haritasıyla dönerim.

WhatsApp Hemen Ara