Merhaba arkadaşlar.

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. 🙂

Single Responsibility prensibindeki asıl amaç: bir class veya function’a sadece ve sadece tek bir sorumluluğu yerine getirmesine dayanmaktadır.

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.

Gökhan Gökalp

View Comments

  • 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.

  • Solid ile alakalı tüm yazılarınızı okuyacağım, br kaçına göz gezdirdim kısa ve net olması güzel

  • 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.

Recent Posts

Securing the Supply Chain of Containerized Applications to Reduce Security Risks (Policy Enforcement-Automated Governance with OPA Gatekeeper and Ratify) – Part 2

{:tr} Makalenin ilk bölümünde, Software Supply Chain güvenliğinin öneminden ve containerized uygulamaların güvenlik risklerini azaltabilmek…

5 months ago

Securing the Supply Chain of Containerized Applications to Reduce Security Risks (Security Scanning, SBOMs, Signing&Verifying Artifacts) – Part 1

{:tr}Bildiğimiz gibi modern yazılım geliştirme ortamında containerization'ın benimsenmesi, uygulamaların oluşturulma ve dağıtılma şekillerini oldukça değiştirdi.…

8 months ago

Delegating Identity & Access Management to Azure AD B2C and Integrating with .NET

{:tr}Bildiğimiz gibi bir ürün geliştirirken olabildiğince farklı cloud çözümlerinden faydalanmak, harcanacak zaman ve karmaşıklığın yanı…

12 months ago

How to Order Events in Microservices by Using Azure Service Bus (FIFO Consumers)

{:tr}Bazen bazı senaryolar vardır karmaşıklığını veya eksi yanlarını bildiğimiz halde implemente etmekten kaçamadığımız veya implemente…

2 years ago

Providing Atomicity for Eventual Consistency with Outbox Pattern in .NET Microservices

{:tr}Bildiğimiz gibi microservice architecture'ına adapte olmanın bir çok artı noktası olduğu gibi, maalesef getirdiği bazı…

2 years ago

Building Microservices by Using Dapr and .NET with Minimum Effort – 02 (Azure Container Apps)

{:tr}Bir önceki makale serisinde Dapr projesinden ve faydalarından bahsedip, local ortamda self-hosted mode olarak .NET…

2 years ago