- İkili arama (binary search) kavramı yalnızca mülakat sorularında değil, gerçek geliştirme aracı olan Git içinde de kullanılır
- Büyük ölçekli monorepo ortamlarında testler aniden başarısız olduğunda, yalnızca loglarla nedenin izini sürmek zorlaşabilir
- Bir ekip arkadaşı, iyi commit ile kötü commit'i belirleyip
git bisect ile otomatik arama yaparak hatanın başladığı sorunlu commit'i tam olarak buldu
- Her adımda bir script çalıştırılıp test sonucuna göre commit'ler otomatik sınıflandırılır ve ilk kez başarısız olan commit tespit edilir
- İkili arama ilkesini kullanan
git bisect, büyük kod tabanlarında hata nedenini hızla izlemek için güçlü bir araçtır
Algoritma ve gerçek vaka
- İkili arama (binary search) algoritması, basit bir mülakat sorusunun ötesinde, gerçek hata ayıklama araçlarında da temel ilke olarak çalışır
git bisect, “hatanın ilk kez eklendiği commit'i (first bad commit)” bulmak için ikili arama kullanan bir araç olarak kullanılabilir
- Leetcode'daki “First Bad Version” problemiyle benzer bir mantıkla çalışır
Gerçek iş ortamındaki problem durumu
- Büyük ölçekli monorepo kullanılan ortamlarda her gün yüzlerce hatta binlerce commit oluşur
- Belirli bir test başarısızlığının nedenini yalnızca loglarla izlemek zordur
- Başarısızlığın nedeni, uzak çağrı için gereken token'ı alan yapılandırma dosyasındaki bir string değişikliğiydi; bu değişiklik başka bir hesabı referans aldığı için test başarısız oldu
- Bu değişiklik entegrasyon testlerini geçti, ancak gerçekte sorun yarattı; sayısız commit arasında bunun tam olarak ne zaman ortaya çıktığını bulmak zordu
git bisect ile problem çözümü
- Başka bir ekipten bir çalışma arkadaşı,
git bisect komutunu kullanarak sorunlu commit'i hızla tespit etti
- İyi commit (good) ve kötü commit (bad) belirlendikten sonra araç otomatik olarak aradaki commit'leri checkout edip testleri çalıştırarak nedeni daralttı
- Her test çalıştırması zaman aldı, ancak sonunda sorunu tam olarak ekleyen commit bulundu
- İlgili commit geri alınınca tüm testler normale döndü
git bisect çalışma süreci
Sonuç
git bisect, ikili arama ilkesini kod geçmişi taramasına uygulayan pratik bir araçtır
- Büyük depolarda veya karmaşık değişiklik geçmişlerinde bile hatanın eklendiği anı hızla izleyebilir
- Test otomasyonu ile birleştirildiğinde, büyük kod tabanlarında da istikrarlı hata ayıklama mümkün olur
2 yorum
Bu tür sorunlar yüzünden TBD (trunk-based development) kullanıyoruz.
Hacker News görüşleri
Eskiden test kapsamı bile olmayan ve soyutlamaları berbat, devasa bir kod tabanında çalışırken
git bisectneredeyse işe yarayan tek araçtıKod o kadar karmaşıktı ki hatayı mantıksal olarak izlemek imkânsızdı; bu yüzden sorunun hangi commit’te ortaya çıktığını bulmak çok daha kolaydı
Ama yüksek kaliteli bir kod tabanında bisect’e pek ihtiyaç olmuyordu. Her bileşen bağımsız olarak test edilebiliyordu ve gözlemlenebilirlik (observability) de iyiydi, bu yüzden nereye bakmak gerektiği açıktı
git bisect’in asla gereksiz olmadığını düşünüyorum. Sadece hatayı bulmakla kalmıyor, o hatanın neden ortaya çıktığını da anlamayı sağlıyorCommit mesajlarının özenli olduğu projelerde bisect ile geçmiş commit’lerin bağlamı anlaşılabiliyor ve bu içerik hata düzeltme commit’ine yansıtılabiliyor. Bu döngü commit kültürünün kendisini de güçlendiriyor
Doğrudan izlemek imkânsızdı ama bir bisect script’i yazıp yaklaşık 30 dakika çalıştırınca sorunlu commit’i tam olarak buldum
git bisectbaşlangıçta Linux kernel regression’larını bulmak için eklenmiş bir araçtıDonanım sürücüleri gibi test edilmesi zor durumlarda bile sıradan kullanıcılar kernel üzerinde bizzat bisect yapıp sorunlu commit’i tespit edebilir hâle geldi
Eskiden geliştiricilerden e-postayla yardım istemek gerekirdi, ama artık kullanıcılar sorunu kendileri daraltabiliyor
Örneğin yanlış işlenmiş verinin kapsamını izlemek veya “bu bir hata mı, özellik mi?” sorusunu değerlendirmek için faydalıdır
Örneğin müşteri 6 yıl önceki bir sürümde sorun yaşıyorsa, 4 yıl önceki sürüme yükseltince çözülüp çözülmeyeceği kontrol edilebilir
Ya da kod büyük ölçüde refactor edildiyse, hata düzeltmesinin bilinçli mi yoksa tesadüfi mi olduğu da anlaşılabilir
git bisectiyi çalıştığında harikadır, ama her hatayı bulamazBazı hatalarda belirtiler eklendikleri anda ortaya çıkmaz, daha sonra yapılan başka bir değişiklikle görünür hâle gelir
Böyle durumlarda bisect’in varsayımı bozulur: yani iyi commit ile kötü commit arasında hata sadece bir kez ortaya çıkmış olmalıdır
Test edilemeyen commit’ler
skipile geçilebilir, ama sorunlu commit onlardan biriyse sonuç belirsizleşirYakın zamanda ilk kez ciddi şekilde
git bisectkullandım ve neredeyse sihir gibi geldiAynı ada sahip iki fonksiyon vardı ve kod formatlama çalışması sırasında doğru fonksiyonun import’u kaldırıldığı için sorun ortaya çıkmıştı
Kodu defalarca inceledim ama bisect ile sorunlu commit’i bulana kadar nedenini hiç anlayamadım
Genelde hatanın hangi dosyada ya da fonksiyonda olduğunu zaten bildiğim için bisect’i çok sık kullanmıyorum
Bunun yerine belirli bir fonksiyonun değişim geçmişini izlemek için
git log -L :func_name:path/to/file.ckomutunu kullanıyorumBunun için
.gitattributesayarı gerekiyor.gitattributesayarıyla ilgili ne gerektiğini merak eden bir soru vardı; daha fazla ayrıntı isteniyordugit log -Lzayıf kalıyor. Aynı isimli overload edilmiş fonksiyonlar arasında belirli bir sürümü izlemek zor olduğu için.gitattributesyoksagit log -Sile belirli bir string’i içeren commit’leri bulmak da bir yöntemdirTest script’lerinde exit code 125’i bilmek faydalıdır
Build hatası gibi test sonucunun belirlenemediği durumlarda 125 döndürülürse bisect o commit’i atlar
Bununla ilgili ayrıntıları blog yazımda derledim
git bisect --first-parentkullanmak faydalı olabilirBöylece “hatayı hangi PR ekledi?” sorusuna hızlıca ulaşılabilir; ardından ilgili branch üzerinde bir ayrıntılı bisect daha yapılabilir
Flaky test ortaya çıktığında bisect gerçekten parlıyor
Race condition yüzünden emin olmak için testi yüz binlerce kez çalıştırmak gerekiyorsa, bisect script’ini arka planda bırakmak bunu pratik olarak çözülebilir kılar
Yakın zamanda Svelte ile yapılmış bir müzik çalar projesinde (lets-make-sweet-music.com) bisect ile bir hatanın kök nedenini buldum
Ne test vardı ne de hata log’u, ayrıca
dependabotgüncellemeleri commit sayısını artırdığı için iz sürmek zorduBisect sayesinde sorunlu commit’i buldum; neden de değiştirdiğim dosyanın çoklu event binding özelliğini uygulamıyor olmasıydı
Commit’leri küçük tutarsanız, bisect ile bulunan sorunun nedenini hızla daraltabilirsiniz
Birisi “mülakatlarda binary search öğrenmenin dayatılması saçma” demişti; ama
git bisectbu kavramın gerçek hayattaki iyi bir örneğiYine de bunu elle uygulamaya gerek yok. Çoğu dilde zaten standart kütüphanede bulunuyor
Orta indeksi hesaplarken
(low + high) / 2kullanılırsa overflow oluşabilirBu, invariant temelli düşünmeyi çalıştırmak için en iyi egzersizlerden biridir
Git’te bisect dışında da
log -L,log -S,blamegibi harika kod keşif araçları varBir zamanlar bu konuda bir blog yazısı yazmıştım