Furkan KapukayaYazılım geliştirme
Yazılım Mimarisi ve Temiz Kod3 dk okuma

SOLID Prensipleri: Örneklerle Anlaşılır Rehber

Nesne yönelimli tasarımın beş temel ilkesi SOLID: tek sorumluluk, açık-kapalı, Liskov, arayüz ayrımı ve bağımlılıkların tersine çevrilmesi; C# örnekleri ve aşırıya kaçmadan uygulama.

SOLID, nesne yönelimli yazılım tasarımının beş temel ilkesinin baş harflerinden oluşur. Yirmi yılı aşkın süredir mülakatların, kod incelemelerinin ve mimari tartışmaların ortak dilidir. Amacı tek bir cümleyle özetlenebilir: değişikliğe kolay uyum sağlayan kod.

S: Tek Sorumluluk (Single Responsibility)

Bir sınıfın değişmek için yalnızca bir nedeni olmalıdır. Hem fatura hesaplayan, hem PDF üreten, hem de e-posta gönderen bir sınıf; üç farklı nedenle değişir.

public class FaturaHesaplayici { /* tutar ve vergi */ }
public class FaturaPdfUretici  { /* belge */ }
public class FaturaGonderici   { /* e-posta */ }

O: Açık-Kapalı (Open/Closed)

Kod, genişlemeye açık ama değişikliğe kapalı olmalıdır. Yeni bir kargo firması eklemek için mevcut ve çalışan kodu değil, yeni bir sınıf eklemek yeterli olmalıdır.

public interface IKargoFirmasi { decimal UcretHesapla(Paket paket); }
public class ArasKargo : IKargoFirmasi { /* ... */ }
public class YeniKargo : IKargoFirmasi { /* yalnızca eklenir */ }

L: Liskov'un Yerine Geçme İlkesi

Bir alt sınıf, üst sınıfın kullanıldığı her yerde sorunsuz çalışmalıdır. Üst sınıfın sözünü bozan, örneğin "Kaydet" çağrıldığında hata fırlatan bir alt sınıf bu ilkeyi ihlal eder. Klasik örnek: matematiksel olarak her kare bir dikdörtgendir, ama genişliği ve yüksekliği bağımsız değiştirilebilen bir Dikdortgen sınıfından Kare türetmek beklenmedik davranışlara yol açar.

I: Arayüz Ayrımı (Interface Segregation)

İstemciler kullanmadıkları metotlara bağımlı olmamalıdır. Yirmi metotlu dev bir arayüz yerine, amaca özel küçük arayüzler tercih edilir: IOkunabilir, IYazilabilir gibi.

D: Bağımlılıkların Tersine Çevrilmesi (Dependency Inversion)

Üst seviye iş mantığı, alt seviye ayrıntılara (veritabanı, SMTP, dosya sistemi) değil soyutlamalara bağlı olmalıdır.

public class SiparisServisi(ISiparisDeposu depo, IBildirimGonderici bildirim)
{
    public async Task OnaylaAsync(int id)
    {
        var siparis = await depo.GetirAsync(id);
        siparis.Onayla();
        await depo.KaydetAsync(siparis);
        await bildirim.GonderAsync(siparis.MusteriId, "Siparişiniz onaylandı.");
    }
}

Bu yapı sayesinde testte gerçek veritabanı yerine sahte bir depo kullanılabilir. .NET'te bu bağımlılıkların nasıl yönetildiği dependency injection yazısında anlatılıyor.

Aşırıya kaçmamak

SOLID bir araçtır, amaç değil. Her sınıf için bir arayüz yazmak, iki satırlık işleri beş dosyaya bölmek okunabilirliği düşürür. Küçük ve değişmeyecek kodda ilkeleri gevşek uygulamak, KISS ve YAGNI ile uyumludur. İlkeleri en çok, sık değişen ve birden fazla kişinin dokunduğu kodda uygulayın.

Sık sorulan sorular

SOLID sadece nesne yönelimli dillerde mi geçerli?

İsimleri nesne yönelimli dünyadan gelir; ancak tek sorumluluk ve bağımlılıkları soyutlama gibi fikirler fonksiyonel programlamada da karşılık bulur.

Mevcut bir projeye SOLID nasıl uygulanır?

Tümünü baştan yazarak değil; değiştirdiğiniz kodu adım adım iyileştirerek. Bkz. refactoring.

Sonuç

SOLID, kodu değişime hazırlamanın beş pratik yoludur. Bu ilkeleri ölçülü uygulamak, yeni özelliklerin eski özellikleri bozmadan eklenebildiği bir kod tabanı sağlar.