SOLID — Beş Harf, Tek Soru
Önce şunu oku: Temiz Kod — İsimler, Fonksiyonlar, Yorumlar
30 saniyede özet
SOLID beş ayrı kural gibi görünür ama hepsi aynı soruyu sorar: bu kod değişince başka kaç yere dokunmam gerekecek? Beşi de bu sayıyı küçültmenin farklı yollarıdır.
Evde bir lambayı değiştirmek için bütün evin elektriğini kesmek zorunda kaldığını düşün. Can sıkıcı, değil mi? Yazılımda da bazen tek bir şeyi değiştirmek, alakasız üç şeyi birden karartır.
Beş harfi bir anda ezberlemeyeceğiz. Harf harf gideceğiz, her harf küçük bir adım. Sonunda beşini yan yana koyunca hepsinin aynı soruyu sorduğunu göreceksin.
Adım adım oku
- Değişmesi gereken şey rapor formatı.
- Her şeyin tek bir sınıfta yaşadığı evde tek sigorta var: rapora dokunmak sipariş ve e-postayı da karartır.
- Her sorumluluğun kendi sınıfı olduğu evde yalnızca rapor odası kararır; öteki odalar yanmaya devam eder.
- SOLID'in beş harfi hep aynı soruyu sorar: bu değişim başka nereye dokunuyor?
-
Bayt: Rapor formatını değiştirdim, sipariş e-postaları bozuldu!
-
Sen: İkisinin ne alakası var?
-
Bayt: Aynı sınıfta yaşıyorlarsa alakaları var: aynı sigortaya bağlılar.
-
Bayt: Beşini birden ezberleme. Harf harf gidelim, her harfte küçük bir kazanç.
S — Single Responsibility
Küçük bir lokanta düşün: aşçı hem yemek yapıyor hem muhasebe tutuyor. Vergi kuralı değişince mutfak da durur.
class ReportService { String format(Sales s) { /* muhasebe ne isterse */ } void email(String body) { /* BT ne isterse */ }}class ReportFormatter { String format(Sales s) { /* ... */ } }class ReportMailer { void send(String body) { /* ... */ } }Kafam karıştı, daha basit anlat
Bir sınıfı kimin değiştirmek isteyeceğini düşün. Tek bir cevap geliyorsa iyi, iki farklı ekip geliyorsa ikiye böl.
SRP'deki "tek sorumluluk" ne demek?
O — Open/Closed
Çalışan bir dosyayı her yeni istekte yeniden açmak, her misafir geldiğinde duvar yıkmak gibidir. OCP, yeni şeyin yeni bir dosya olarak eklenebilmesini ister.
Yeni bir ödeme tipi (kripto) eklemek için kaç dosyaya dokunmak gerekiyor? Cevabı göster
Mevcut hâlde en az iki: PaymentProcessor (yeni else if) ve testleri. Dosya değiştiği için eski dalları da yeniden test etmek gerekir.
Yeni tip eklemek neye mal oluyor?
void process(Payment p) { if (p.type() == CARD) { cardGateway.charge(p); } else if (p.type() == TRANSFER) { bank.transfer(p); } else if (p.type() == WALLET) { wallet.debit(p); } else { throw new IllegalArgumentException(); }}Debug
bugün Üç ödeme tipi, üç dal. Bu hâliyle kod tamamen okunur ve sorun yok.
- tip sayısı
- = 3
- dokunulan dosya
- = 1
Sol/sağ ok tuşlarıyla da gezebilirsin.
Kafam karıştı, daha basit anlat
Çekmecesi olan bir dolap düşün. Yeni bir şey koymak için dolabı sökmezsin, yeni bir çekmece takarsın.
Her yeni ödeme tipi neye mal oluyor?
Tohum 487319Oynat ya da adımla: her adımda yeni bir ödeme tipi gelir.
Şu an ne oldu?
if-else zinciri (tek PaymentProcessor)
Bugün 3 ödeme tipi var; 5 yeni tip sırayla gelecek.
Görevler0/2
Çalışan bir dosyayı on kez yeniden açaçık
İpucu
Varsayılan ayarlar yeter.
Beş yeni tipi, çalışan hiçbir dosyaya dokunmadan ekleaçık
İpucu
Her tip kendi sınıfında.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. if-else zincirinde beş yeni tip, çalışan PaymentProcessor’ı ve testini her seferinde yeniden açtı.
- “PaymentHandler arayüzü” seç. Aynı beş tip yeni sınıflar olarak geldi; çalışan hiçbir dosyaya dokunulmadı.
Üç dallı bir `if/else` zincirini hemen Strategy'ye çevirmeli misin?
L — Liskov Substitution
Liskov ikamesiAlt tip, üst tipin kullanıldığı her yerde sorunsuz yerine geçebilmeli. Ölçüt "gerçek hayatta öyle mi" değil, "üst tipi kullanan kod alt tiple de doğru çalışır mı".Sözlükte gör → ilkesi şunu der: alt sınıf, üst sınıfın yerine geçtiğinde kimse fark etmemeli. Derleyici bunu göremez, çünkü bozulan şey imza değil, verilen sözdür.
class Rectangle { void setWidth(int w) { this.w = w; } void setHeight(int h) { this.h = h; } int area() { return w * h; }}
class Square extends Rectangle { void setWidth(int w) { this.w = w; this.h = w; } // sözü bozdu void setHeight(int h) { this.h = h; this.w = h; }}Rectangle kullanan kod “genişliği değiştirirsem yükseklik sabit kalır” diye bir söz almıştı. Square bu sözü tutmuyor.
Bankada da aynısı olur: vadeli hesap da bir hesaptır ama vadesi dolmadan para çekilemez. Onu “çekilebilir” gibi göstermek, üst tipin sözleşmeBir metodun çağırana verdiği söz: neyi kabul eder, ne döndürür, hangi hataları atar. İmzada görünmeyen kısmı da sözleşmenin parçasıdır.Liskov ihlalleri neredeyse her zaman imzayı değil sözleşmeyi bozar — bu yüzden derleyici onları yakalayamaz.Sözlükte gör →sini daraltır.
Derinleş · Vadesiz ve vadeli hesap: sözü daraltmadan 4 dosya · ~82 satır · ilk okumada atlayabilirsin
Kafam karıştı, daha basit anlat
“Ben de bir hesabım” diyen her şey, hesaptan beklenen her işi yapabilmeli. Yapamıyorsa hesap gibi davranmasın, kendi adıyla dursun.
Bir alt sınıf üst sınıfın kabul ettiği bir girdiyi reddedip istisna atıyor. Bu hangi ilkeyi bozar?
I — Interface Segregation
Altmış tuşlu bir televizyon kumandası düşün; sen yalnızca sesi açmak istiyorsun. Asansör paneli ise sana sadece katları gösterir.
Interface Segregation, her kullanıcıya yalnızca işine yarayan tuşları vermeyi ister.
interface ReportStore { Report find(ReportId id); List<Report> findAll(); void save(Report report); // read-only clients never call this void delete(ReportId id); void purgeOlderThan(Duration age); // only the nightly cleanup job does}interface ReportReader { Report find(ReportId id); List<Report> findAll(); }interface ReportWriter { void save(Report report); void delete(ReportId id); }interface ReportMaintenance { void purgeOlderThan(Duration age); }Aynı sınıf üçünü birden uygulayabilir. Ama ekrandaki rapor listesi yalnızca ReportReader görür ve yanlışlıkla bir şey silemez.
Kafam karıştı, daha basit anlat
Bir sınıf, bir arayüzün yarısını “bu bana lazım değil” diye boş bırakıyorsa, o arayüz fazla büyüktür.
Bu arayüzü uygulayan `ReadOnlyReportStore` sınıfı her metotta exception fırlatmak zorunda kalıyor. Hangi satırlar ISP'yi ihlal eden şişkinliğin kaynağı?
D — Dependency Inversion
Duvara bir priz takılı: lambayı değiştirirken duvarı kırmazsın, çünkü ikisi aynı fişe uyar. Dependency Inversion da iş kurallarını veritabanına değil, kendi tanımladığı bir fişe bağlar.
Kötü: OrderService ──► PostgresOrderRepository (iş kuralı, altyapıya bağlı)
İyi: OrderService ──► OrderRepository ◄── PostgresOrderRepository (arayüz iş katmanında tanımlı)Kritik nokta arayüzün nerede tanımlandığı. Arayüz altyapı paketinde duruyorsa ok yönü değişmemiştir, araya yalnızca bir dosya girmiştir.
Kafam karıştı, daha basit anlat
Fişin şeklini prizi kullanan belirler. Duvardaki kablolar değişse de lamba aynı kalır.
Her durumu, hangi SOLID maddesinin işaret ettiğine göre ayır.
Hepsi bir arada
Beş harfi tek tek geçtin. Şimdi yan yana koyalım:
| Harf | Kısaca | Asıl sorusu |
|---|---|---|
| S — Single Responsibility | Tek değişim sebebi | Bu sınıf kimin isteğiyle değişiyor? |
| O — Open/Closed | Eklemeye açık | Yeni durum eski kodu açtırıyor mu? |
| L — Liskov Substitution | Sözü daraltma | Alt sınıf verilen sözü tutuyor mu? |
| I — Interface Segregation | Küçük arayüzler | Kullanıcı boş tuş taşıyor mu? |
| D — Dependency Inversion | Ok yönü | Arayüz kimin paketinde? |
Hepsi aynı soruyu soruyor: bu değiştiğinde başka nelere dokunmam gerekecek?
Üç küçük uyarı:
- SOLID bir teşhis aracıdır, hedef değil. Cevap “az yere” ise harfleri saymana gerek yok.
- Her ilkenin bir bedeli var. OCP dosya, ISP arayüz, DIP dolaylılıkBir şeye doğrudan değil, araya giren bir katman üzerinden ulaşmak. Esneklik verir, okurken bir adım daha attırır — bedava değildir.Sözlükte gör → ekler.
- Arayüz sayısı başarı değildir. Tek uygulaması olan arayüzü, ikinci uygulama gelince çıkarmak kolaydır.
Tek sorumluluk ilkesi, bir sınıfın yalnızca tek bir metodu olması demektir.
SOLID'in beş maddesinin ortak amacı nedir?
Aklında kalacak üç şey
- 1 SOLID'in beş harfi tek bir soruyu farklı açılardan sorar: bu değişince başka nelere dokunmam gerekecek?
- 2 'Tek sorumluluk' tek iş yapmak değil, değişmek için tek bir sebebe sahip olmaktır. Kimin isteğiyle değişiyorsa sorumlusu odur.
- 3 Alt sınıf, üst sınıfın sözünü daraltıyorsa (daha az girdi kabul ediyor ya da daha zayıf söz veriyorsa) kalıtım yanlıştır.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.