Giriş
Yazılım dünyasında, karmaşıklık arttıkça kodun okunabilirliği, sürdürülebilirliği ve test edilebilirliği giderek daha fazla önem kazanır. Bu zorlukların üstesinden gelmek için geliştiriciler, bir dizi ilke ve prensip benimsemişlerdir. Bu prensipler arasında, özellikle nesne yönelimli programlamada (OOP) öne çıkan SOLID prensipleri, yazılım kalitesini artırmanın temel taşlarından biridir. SOLID, her biri yazılım tasarımında belirli bir soruna çözüm getiren beş prensibin baş harflerinden oluşur: Tek Sorumluluk (Single Responsibility), Açık-Kapalı (Open-Closed), Liskov İkamesi (Liskov Substitution), Arayüz Ayrımı (Interface Segregation) ve Bağımlılık Tersine Çevrilmesi (Dependency Inversion). Bu makalede, SOLID prensiplerini detaylı bir şekilde inceleyecek, temiz kod yazma teknikleri ve kod kalitesini artıran iyi uygulamalar ile ilişkilendirecek ve bu prensiplerin gerçek hayatta nasıl uygulanabileceğini bir kullanıcı yönetim sistemi örneği üzerinden göstereceğiz.
Tek Sorumluluk Prensibi (Single Responsibility Principle – SRP)
Tek Sorumluluk Prensibi, bir sınıfın (veya modülün) yalnızca tek bir sorumluluğu olması gerektiğini belirtir. Başka bir deyişle, bir sınıfı değiştirmek için yalnızca tek bir neden olmalıdır. Bu prensip, sınıfların daha odaklı, daha az karmaşık ve daha kolay anlaşılır olmasını sağlar. Bir sınıfın birden fazla sorumluluğu olduğunda, bu sorumluluklar birbirine bağımlı hale gelebilir ve birindeki değişiklik diğerini beklenmedik şekilde etkileyebilir. Örneğin; bir kullanıcı yönetim sisteminde, kullanıcı bilgilerini veritabanına kaydetmek ve kullanıcıya e-posta göndermek gibi iki farklı sorumluluğu olan bir sınıf, SRP’ye aykırıdır. Bu sınıf, ‘KullaniciKayit’ ve ‘EpostaGonderici’ gibi iki ayrı sınıfa bölünmelidir.
Sorumlulukları ayırmak, kodun yeniden kullanılabilirliğini ve test edilebilirliğini de artırır. Her sınıfın tek ve belirli bir görevi olduğunda, o sınıfı farklı bağlamlarda tekrar kullanmak veya o sınıf için birim testler yazmak çok daha kolay hale gelir.
Açık-Kapalı Prensibi (Open-Closed Principle – OCP)
Açık-Kapalı Prensibi, yazılım varlıklarının (sınıflar, modüller, fonksiyonlar vb.) genişlemeye açık, ancak değişikliğe kapalı olması gerektiğini ifade eder. Bu, mevcut kodu değiştirmeden yeni özellikler ekleyebilmek anlamına gelir. Pratikte bu, genellikle soyutlamalar (abstract sınıflar veya arayüzler) ve polimorfizm kullanılarak gerçekleştirilir. Örneğin; kullanıcı yönetim sistemine yeni bir kimlik doğrulama yöntemi (örneğin, sosyal medya hesabı ile giriş) eklemek istediğimizde, mevcut ‘Kullanici’ sınıfını değiştirmek yerine, yeni bir ‘SosyalMedyaKimlikDogrulama’ sınıfı oluşturup, bir ‘KimlikDogrulama’ arayüzünü (veya soyut sınıfını) uygulayabiliriz. Bu sayede mevcut kod bozulmadan sistemimize yeni işlevsellik eklenimiş olur. Değişikliğe kapalı olmak, yazılımın kararlılığını ve geriye dönük uyumluluğunu korur.
Liskov İkamesi Prensibi (Liskov Substitution Principle – LSP)
Liskov İkamesi Prensibi, alt sınıfların, üst sınıfların yerine kullanılabildiğinde, programın doğruluğunun bozulmaması gerektiğini belirtir. Yani, bir ‘B’ sınıfı, ‘A’ sınıfının alt sınıfıysa, programın herhangi bir yerinde ‘A’ yerine ‘B’ kullanıldığında, programın davranışında beklenmedik bir değişiklik olmamalıdır. Bu, kalıtımın doğru kullanılmasını ve alt sınıfların, üst sınıfların sözleşmelerine uymasını sağlar. Örneğin; kullanıcı yönetim sistemimizde, bir ‘AdminKullanici’ sınıfı, ‘Kullanici’ sınıfının alt sınıfı ise, ‘Kullanici’ sınıfının kullanıldığı her yerde ‘AdminKullanici’ sınıfı da sorunsuz bir şekilde kullanılabilmelidir. LSP’ye uyulmaması, genellikle alt sınıfların, üst sınıfların metotlarını geçersiz kılarak (override) beklenmeyen davranışlar sergilemesiyle ortaya çıkar.
Arayüz Ayrımı Prensibi (Interface Segregation Principle – ISP)
Arayüz Ayrımı Prensibi, istemcilerin (client) kullanmadıkları metotlara bağımlı olmaya zorlanmaması gerektiğini belirtir. Başka bir deyişle, bir sınıfın ihtiyaç duymadığı metotları içeren “şişman” arayüzler yerine, daha küçük ve daha özelleşmiş arayüzler tercih edilmelidir. Bu, sınıflar arasındaki bağımlılıkları azaltır ve kodun daha esnek ve yeniden kullanılabilir olmasını sağlar. Örneğin, kullanıcı yönetim sistemimizde, farklı kullanıcı türleri (örneğin, normal kullanıcılar, yöneticiler, misafir kullanıcılar) için farklı yetkilere sahip arayüzler oluşturmak, ISP’ye uygun bir yaklaşımdır. ‘IKullanici’ arayüzünde hem normal kullanıcıların hemde admin kullanıclarının ihtiyaç duyduğu metodlar olursa karmaşıklık oluşur. ‘IKullanici’ ve ‘IAdmin’ olarak iki ayrı arayüz oluşturmak daha doğrudur.
Bağımlılık Tersine Çevrilmesi Prensibi (Dependency Inversion Principle – DIP)
Bağımlılık Tersine Çevrilmesi Prensibi, yüksek seviyeli modüllerin (örneğin, iş mantığını içeren sınıflar) düşük seviyeli modüllere (örneğin, veritabanı işlemleri, ağ iletişimi gibi altyapı sınıfları) doğrudan bağımlı olmaması gerektiğini belirtir. Bunun yerine, her iki modül de soyutlamalara (arayüzler veya soyut sınıflar) bağımlı olmalıdır. Bu, modüller arasındaki bağımlılığı tersine çevirir ve kodun daha esnek, yeniden kullanılabilir ve test edilebilir olmasını sağlar. Örneğin; kullanıcı, yönetim sistemimizde, ‘KullaniciServisi’ sınıfının doğrudan bir ‘Veritabani’ sınıfına bağımlı olması yerine, her iki sınıfın da bir ‘IKullaniciRepository’ arayüzüne bağımlı olması, DIP’ye uygun bir yaklaşımdır. Bu sayede, veritabanı teknolojisini değiştirmek istediğimizde, sadece ‘IKullaniciRepository’ arayüzünü uygulayan yeni bir sınıf yazmamız yeterli olacaktır.
Sonuç
SOLID prensipleri, yazılım tasarımında karşılaşılan karmaşıklık, sürdürülebilirlik ve test edilebilirlik gibi önemli sorunlara çözümler sunan güçlü araçlardır. Tek Sorumluluk, Açık-Kapalı, Liskov İkamesi, Arayüz Ayrımı ve Bağımlılık Tersine Çevrilmesi prensiplerini anlamak ve uygulamak, daha temiz, daha esnek ve daha dayanıklı kodlar yazmamıza yardımcı olur. Bu prensipler, özellikle nesne yönelimli programlamada, sınıfların ve modüllerin daha iyi organize edilmesini, bağımlılıkların azaltılmasını ve kodun yeniden kullanılabilirliğinin artırılmasını sağlar. Bu makalede ele aldığımız kullanıcı yönetim sistemi örneği, SOLID prensiplerinin gerçek hayatta nasıl uygulanabileceğine dair somut bir örnek sunmaktadır. Unutmamak gerekir ki SOLID prensipleri, birer amaç değil, daha iyi bir yazılım tasarımına ulaşmak için kullandığımız araçlardır. Bu prensiplere körü körüne bağlı kalmak yerine, onları bilinçli bir şekilde ve projenin ihtiyaçlarına göre uygulamak en iyi sonuçları verecektir.