Regresyon, kodda değişiklik yapıldıktan sonra ortaya çıkan bir hatadır, oysa aynı işlevsellik daha önce doğru çalışıyordu. Regresyon, yeni bir değişikliğin daha önce yazılmış ve test edilmiş olanı “bozduğu” anlamına gelir. Geliştirmedeki en yaygın ve tehlikeli sorunlardan biridir: bir hatayı düzeltirken geliştirici farkında olmadan diğer üç özelliği bozabilir. Capers Jones Software Engineering 2023’e göre, değiştirilen her 100 kod satırında ortalama regresyon hatası yoğunluğu 1–3’tür. Regresyonların nedenlerini, tespit yöntemlerini ve önleme stratejilerini inceleyelim.
Önemli Noktalar
Regresyon, önceki bir sürümde çalışan bir işlevselliğin değişiklik yapıldıktan sonra çalışmayı durdurduğu bir durumdur. Değişiklik herhangi bir şey olabilir: hata düzeltme, yeni özellik ekleme, yeniden düzenleme, kitaplık güncelleme veya hatta bir yapılandırma değişikliği. Regresyon, istikrarın ana düşmanıdır: her değişiklik, daha önce doğrulanmış ve yayınlanmış bir şeyi bozma riski taşır.
Terim testten gelir: regresyon testi, eski işlevselliğin bozulmadığını doğrulamak için her değişiklikten sonra mevcut testlerin yeniden çalıştırılması sürecidir. Daha önce geçen bir test başarısız olursa, bir regresyon meydana gelmiştir. Daha geniş anlamda regresyon, yalnızca bir test başarısızlığı değil, kullanıcı veya QA tarafından fark edilen herhangi bir davranış bozulmasıdır. Tricentis State of Testing 2023’e göre, regresyonlar üretimde bulunan tüm hataların %35–45’ini oluşturur.
Bir regresyonu sıradan bir hatadan ayıran şey zamansal bağlamdır: sıradan bir hata her zaman var olmuş olabilirken, regresyon her zaman bir değişikliğin sonucudur. Bu önemli bir ayrımdır çünkü bir regresyonun nedenini bulmak, “çalışıyordu” ve “çalışmayı durdurdu” arasında neyin değiştiğini analiz etmekle başlar. Git bisect, regresyona neden olan commit’i bulmak için standart araçtır.
Yerel regresyon — A modülündeki bir değişiklik, aynı A modülündeki işlevselliği bozar. Örnek: bir geliştirici sıralama işlevini yeniden yazar ve boş bir diziyi doğru şekilde işleyemez hale gelir. Yerel regresyon, neden ve sonuç yakın olduğu için tespit edilmesi ve düzeltilmesi en kolay olanıdır.
Uzak regresyon — A modülündeki bir değişiklik, kodla doğrudan bağlantılı olmayan ancak veri veya zamanlama ile bağlantılı olan B modülündeki işlevselliği bozar. Örnek: “Kullanıcılar” modülündeki veritabanı şemasını değiştirmek, aynı tabloyu kullanan “Analitik” modülündeki bir raporu bozar. Uzak regresyonlar en sinsi olanlardır: geliştirici, değişikliğinin başka bir modülü etkileyeceğinden şüphelenmez.
Yan etki regresyonu — bir yan etkideki (günlükleme, önbellekleme, bildirim gönderme) değişiklik beklenen davranışı bozar. Örnek: bir geliştirici performansı hızlandırmak için önbellek ekler, ancak eski önbellek nedeniyle kullanıcılar güncel olmayan verileri görür. Yan etki regresyonlarını otomatik testlerle yakalamak zordur çünkü yan etkiler genellikle testler tarafından kapsanmaz.
Performans regresyonu — kod işlevsel olarak doğru çalışmaya devam eder ancak eskisinden daha yavaştır. Örnek: yeni bir şifreleme algoritması aynı sonuçları üretir, ancak yürütme süresi 2 ms’den 200 ms’ye çıkmıştır. Performans regresyonları sıradan birim testleri tarafından tespit edilmez — kıyaslamalar ve profil oluşturma gerekir.
| Regresyon Türü | Örnek | Tespit Yöntemi |
|---|---|---|
| Yerel | Bozuk sıralama | Birim testleri |
| Uzak | DB şema değişikliği | Entegrasyon testleri |
| Yan etki | Eski önbellek | E2E testleri |
| Performans | Yavaş yanıt | Kıyaslamalar |
İlk neden kod bağımlılığıdır. Modüller birbirine ne kadar bağımlıysa, birindeki değişikliğin diğerinde regresyona neden olma olasılığı o kadar yüksektir. Klasik anti-örüntüler: God Object (her şeyi yapan nesne), Shotgun Surgery (bir yerdeki değişiklik düzinelerce yerde düzenleme gerektirir), döngüsel bağımlılık. Bağımlılığı azaltmak mimari meselesidir: SOLID ilkeleri, Bağımlılık Enjeksiyonu, heksagonal mimari.
İkinci neden, değiştirilen işlevsellik için test eksikliğidir. Kod testlerle kapsanmıyorsa, geliştirici bir regresyonu yalnızca QA veya kullanıcılardan öğrenir. Google Testing Blog’a göre, test kapsamı >%75 olan projeler, kapsamı <%25 olan projelere göre 5 kat daha az regresyona sahiptir. TDD (Test Odaklı Geliştirme), testlerin “zaman olunca” değil, koddan önce yazılmasını sağlar.
Üçüncü neden insan faktörüdür. Geliştirici ilgili işlevselliği bilmez, tüm bağımlılıkları anlamaz veya sadece acele ediyordur. Nedeni, kod tabanı bilgi paylaşımının yetersiz olmasıdır. Çözümler: diğer modüllerden geliştiricilerle kod incelemesi, çiftli programlama, mimari dokümantasyonu. Projenin otobüs faktörü, belgelenmiş mimari kararların sayısıyla ters orantılıdır.
Regresyon testi, eski işlevselliğin bozulmadığını doğrulamak için her değişiklikten sonra mevcut testlerin yeniden çalıştırılması sürecidir. Yeni bir değişikliğin mevcut kodu bozmadığını garanti etmenin tek yoludur. Regresyon testi olmadan, her sürüm bir piyangodur: geliştirici hiçbir şeyi bozmadığını umar ancak bunu doğrulayamaz.
Manuel regresyon testi en pahalı ve en az etkili yaklaşımdır. Bir proje büyüdükçe, regresyon test senaryolarının sayısı doğrusal olarak artarken, manuel yürütme süresi üstel olarak artar. 2–3 yıllık geliştirmeden sonra, manuel regresyon 2–3 hafta sürebilir ve sık sürümleri imkansız hale getirir. Tek çözüm otomasyondur.
Otomatik regresyon testi, test piramidine göre seviyelere ayrılır:
Google Testing Blog’a göre, optimum oran %70 birim testi, %20 entegrasyon testi, %10 E2E’dir. Bu orandan sapmak regresyon testinin etkinliğini azaltır: çok fazla E2E testi hattı yavaşlatır, çok az birim testi mikro hataların tespit edilmemesine neden olur.
İlk strateji Tam Regresyon’dur. Projenin tüm testleri çalıştırılır. En güvenilir ancak en yavaş yaklaşım. Küçük projeler için uygundur (10.000 teste kadar, çalışma süresi <30 dakika). Büyük projeler için tam regresyon saatler sürebilir ve CI/CD hattını pratik olmaktan çıkarır.
İkinci strateji Seçici Regresyon’dur. Yalnızca değiştirilen kodla ilgili testler çalıştırılır. İlişkileri belirlemek için bir kod bağımlılık grafiği kullanılır. Araçlar: Bazel (Google), Nx (JavaScript), sbt (Scala). Seçici regresyon, çalışma süresinin %60–80’ini tasarruf ettirir ancak doğru bağımlılık grafiği oluşturulmasını gerektirir — hatalar gözden kaçan regresyonlara yol açar.
Üçüncü strateji Önceliklendirilmiş Regresyon’dur. Tüm testler önceliğe göre sıralanır: kritik yol (en önemli kullanıcı senaryoları), yüksek risk (hata geçmişi olan kod), değiştirilen kod (değişiklikten etkilenen kod). En yüksek öncelikli testler önce çalıştırılır — geçerlerse geliştirici hızlı geri bildirim alır. Zaman sınırlı çalıştırma: kritik testler 10 dakikada kontrol edilir, geri kalanı arka planda çalışır.
İlk ve en önemli adım, test yazma kültürüdür. Her değişikliğe, değişikliğin çalıştığını doğrulayan bir test ve hiçbir şeyin bozulmadığını doğrulayan bir test eşlik etmelidir. TDD (Test Odaklı Geliştirme) en iyi sonuçları verir: geliştirici önce başarısız olan bir test yazar, ardından onu geçiren kodu yazar. Bu, testin koddan önce var olmasını garanti eder.
İkinci adım, zorunlu test yürütmeli bir CI/CD hattıdır. Tüm testler geçene kadar bir pull request birleştirilemez. Aciliyet nedeniyle testler “atlanamaz” — acil değişiklikler hızlandırılmış ancak zorunlu bir test paketinden geçer. Google DevOps Research’e göre, zorunlu CI/CD’ye sahip ekiplerin üretimde 3 kat daha az regresyonu vardır.
Üçüncü adım, üretim izlemesidir. En iyi testler bile regresyonlara karşı %100 koruma garantisi vermez. Gözlemlenebilirlik araçları (Sentry, Datadog, New Relic) her dağıtımdan sonra temel metrikleri takip etmelidir: hata oranı, gecikme, iş hacmi. Eşikler aşıldığında otomatik geri alma, bir regresyon üretime ulaşırsa bir güvenlik ağıdır.
Dördüncü adım, regresyon zihniyetiyle kod incelemesidir. İncelemeci şunu sormalıdır: “Bu değişiklik hangi diğer modülleri bozabilir?”. Kodun doğru olduğunu kontrol etmek yeterli değildir — ilgili işlevselliği bozmayacağını kontrol etmek gerekir. Kod inceleme kontrol listesi, “ilgili modüllerde regresyon kontrolü” maddesini içermelidir.
Sıkça Sorulan Sorular
Regresyon, daha önce var olmayan bir hatadır. Sıradan bir hata, özelliğin oluşturulmasından beri var olmuş olabilir. Regresyon her zaman belirli bir değişikliğe bağlıdır — bu, nedeni bulmak için git bisect kullanılmasına olanak tanır.
git bisect kullanın: her şeyin çalıştığı commit’i ve bozulduğu commit’i belirtin. Git, geçmişte ikili arama yaparak regresyona neden olan commit’i bulur. Bu, binlerce commit’i olan büyük projelerde bile çalışır.
Kesin bir sayı yoktur, ancak ampirik bir kural vardır: temel kullanıcı akışlarının kapsamı %100, tüm işlevlerin kapsamı en az %70 olmalıdır. Nicelikten çok nitelik önemlidir: bir uç durumu kontrol eden bir test, mutlu yoldaki on testten daha değerlidir.
Evet, buna altyapı regresyonu denir. Bir işletim sistemi güncellemesi, veritabanı sürüm değişikliği, SSL sertifikası güncellemesi veya web sunucusu yapılandırma değişikliği, çalışan kodu bozabilir. IaC (Kod Olarak Altyapı) ve altyapı testi (Test Kitchen, Terratest) bu tür regresyonların yakalanmasına yardımcı olur.
Tek bir kritik kullanıcı akışıyla başlayın. En önemli senaryo için (giriş, ödeme) otomatik bir test yazın. Bir demoda testin bir regresyonu nasıl yakaladığını gösterin. Ekip faydayı gördüğünde, kapsamı kademeli olarak genişletin.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun