Kafayı yiyecektim arkadaşlar. Bir API endpoint'i, belli bir koşulda null döndürüyordu. Basit bir null check ekleyip, belki bir iki satır temizlik yapayım dedim. "Sadece şurayı düzelteceğim" cümlesi, yazılım dünyasındaki en büyük yalan sanırım.
if response is not None diyerek başladım işe. Ama sonra gördüm ki, response geliyor ama içindeki data alanı boş bir liste. Onu da kontrol ettim. Derken, bu endpoint'i kullanan 3 farklı servis olduğunu fark ettim. Biri list, biri dict, diğeri string bekliyordu! Hepsi aynı koddan besleniyordu. İşte o an, refactor fikri beynimde bir ampul gibi patladı. "Bu karmaşayı düzeltmeliyim" dedim.
Python:
# Eski korkunçluk
def get_data():
# bazen None, bazen [], bazen {}
return magic()
Hızlıca bir DataParser sınıfı yazmaya koyuldum. Her servis tipi için ayrı bir parse metodu. Interface'i güzel, temiz oldu. Testleri local'de çalıştırdım, her şey harika. Deploy'u attım.
10 dakika sonra Slack'te yangın çanları çalmaya başladı. Bir servis TypeError veriyor, diğeri eski formatı beklediği için data'yı boş görüyor. Meğerse ben refactor ederken, o "basit" null check'i sildiğim yerde, artık None gelen durumları hiç handle etmiyormuşum! Üstelik yeni parser, tarih formatını da farklı döndürüyordu. İki tane yepyeni, güzelim bug daha eklemiştim sisteme. Şaka gibi ama gerçek.
Bence sebebi şu: Kodun bir yerine dokunduğunda, o kodun gizli bağımlılıklarını ve tüm kullanım senaryolarını ilk bakışta göremiyorsun. "Temizleme" isteği, seni orijinal bug'ın çok ötesine taşıyor. Ve her yeni satır, yeni bir potansiyel hata demek.
Peki çözüm? Sanırım unit test coverage'i yüksek tutmak ve değişiklik yapmadan önce git blame ile o koda son dokunanları/commit mesajlarını incelemek şart. Ama itiraf ediyorum, bazen "hızlıca düzeltirim" dürtüsü hepsini ezip geçiyor.
Siz de böyle "ufak bir düzeltme" ile projeyi yıkıp, gece yarısı hotfix yüklemek zorunda kaldığınız oldu mu? Bu refactor-bug döngüsünden çıkmanın bir sırrı var mı?