🗄️ B3 · Repository Katmanı: in-memory Map

B3 · Repository Katmanı: in-memory Map: Repository katmanı, verinin **arşiv memuru**dur: "bu bug'ı sakla", "42 numaralıyı getir", "sil" gibi ham depolama işlerini yapar — ama HİÇ

Repository katmanı, verinin **arşiv memuru**dur: "bu bug'ı sakla", "42 numaralıyı getir", "sil" gibi ham depolama işlerini yapar — ama HİÇBİR iş kuralı bilmez ("bu kullanıcı silebilir mi?" onun sorusu değildir). Bu sayfada gerçek veritabanı yerine bellek-içi bir `Map ` kullanacağız; amaç depolama teknolojisini öğrenmek değil, **katmanların sorumluluk ayrımını** görmektir. Peki neden depolamayı ayrı bir katmana koyuyoruz, controller doğrudan Map'e yazsa olmaz mı? Çünkü depolama bir gün Map'ten gerçek bir veritabanına dönerse, sadece bu katman değişmeli, üstteki iş mantığı ve controller aynı kalmalı — tek sorumluluk ilkesi. Java'da bunun karşılığı bir `interface BugRepository` ve onun implementasyonudur; çağıran sadece `save`/`findById` imzasını bilir, arkasının Map mi JPA mı olduğunu bilmez. QA açısından repository, **test izolasyonunun** anahtarıdır: bellek-içi bir repository her test öncesi sıfırlanabilir, böylece testler birbirinin verisini kirletmez — "önceki testten kalan kayıt yüzünden düşen test" kâbusu buradan çözülür.

Bellek-İçi Repository

**🐞 Defect Doğum Anı — `findById` `null` yerine boş `Optional` dönmezse** **Kod:** `public Bug findById(Long id) { return store.get(id); }` — kayıt yoksa doğrudan `null` döner (Optional yok). **Ne olur:** Servis katmanı `repository.findById(999).getSeverity()` çağırdığında, olmayan kayıt `null` döner ve `.getSeverity()` bir **NullPointerException** fırlatır. Sonuç: `GET /api/v1/bugs/999` request'i 404 yerine **500 Internal Server Error** döner. **Neden sinsi:** "Kayıt bulunamadı" aslında normal, beklenen bir durumdur (404) — ama `null` döndürmek onu bir sunucu çökmesine (500) çevirir. Belirtiye bakan tester "sunucu bug'ı" der, oysa kök neden eksik bir null-güvenliğidir. **Tester nerede yakalar:** Olmayan bir id ile `GET /api/v1/bugs/999` gönderip 404 beklerken 500 alınca. `Optional` döndürmek, üst katmanı "yoksa 404 dön" demeye zorlar ve çökmeyi engeller.

🎬 404 mü 500 mü? Boş Optional ile null Farkı

Bir request olmayan bir kaydı istiyor: GET /api/v1/bugs/999. Repository ne dönerse sonuç ona bağlı.

Yol A — Repository null döner. Üst katman `.getSeverity()` çağırınca NullPointerException patlar → 500 Internal Server Error.

Yol B — Repository boş Optional döner. "Kayıt yok" artık bir çökme değil, ele alınabilir bir durumdur.

Boş Optional üst katmanı "yoksa 404 dön" demeye zorlar. İstemci doğru, beklenen response'u alır: 404 Not Found.

Ders — "Bulunamadı" normal bir durumdur (404), çökme değil (500). Optional bu farkı yapıya gömer. Tester olmayan id ile 404 bekleyerek doğrular.

Katman Ayrımı Neden Test İzolasyonu Getirir?

Repository sadece depolar…

Bellek-içi Map, iş kuralı içermez; save/find/delete'ten ibarettir. Bu yalınlık onu test için ideal yapar.

Her test öncesi sıfırla…

Map'i temizlemek (store.clear()) tüm veriyi siler; her test taze bir durumla başlar.