Hata Replikasyonu (Bug Reproduction)
Bir bug'ı sistemli şekilde replicate eden ve minimal reproducible example çıkaran skill — triage, izolasyon, binary search ile kök neden, regression test. "Benimkinde çalışıyor" diyenlere karşı disiplin.
İçerik
Hata Replikasyonu (Bug Reproduction)
Bug'ı "çözmek"ten önce stabil şekilde tetiklemeyi öğreten skill. Bir bug repro edilemiyorsa düzeltildiği de doğrulanamaz.
Ne zaman aktif olur
- Issue / bug report triage edilirken
- Kullanıcıdan "X yaptım, Y oldu" raporu gelince
- Intermittent / flaky hata kovalanırken
- Regression testi için minimal case çıkarılırken
Çekirdek prensipler
1. Önce repro, sonra düzelt
Repro yoksa:
- Düzelttiğini nereden bileceksin?
- Regression testi nasıl yazacaksın?
- "Benimkinde çalışıyor" nasıl çürüteceksin?
Repro olmayan bug = hipotez. Onu fix etmek = tahmin.
2. Minimal reproducible example (MRE)
Bug'ı tetikleyen en küçük hal. Gereksiz her parça çıkarılır — konfig, veri, adım.
İyi MRE:
- 30 saniyede anlaşılır
- Dış bağımlılık minimum
- Başka biri makinesinde çalıştırabilir
- Bug'ın göründüğü sürümle görünmediği sürüm test edilebilir
3. "Bende çalışıyor" bir yanıt değildir
Bug raporunda detay eksiksem, senden eksik olan. Kullanıcıya sormadan "reproduce olmuyor" yazma.
Workflow
Adım 1: Bug'ı anla (triage)
Rapor genelde eksik. Şunları sor:
Ortam:
- OS + version
- Browser / runtime + version
- App version / git sha
- Env: prod / staging / local
Zaman:
- İlk ne zaman gördün?
- Her seferinde mi, ara ara mı? (frequency)
- Son kez ne zaman çalışıyordu?
Veri:
- Hangi user ID / account
- Hangi record ID
- Ekran görüntüsü / video
Adımlar:
- Tam adım adım ne yaptı
- Ne bekledi, ne gördü
Eksik bilgi varsa tahmin üretmek yerine sor.
Adım 2: Lokalde repro dene
- Kullanıcının sürümü ile aynı sürüme checkout
- Kullanıcının env konfigürasyonu mümkünse (env vars, feature flags)
- Kullanıcının adımlarını birebir uygula
- Repro oldu mu / olmadı mı?
Adım 3: Repro olmadıysa
- Env farkı? OS, browser, yerel zaman dilimi, dil
- Veri farkı? DB state, feature flag, A/B bucket
- Timing farkı? Slow network, race condition
- Kullanıcının account durumu? Role, plan, geçmişi
Her birini hipotez olarak test et.
Adım 4: Minimal'e indir (binary search)
Repro elindeyken gereksiz parçaları söküp atarsın. Binary search:
Karmaşık repro: X adım
→ yarısını çıkar → hala repro oluyor mu?
→ evet → gereksiz yarı; hayır → kritik yarı
→ her döngüde yarıya böl
Örnek:
- 10 kayıt oluşturuyorum → 1 kayıt ile de oluyor mu?
- 3 endpoint çağırıyorum → 1'i ile?
- 50 satırlık input → 5 satır?
Adım 5: Kök neden (root cause)
Minimal repro'da:
- Logları aç (DEBUG level)
- Breakpoint /
console.logstratejik noktalarda - Git bisect ne zaman kırıldı belirsizse:
git bisect start git bisect bad HEAD git bisect good <known-good-sha> # her iterasyonda: test et, good/bad de - Stack trace — satır satır oku, atma
- Varsayımı yaz — "Sanırım X olduğu için Y oluyor" — kanıtla veya çürüt
Adım 6: Fix yazmadan regression testi
Tersini yap:
- Önce bug'ı yakalayan bir test yaz (kırmızı)
- Fix'i yap
- Test yeşile dönsün
Bu sırada fix'in yanlışlıkla başka şeyi bozmadığını garanti etmiş olursun.
Adım 7: Fix
- Kök nedene inen fix. Semptom bandajı değil.
- Aynı pattern başka yerde var mı? (audit)
- Fix'in performans / güvenlik yan etkisi var mı?
Adım 8: Doğrulama
- Minimal repro → artık repro olmuyor
- Yeni regression testi yeşil
- Mevcut testler yeşil
- Manual smoke test
- Prod'da metric izle (error rate düştü mü?)
MRE formatı (başkalarına paylaşırken)
## Ortam
- App: v2.4.1 (git sha abc123)
- OS: macOS 14.2
- Node: 20.9
- Browser: Chrome 121
## Adımlar
1. `pnpm install && pnpm dev`
2. Browser: localhost:3000/settings aç
3. Input: "Test Name", Save bas
4. **Beklenen:** Profile güncellenir, 200 response
5. **Görülen:** 500 Internal Server Error, console'da: `TypeError: Cannot read property 'id' of undefined`
## Stack
[error stack]
## Veri
Test user: `test@example.com` (seed'li)
## Notlar
- Test user yerine yeni kullanıcı açtığımda olmuyor → seed'li user'a bağımlı
- Son çalıştığı sürüm: v2.4.0
Flaky / intermittent bug'lar
"Ara ara oluyor" en zor kategori.
Stratejiler
1. Loop'la:
for i in {1..1000}; do
pnpm test foo || { echo "fail at $i"; break; }
done
2. Stress:
- Concurrent request'ler
- High CPU load ("stress --cpu 4")
- Slow network (Chrome DevTools throttle)
- Küçük / tam disk
- Dil / timezone değişimi
3. Determinism kontrol:
- Clock mock edildi mi? (
Date.now()çıktı mı) - UUID / random seed'li mi?
- Test order bağımsız mı? (
--randomrunner flag)
4. Audit logs:
- Structured log ekle
- Hangi branch'e girdiğini, hangi değerlerle, hangi timing'de
Heisenbug
İzlemeye başladığında kaybolan bug. Sebep:
- Debug logging timing'i değiştiriyor
- Debugger CPU yavaşlatıyor, race geçiyor
console.logside-effect yaratıyor
Çözüm: non-invasive observability (prometheus metric, structured log'u prod'daki gibi bıraktığın)
Kullanıcı ile iletişim
Bug report isterken
Merhaba,
Hatayı yeniden üretebilmem için şunları paylaşır mısın:
1. Tarayıcı + sürümü (Chrome/Safari/... 100.x)
2. Tam adım adım ne yaptın:
- Hangi sayfaya gittin
- Ne tıkladın / yazdın
- Ne bekliyordun, ne gördün
3. Ekran görüntüsü veya video (1 dakikalık yeter)
4. Console'da hata var mı (F12 → Console)
5. Hatayı hangi tarih/saatte gördün (prod log'larını arayayım)
6. Hesap bilgin (user id / email) — gizli tutarım
Repro sağlanamadığında
Merhaba,
Hatayı senin anlattığın gibi tetikleyemedim. Birkaç olasılık:
1. Cache temizleyip tekrar dene (Cmd+Shift+R / Ctrl+Shift+R)
2. Farklı bir browser'da dene
3. Incognito / özel pencerede dene
Eğer hala oluyor: DevTools → Network tab'i açık iken tekrar dene,
hatanın olduğu request'in "Copy as cURL" çıktısını paylaşır mısın?
Somut örnek
Bug raporu
"Profil sayfası bazen 500 veriyor."
Triage (iyi)
- "Bazen" ne sıklıkta? Kullanıcıya sor.
- Hangi endpoint? Server log'a
user.idile ara. - Belirli user'da mı? Patterns?
Hipotez
Server log → sadece role=admin olan user'lar 500 alıyor.
Minimal repro
# Production env'de (staging mirror ile)
curl -H "Authorization: Bearer $ADMIN_TOKEN" \
http://staging.../api/user/profile
# → 500
Root cause
Profile endpoint user.company.name bekliyor. Admin user'ların company_id = NULL. Join NULL → Error.
Fix + test
// Önce test
test("company_id olmayan admin user profile çekebilir", async () => {
const admin = await userFactory({ role: "admin", companyId: null });
const resp = await get(`/api/user/profile`, admin);
expect(resp.status).toBe(200);
expect(resp.body.company).toBeNull();
});
// → kırmızı
// Fix
const profile = {
...user,
company: user.company ?? null,
};
// → yeşil
Anti-pattern'ler
- ❌ Repro etmeden "çözüm" commit'lemek
- ❌ "Bende çalışıyor" ile kapatmak
- ❌ Regression testi yazmamak (aynı bug döner)
- ❌ Semptomu bandajlamak (try/catch ile hatayı gizlemek)
- ❌ Kullanıcıdan bilgi istemeden tahmin düzeltmek
- ❌ Flaky testi
skipetmek, kök nedenini atlamamak - ❌ Binary search yerine tam kod sökerek saatlerce kaybolmak
- ❌ Fix sonrası prod metric'i izlememek (gerçekten çözüldü mü?)
Checklist — bug fix PR'ı öncesi
- Minimal reproducible example yazıldı
- Root cause belgelendi (sadece semptom değil)
- Regression test eklendi ve önce kırmızıydı
- Aynı pattern başka yerde var mı audit edildi
- Fix'in yan etkisi / performans/güvenlik düşünüldü
- PR description'da MRE var
- Prod metric / log izleme planı hazır