Bir kaç makale serisi boyunca, SOLID prensipleri üzerinde durmayı planlıyorum. Öncelikle ilk prensibimiz olan Single Responsibility‘e geçmeden, kısaca SOLID kavramı nedir bir tanımaya çalışalım.
SOLID, Robert Martin‘in sunumu ile ortaya çıkan bir Dependency Managament(Bağımlılık Yönetimi) biçiminin, 5 adet ilkesinin baş harflerinden oluşan prensiplerdir.
Bunları sıralayacak olursak eğer:
- Single Responsibility
- Open Closed
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
Klasik tanımları bir kenara bırakacak olursak ve neden bu SOLID prensiplerine ihtiyacımız olduğu veya neden kullanmamız gerektiği düşüncesine gelirsek:
Bağımlılık yönetiminin(Dependency managament) kötü oluşturulmuş olduğu bir projede, genişletilebilirliğin neredeyse mümkün olmaması, sabit(Immobility: geliştirilen modüllerin tekrar kullanıma uygun olmaması) ve kırılgan(Fragility: yapılacak olan bir değişikliğin, başka kısımları etkilemesi) bir yapının olmasından dolayı projemizin hayat sigortasının sınırlı olması ve sürdürülebilirliğinin olmaması durumudur diye açıklayabiliriz.
Bu sebepler genel olarak SOLID prensiplerinin ortaya çıkış noktasıdır ve biz kısaca:
“Projemizin sürdürülebilirliğinin olması, yani yeni teknoloji ve eklentilere açık olması, yapılacak bir değişikliğin farklı yerleri etkilemeyip, geliştirmelere açık olmasıdır da” diyebiliriz.
Evet, bu kadar hızlı bir SOLID nedir kavramından sonra ilk prensiplerimizden birisi olan Single Responsibility yani tek sorumluluk manasına gelen prensibimizi incelemeye başlayabiliriz. 🙂
Birden fazla sorumluluklar bir class veya function’a yüklendiğinde kod aşırı büyüyor ve karmaşık bir hale geliyor. Karmaşık ve aşırı büyük bir kodun yönetimi zordur ve bu seviyede kırılganlığı (Fragility) ortaya çıkar. Aynı zamanda esnekliği (Extendability) bi okadar da azdır.
Kendisi ile ilgili sorumlulukları yerine getirmediği için, yapacağımız en ufak değişiklikler başka yerleri etkileyebilir ve yeniden kullanılabilirliğini de düşürmüş oluruz.
Yalnızca kendi sorumluluğunu getirecek şekilde parçalara böldüğümüzde ise, hem yönetimini kolaylaştırmış olup hemde yeniden kullanabilirliğini sağlarız.
Şimdi basit bir örnekle açıklayalım:
public class User { public void ChangeUserName() { //Kullanıcı adını değiştirir } public void ChangeEmailAddress() { //Email adresini değiştirir } public void SendAnEmail() { //Email gönderir } }
“User” işlemlerinin yapıldığı bir class düşünelim. İçerisinde “ChangeUserName“, “ChangeEmailAddress” ve “SendAnEmail” metotlarının olduğunu varsayalım.
İlk bakıldığında her ne kadar normal gözükse de aslında hatalı bir tasarımdır. “ChangeUserName” ve “ChangeEmailAddress” metotları “User” class’ının sorumlulukları olabilir ama “SendAnEmail” metotu sorumluluğu içinde değildir.
Bu şekildeki bir tasarımla artık “SendAnEmail” metotunun başka yerlerde kullanılabilirliğini (Reusability) engellemiş olduk.
Doğru bir tasarım yapmak gerekirse:
public class User { public void ChangeUserName() { //Kullanıcı adını değiştirir } public void ChangeEmailAddress() { //Email adresini değiştirir } } public class EmailHelper { public void SendAnEmail() { //Email gönderir } }
“User” class’ına sadece kendi sorumluluğunu verdik ve email işlemlerini “EmailHelper” isminde bir class’da topladık. (Bu helper class’ları proje yapınıza ve nerelerde ortak kullanacağıza göre değişiklik gösterebilir. Ben bu senaryo için bu şekilde uygun gördüm.) Artık email ile ilgili işlemlerimiz “EmailHelper” class’ın sorumluluğunda gerçekleştirilecek.
Bu şekildeki kullanımlarda hem kodumuzun kontrolü daha kolaylaşıyor hem de tekrar kullanılabilirliği (Reusability) artıyor.
Kısaca basit bir örnek üzerinden tanımlamış olduk. Umarım bu basit örnek, real-world projelerinizde ki yaklaşımlarınızı düşünürken, bir class’a veya bir function’a yükleyeceğiniz sorumlulukları tekrardan basit bir şekilde nasıl gözden geçirebileceğinize yardımcı olur.
Takipte kalın.
[…] bir önceki Single Responsibility makalesinden sonra sıra geldi 2. prensibimiz olan Open-Closed (Açık Kapalı) […]
Okuduğum en güzel yazılardandı hocam 🙂 Blogunuzu 1.5 yıldır takip ediyorum bugün boş vakit oldu yorum atma isteği geldi 🙂
Bu yazı ben üniversitedeyken okuduğum bir yazıydı.
Bugün hala 15-20 bin satırlık tek dosyalar üzerinden çalışılan projeler var.
Mail göndermesi de kullanıcı silmesi de yazı eklemesi de tek class üzerinde işliyor.
Bu yazıyı okuyana kadar yani iş hayatından önce ben de öyle yapıyordum.
Tabi okunabilirlik derken abartanı da gördüm. Örneğin;
class UserAccount
{
public User CreateUser()
{
}
}
class UserDeleteAccount
{
public UserDelete DeleteUserAccount()
{
}
}
Gibi. Tamam okunabilir belki ama bütünlüğü nasıl sağlayacaksınız gibi sorunlar çıkıyor.
Öncelikle teşekkür ederim, evet 3 yıl önce yazdığım eski bir post. 🙂 15-20bin satırlı god class’lar bir çok yerde karşımızda olacaktır, eminim. 🙂 Bu arada vermiş olduğun örnek sanırım, CQS kafasında bir olay. (Command/Query Object Pattern). Projeye göre değişiklik gösterir. 🙂 https://gokhan-gokalp.azurewebsites.net/repository-pattern-yaklasimi-yerine-command-query-object-pattern-yaklasimi/
Solid ile alakalı tüm yazılarınızı okuyacağım, br kaçına göz gezdirdim kısa ve net olması güzel
Teşekkür ederim.
Merhaba, yazı için teşekkürler gayet kısa ve net açıklanmış.
Bir noktaya değineceğim:
“esnetilebilirliğin(Rigidity: yeni eklentilere ve geliştirmelere açık olması)” demişsiniz, ancak rigidity katılık anlamına geliyor bunun yerine flexbility daha uygun sanırım.
İyi çalışmalar
İki kere kontrol ettim, harbiden öyle yazmışım. 🙂 O yıllarda “https://gokhan-gokalp.azurewebsites.net/iyi-tasarim-ve-kotu-tasarim-nedir/” şu yazının devamı niteliğinde başlıyacaktım. Hatta orada “Rigidity” nin “Esnemezlik” olduğunu da anlatmışım. Diğerinde kafam neredeyse artık, neden öyle demişim hala farkedemedim. 🙂
En kısa zamanda güncelleyeceğim.
Teşekkür ederim.
[…] maddede aslında dikkat etmemiz gereken asıl nokta, method özünde Single Responsibility prensibine özen göstermektir. Bu sayede bize kazandıracağı bazı avantajlar […]