Yazılım6 dk okuma

Golang Mülakat Soruları ve Örnek Cevaplar

Golang mülakatında sorulan goroutine, channel, hata yönetimi ve performans sorularını seviyelere göre örnek cevaplarla anlatıyoruz.

Golang Mülakat Soruları ve Örnek Cevaplar

Golang (Go), Google'ın 2009'da duyurduğu, derlenen, statik tipli ve eşzamanlılık (concurrency) odaklı bir programlama dilidir. Bir Golang mülakatında dilin temel sözdizimi ve hata yönetiminin yanı sıra, dilin en ayırt edici özelliği olan goroutine ve channel yapılarına ne kadar hakim olduğunuz sorgulanır.

Hangi Seviyede Hangi Konular Sorulur?

Go mülakatları, dilin sade sözdiziminden dolayı hızla eşzamanlılık ve performans konularına kayar. Seviyelere göre dağılım şu şekildedir:

SeviyeOdak KonularÖrnek Soru Tipi
Temel (Junior)Slice/array farkı, struct, interface, hata yönetimi"defer ne zaman çalışır?" gibi tanım soruları
Orta (Mid)Goroutine, channel, sync paketi, error wrapping"İki goroutine arasında veriyi nasıl senkronize edersiniz?" gibi uygulama soruları
İleri (Senior)Garbage collector, pprof ile profiling, context ile iptal"Bu servis neden bellek sızdırıyor?" gibi analiz soruları

Temel Seviye Sorular

Slice, Array ve Struct

Go'da array sabit uzunlukludur ve uzunluğu tipin bir parçasıdır; slice ise bir array üzerine kurulu, dinamik olarak büyüyebilen bir görünümdür ve günlük kullanımda neredeyse her zaman slice tercih edilir. struct, ilişkili alanları bir arada tutan; Go'da class yerine geçen, ama kalıtım değil kompozisyon (embedding) ile genişletilen bir veri tipidir.

Interface ve Kompozisyon

Go'da bir interface, bir veya daha fazla metot imzasını tanımlayan bir sözleşmedir ve bir tip bu interface'i örtük olarak (implements anahtar kelimesi olmadan) karşılıyorsa otomatik olarak o interface'i sağlamış sayılır. Kalıtım olmadığı için ortak davranış, bir struct'ı başka bir struct'ın içine gömerek (embedding) elde edilir.

SoruCevap
defer ne işe yarar?İçinde bulunduğu fonksiyon geri dönmeden hemen önce çalışacak bir çağrıyı kuyruğa alır; genellikle kaynak kapatma (dosya, bağlantı) için kullanılır.
panic ve recover ne zaman kullanılır?panic, normal akışı durduran beklenmedik bir hatadır; recover ise bir defer içinde çağrılarak panic'i yakalayıp programın çökmesini engeller. Normal hata yönetimi için error dönmek tercih edilir, panic sadece gerçekten kurtarılamaz durumlar içindir.
Go'da hata yönetimi neden error değeriyle yapılır?Go, exception mekanizması yerine fonksiyonların son dönüş değeri olarak error döndürmesini tercih eder; bu, hata yolunun kod okunurken açıkça görülmesini sağlar.

Değer (Value) ve Gösterici (Pointer) Semantiği

Go'da bir fonksiyona bir struct değeri geçirildiğinde, varsayılan olarak o değerin bir kopyası gönderilir; fonksiyon içindeki değişiklikler orijinali etkilemez. Bir *T (pointer) geçirildiğinde ise fonksiyon orijinal veriye doğrudan erişir ve değişiklik kalıcı olur. Mülakatlarda "bu metodu neden pointer receiver ile tanımladınız" sorusu sık gelir: metot struct'ı değiştirecekse veya struct büyükse (kopyalama maliyeti varsa) pointer receiver tercih edilir. Bir metodu tutarlı bir şekilde ya hep value hem hep pointer receiver ile tanımlamak, kod tabanında karışıklığı önler.

type Sepet struct {
    Urunler []string
}

func (s *Sepet) Ekle(urun string) {
    s.Urunler = append(s.Urunler, urun) // pointer receiver: orijinali degistirir
}

Map, Nil Kontrolü ve Zero Value

Go'da her tipin bir sıfır değeri (zero value) vardır: int için 0, string için boş string, pointer/slice/map/interface için nil. Başlatılmamış (nil) bir map'e yazma denemek panic'e yol açar, ama nil map'i okumak güvenlidir ve sıfır değeri döner — bu ayrım, junior seviye mülakatlarda sık karşılaşılan bir tuzaktır. Bir slice'ın nil mi yoksa boş (ama başlatılmış) mı olduğunu ayırt etmek de benzer bir tuzaktır: ikisi de len() == 0 döner, ama == nil karşılaştırması farklı sonuç verir.

Orta Seviye Sorular

Goroutine ve Channel

Goroutine, Go çalışma zamanı (runtime) tarafından yönetilen, işletim sistemi thread'inden çok daha hafif bir eşzamanlılık birimidir; go anahtar kelimesiyle başlatılır. Channel ise goroutine'ler arasında güvenli veri alışverişi ve senkronizasyon sağlayan tipli bir boru hattıdır.

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        results <- j * 2
    }
}

func main() {
    jobs := make(chan int, 5)
    results := make(chan int, 5)

    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)
}

sync Paketi: Mutex ve WaitGroup

Birden fazla goroutine aynı veriye eşzamanlı erişiyorsa sync.Mutex ile bu erişim kilitlenir; birden fazla goroutine'in bitmesini beklemek için ise sync.WaitGroup kullanılır. Mülakatlarda "channel mi mutex mi kullanırsınız" sorusu sık sorulur: Go'nun felsefesi "belleği paylaşarak iletişim kurmak yerine, iletişim kurarak bellek paylaşmaktır" — bu nedenle veri akışı söz konusuysa channel, basit bir sayaç/durum korumak gerekiyorsa mutex daha uygundur.

Hata Sarmalama (Error Wrapping)

Go 1.13 ile gelen %w biçimlendirme fiili ve errors.Is/errors.As fonksiyonları, bir hatayı orijinal bağlamını kaybetmeden sarmalamayı ve daha sonra bu hatanın belirli bir tipte olup olmadığını kontrol etmeyi sağlar.

if err != nil {
    return fmt.Errorf("kullanici getirilemedi: %w", err)
}

// Çağıran taraf
if errors.Is(err, sql.ErrNoRows) {
    // özel durum yönetimi
}

İleri Seviye Sorular

Garbage Collector ve Bellek Yönetimi

Go'nun çöp toplayıcısı eşzamanlı (concurrent) ve üç renkli işaretle-süpür (tri-color mark-and-sweep) algoritmasına dayanır; uygulamayı uzun süre durdurmadan çalışacak şekilde tasarlanmıştır. Senior seviye mülakatlarda, gereksiz heap tahsisinden kaçınmak için değerlerin ne zaman stack'te ne zaman heap'te tutulduğunu belirleyen escape analysis kavramı da gündeme gelebilir.

Profiling: pprof

Go'nun standart kütüphanesindeki net/http/pprof paketi, çalışan bir servisin CPU kullanımını, bellek tahsislerini ve goroutine sayısını canlı olarak profillemeyi sağlar. Bir performans sorununu "nasıl teşhis edersiniz" sorusuna en somut cevap, pprof çıktısını nasıl okuyup yorumladığınızı anlatmaktır.

context Paketi ile İptal ve Zaman Aşımı

context paketi, bir isteğin sınırlarını (zaman aşımı, iptal sinyali, istek bazlı değerler) goroutine'ler arasında taşımak için kullanılır. Özellikle bir HTTP isteğinin belirli bir süre içinde cevap vermezse iptal edilmesi gereken senaryolarda kullanılır.

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

result, err := fetchData(ctx)
if err != nil {
    log.Println("istek iptal edildi veya zaman asimina ugradi:", err)
}

AppFellas

Fikrinizi konuşalım.

Ücretsiz keşif görüşmesinde projenizi, bütçenizi ve zaman çizelgenizi netleştirelim.

Sık Yapılan Golang Hataları

  • Goroutine sızıntısı: Bir channel'dan hiç okuma yapılmayacaksa veya kapatılmayacaksa, o channel'ı bekleyen goroutine sonsuza kadar bellekte kalır.
  • Döngü değişkenini closure içinde yanlış yakalamak: Go 1.22 öncesinde for döngüsündeki değişkeni bir goroutine içinde doğrudan kullanmak, beklenmedik şekilde hep son değeri yakalayabilirdi; bu davranış Go 1.22 ile değişti, ama eski kod tabanlarında hâlâ görülebilir.
  • error'ları sessizce yutmak: _ = someFunc() gibi hatayı görmezden gelmek, üretimde teşhisi çok zorlaştıran sessiz hatalara yol açar.
  • Gereksiz interface tanımlamak: Go'nun felsefesi "küçük interface'ler, kullanan tarafta tanımlanır"dır; sağlayan tarafta önceden geniş bir interface tanımlamak, Go'nun idiomatic yaklaşımına aykırıdır.

Örnek Mülakat Senaryosu: Race Condition Bulma

Mülakatlarda sık sorulan bir pratik senaryo: "Aşağıdaki kod bazen yanlış sonuç veriyor, neden?" sorusuyla birlikte kilitlenmeyen bir sayaç örneği verilir:

var sayac int

func arttir() {
    sayac++ // atomik degil: okuma + yazma iki ayri adim
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            arttir()
        }()
    }
    wg.Wait()
    fmt.Println(sayac) // 1000 degil, degisken bir sonuc verebilir
}

Doğru cevap, sayac++'in aslında "oku, bir ekle, yaz" olmak üzere üç ayrı adımdan oluştuğunu ve birden fazla goroutine bu adımları aynı anda çalıştırdığında verinin kaybolabileceğini (race condition) açıklamaktır. Çözüm olarak sync.Mutex ile kilitleme ya da sync/atomic paketinin atomik işlemleri gösterilir. Bu tür bir soruda go run -race bayrağının bu sınıf hataları nasıl yakaladığını bilmek de artı değer taşır. Bu senaryo aynı zamanda "neden Go'da mutex de var, channel de var" sorusuna doğal bir geçiş sağlar: basit bir sayaç korumak için mutex yeterliyken, veri akışı ve iş dağıtımı gerektiren senaryolarda channel daha okunabilir bir çözümdür.

Mülakata Hazırlık İçin Pratik İpuçları

  • Goroutine ve channel kullanan küçük bir örnek proje (örneğin basit bir iş kuyruğu) yazıp GitHub'da paylaşın; bu, mülakatta somut bir referans noktası oluşturur.
  • go vet ve golangci-lint gibi araçları kullanmayı bilin; kod kalitesi konusundaki farkındalığınızı gösterir.
  • Standart kütüphaneyi (özellikle net/http, encoding/json, context) dışarıdan paket eklemeden kullanabildiğinizi gösterin; Go ekosisteminde bu tercih edilen bir yaklaşımdır.
  • Bir race condition örneğini go run -race ile nasıl tespit edeceğinizi anlatabilecek düzeyde pratik yapın.

Backend tarafında başka bir dil için de mülakata hazırlanıyorsanız C# mülakat soruları ve Python mülakat soruları yazılarımızı inceleyebilirsiniz. AppFellas'ın geliştirdiği projelere işlerimiz sayfasından, ekiple iletişime geçmek için iletişim sayfamızdan ulaşabilirsiniz.

Sıkça Sorulan Sorular

Sık sorulan sorular

Golang mülakatı için kaç yıllık deneyim aranır?

İlana göre değişir. Junior pozisyonlarda dilin temel yapı taşlarını (slice, struct, interface, hata yönetimi) bilmek yeterli olurken, mid ve senior pozisyonlarda eşzamanlılık (goroutine/channel) ve performans konularında gerçek proje deneyimi beklenir.

Mülakatta canlı kod yazmam istenir mi?

Evet, çoğu Golang mülakatında en az bir canlı kodlama bölümü bulunur. Genellikle bir goroutine/channel senaryosu ya da basit bir algoritma sorusu, paylaşımlı bir editör veya online derleyici üzerinden çözülür.

Hangi konulara öncelikle çalışmalıyım?

Goroutine ve channel'lar, hata yönetimi (error wrapping), ve temel algoritma/veri yapıları en sık sorulan konulardır. Senior pozisyonlar için buna garbage collector ve pprof ile profiling de eklenir.

Web framework (Gin, Echo) bilmek şart mı?

Pozisyona göre değişir. Bazı ekipler sadece standart kütüphanenin <code>net/http</code> paketini kullanır, bazıları Gin veya Echo gibi framework'lere aşinalık ister; bu detay genellikle ilan metninde veya ön görüşmede netleşir.

Golang mülakatında algoritma sorusu (LeetCode tarzı) çıkar mı?

Bazı şirketlerde evet, dil bağımsız algoritma/veri yapısı soruları Go ile çözülmesi istenebilir. Ancak çoğu Golang mülakatı, dilin kendine özgü yapılarına (goroutine, channel, error handling, pointer semantiği) daha çok ağırlık verir; bu oran şirketten şirkete değişir.

Paylaş

Bu konuyu projenize uygulayalım.

Yazıda anlatılanları kendi ürününüzde nasıl hayata geçireceğinizi ücretsiz keşif görüşmesinde konuşalım.