1. SOLID Nedir? Tarihçesi ve Modern Önemi
SOLID, yazılım mühendisliğinde temiz, ölçeklenebilir ve bakım dostu kod yazmak için oluşturulmuş 5 temel OOP prensibinin baş harflerinden oluşur.
Bu prensipler ilk kez 1980’lerde Robert C. Martin (“Uncle Bob”) tarafından ortaya atıldı, yıllar içinde sektörde adeta “kodun anayasası” haline geldi.
Bugün, küçük bir startup projesinden milyar dolarlık kurumsal yazılıma kadar, herkes SOLID prensiplerini uygulamanın önemini vurguluyor.
Çünkü yazılım değişim ister; kodun değişime ne kadar kolay adapte olursa, uzun vadede o kadar az “tekrar baştan yaz” ihtiyacı duyarsın.

SOLID, 5 temel nesne yönelimli programlama prensibinin baş harflerinden oluşur:
- Single Responsibility Principle (SRP) – Tek Sorumluluk
- Open/Closed Principle (OCP) – Açık/Kapalı
- Liskov Substitution Principle (LSP) – Yerine Geçme
- Interface Segregation Principle (ISP) – Arayüz Ayrımı
- Dependency Inversion Principle (DIP) – Bağımlılıkların Tersine Çevrilmesi
2. Single Responsibility Principle (SRP) – Tek Sorumluluk Prensibi
Teorik Temel
Bir sınıfın/değerin yalnızca bir işi/sorumluluğu olmalı. Aksi halde kod büyüdükçe, bir değişiklik başka bir yerde istenmeyen etki doğurur.
Gerçek Projeden Hikaye:
Bir e-ticaret sitesinde, “OrderManager” sınıfı başta çok küçük; sipariş kaydediyor. Ama yeni ihtiyaçlar geldikçe şu fonksiyonlar ekleniyor:
- E-posta gönder
- Fatura oluştur
- Raporlama
- Bildirim
Bir süre sonra kim hangi işi yapıyor, kimse anlamaz hale geliyor!
Kötü Kod (SRP’ye aykırı):
class OrderManager {
public void SaveOrder(Order order) { /* ... */ }
public void SendEmail(Order order) { /* ... */ }
public void GenerateInvoice(Order order) { /* ... */ }
public void Log(string message) { /* ... */ }
}
Bir müşteri “fatura formatını değiştir” dediğinde, kodun her yeri karışır.
Doğru Yaklaşım (SRP’ye uygun):
class OrderSaver { public void Save(Order order) { /* ... */ } }
class EmailSender { public void Send(Order order) { /* ... */ } }
class InvoiceGenerator { public void Generate(Order order) { /* ... */ } }
class OrderLogger { public void Log(string message) { /* ... */ } }
SRP’nin Sağladığı 5 Pratik Avantaj
- Değişiklik izole olur, domino etkisi yaratmaz.
- Test etmek kolaylaşır.
- Ekipte her sorumluluk için ayrı bir uzman bulunabilir.
- “Benim işim ne?” sorusu çok net olur.
- Her sınıf küçük ve okunur kalır.
Kritik İpucu:
Her yeni fonksiyon yazarken “bu sınıfın sorumluluğu mu?” diye kendine sor!
3. Open/Closed Principle (OCP) – Açık/Kapalı Prensibi
Temel Fikir
Kod geliştirmeye açık, değişikliğe kapalı olmalı. Yeni iş eklerken mevcut kodu bozmak zorunda değilsin!
Gerçek Projede Sık Düşülen Hata
Ödeme altyapısında her yeni ödeme yöntemi için “if-else” ya da “switch-case” büyür:
class PaymentProcessor {
public void Pay(string method) {
if (method == "Kredi Kartı") { /* ... */ }
else if (method == "PayPal") { /* ... */ }
else if (method == "Bitcoin") { /* ... */ }
}
}
Her yeni ödeme tipinde kodun her yeri değişir, testler patlar.
OCP’ye Uygun Çözüm
interface IPaymentMethod { void Pay(); }
class CreditCard : IPaymentMethod { public void Pay() { /* ... */ } }
class PayPal : IPaymentMethod { public void Pay() { /* ... */ } }
class PaymentProcessor {
public void Process(IPaymentMethod paymentMethod) {
paymentMethod.Pay();
}
}
Yeni ödeme için sadece yeni bir sınıf ekle, kodun geri kalanı değişmez.
OCP Uygulamasının 3 Büyük Faydası
- Kodun gelecekteki işlere karşı dayanıklı olur.
- Birden fazla geliştirici paralel iş yapabilir.
- Canlıda “feature eklerken bug çıkma” ihtimali düşer.
Dikkat: Kodu “değişikliğe kapalı” hale getirmek için, interface ve abstract class kullanımını öğrenmek şart!
4. Liskov Substitution Principle (LSP) – Yerine Geçme Prensibi
Temel Anlam
Bir temel sınıf/interface yerine geçen alt sınıf, tüm beklentileri sağlamalı. Aksi halde alt sınıf, kodun başka bir yerinde bug üretir!
Yaşanmış Bir Kriz
Bankacılık projesinde, Account sınıfının bir alt sınıfı olan ReadOnlyAccount vardı. Tüm Account nesneleri Withdraw() fonksiyonuna sahipti, fakat ReadOnlyAccount’ta bu fonksiyon exception fırlatıyordu.
Sonuç?
Müşterilerin hesapları bir anda kitlendi!
LSP’ye Uygun Refactoring
interface IAccount { decimal GetBalance(); }
interface IWithdrawable { void Withdraw(decimal amount); }
class NormalAccount : IAccount, IWithdrawable { /* ... */ }
class ReadOnlyAccount : IAccount { /* ... */ }
ReadOnlyAccount sadece bakiye gösterir, para çekmez.
LSP’nin Sağladığı 4 Pratik Sonuç
- Kodun her yerinde alt sınıflar güvenle kullanılabilir.
- Exception fırlatan override’lar azalır.
- Takım içinde kodun anlaşılması kolaylaşır.
- Olası bug’lar ve canlı sorunlar önlenir.
Altın Kural:
Kodda “bu alt sınıfı burada kullanma” diyorsan, LSP ihlalidir!
5. Interface Segregation Principle (ISP) – Arayüz Ayrımı Prensibi
Temel Amaç
Büyük, her işi kapsayan arayüzler yerine küçük ve spesifik arayüzler kullan!
Sık Yapılan Hata
interface IWorker { void Work(); void Eat(); }
class Robot : IWorker { public void Work() { } public void Eat() { throw new Exception(); } }
Robot yemek yemez, ama interface yüzünden Eat() fonksiyonu yazmak zorunda!
Gerçek Projede Refactoring
Bir SaaS platformunda, ana interface’de gereksiz fonksiyonlar vardı. Tüm modüller ya boş bıraktı ya da “NotImplementedException” fırlattı. Refactor sonrası, her işlev için ayrı arayüz ve daha okunabilir kod!
Doğru Yaklaşım
interface IWorkable { void Work(); }
interface IFeedable { void Eat(); }
class Robot : IWorkable { public void Work() { } }
class Human : IWorkable, IFeedable { public void Work() { } public void Eat() { } }
ISP’nin Sağladığı Faydalar
- Kodda gereksiz metod kalabalığı olmaz.
- Her modül sadece işine yarayan interface’i implement eder.
- Kod okunabilirliği ve bakımı kolaylaşır.
Küçük Bir İpucu:
Bir interface’in tüm implementasyonları aynı fonksiyonu “boş bırakıyor” veya “throw” ediyorsa, kesin ISP ihlali vardır!
6. Dependency Inversion Principle (DIP) – Bağımlılıkların Tersine Çevrilmesi Prensibi
Temel Kural
Üst seviye (iş mantığı) ve alt seviye (detaylar) sınıflar, birbirine doğrudan bağlı olmamalı. Bağımlılığı interface/abstract class ile çöz!
Klasik Hata
class ReportGenerator {
private ExcelExporter exporter = new ExcelExporter();
public void Generate() { exporter.Export(); }
}
PDF çıktısı istendiğinde baştan sona kod değişiyor.
DIP’ye Uygun Yaklaşım
interface IExporter { void Export(); }
class ExcelExporter : IExporter { public void Export() { /* ... */ } }
class PdfExporter : IExporter { public void Export() { /* ... */ } }
class ReportGenerator {
private IExporter exporter;
public ReportGenerator(IExporter exporter) { this.exporter = exporter; }
public void Generate() { exporter.Export(); }
}
Modern Projede DIP Nasıl Otomatikleşir?
ASP.NET Core, Spring Boot gibi frameworklerde DI Container ile dependency injection yapılır. Unit testlerde mock nesnesi kolayca inject edebilirsin.
DIP’nin Faydaları
- Kod değişikliğe dayanıklı olur.
- Birim test kolaylaşır.
- Farklı ortamlarda farklı implementasyonlar rahatça kullanılır.
Ekstra Not: “new” anahtar kelimesi geçen her yeri, önce interface ile çözmeyi dene!
7. Gerçek Projede SOLID: Yaşanmış Bir Refactoring Hikayesi
Başlangıç Sorunu
E-posta, SMS, push notification gibi bildirimlerin hepsi tek bir NotificationManager’da toplandı. Kod sürekli değişiyor, bir yeni özellik geldiğinde herkes baştan aşağı kodu gözden geçiriyor.
Refactoring Adımları
- Her bildirim tipi için IMessageSender interface’i yazıldı.
- NotificationManager sadece bu interface’ten nesne aldı.
- Loglama, istatistik ve retry işlemleri ayrı sınıflara bölündü.
- Kod test edilir ve genişletilir hale geldi.
Sonuç
Kodun bakımı ve testleri %50 hızlandı, canlıda bug sayısı azaldı. Takım içinde “kodu bozan değil, kodu genişleten” olmak motive etti!
8. SOLID’in Sık Yapılan Hataları
- Devasa sınıflar: Tek sorumluluğu olmayan, SRP’yi ihlal eden kütüphaneler.
- If-else/switch-case canavarı: OCP’yi unutturup “her şey bir yerde değişir” tuzağı.
- Exception fırlatan override’lar: LSP’ye aykırı, alt sınıfın üst sınıf davranışını bozan örnekler.
- Gereksiz interface şişkinliği: ISP ihlalinde kodda bir sürü boş/atıl fonksiyon.
- Direkt new’leme: DIP olmadan, bağımlılıkları hardcoded çözmek.
9. Takımda SOLID Kültürü Nasıl Oturur?
- Her kod review’da “hangi SOLID ihlal edildi?” diye sor.
- Yeni başlayanlara, önce örnek kodda refactoring göster.
- Her yeni feature’da “SOLID’e uygun mu?” checklist’i uygula.
- Küçük refactoring’ler ile başlamaktan çekinme; “her şey bir anda değişmez”!
10. SSS – En Çok Sorulan Sorular
SOLID’in hepsi her projede kullanılmalı mı?
Küçük projede çok aşırıya kaçmak gerekmez; ama kod büyüyecekse, baştan SOLID temeli atmak avantaj sağlar.
Refactoring için en doğru zaman ne?
Kodda “her değişiklikte başka bir şey bozuluyor” diyorsan, refactoring zamanı gelmiştir!
SOLID’i tam uygulayınca performans sorunu olur mu?
Doğru uygulandığında uzun vadede hem bug hem bakım yükünü azaltır; modern dillerde performans problemi yaratmaz.
11. Sonuç ve Kapanış
Kodun bugünden yarına taşınmasını istiyorsan, SOLID prensipleri en güvenli limandır.
- Sadece bugünkü ihtiyacı değil, yarının değişikliklerini de düşünerek kod yaz.
- Refactoring’i korkulacak bir şey değil, kodun sağlıklı kalması için bir fırsat olarak gör.
- Takımda kod kalitesini artırmak için pratik örnekler, code review’lar ve checklist’ler kullan.
Bugün okuduğun bu rehberi,
- Kendi projene adapte edebilir,
- Takım arkadaşlarına önerebilir,
- Kodda her sorun çıktığında tekrar başvurulacak bir başucu kaynağı yapabilirsin.
Kodunu geleceğe sağlam bırak!