SOLID Prensipleri Nelerdir?

SOLID Prensipleri Nelerdir?

Merhaba, bu yazımda sizlere yazılım geliştirmenin temel prensipleri olarak kabul edilen SOLID’den bahsedeceğim.

SOLID Nedir?

  • SOLID yazılım prensipleri; geliştirilen yazılımın esnek, yeniden kullanılabilir, sürdürülebilir ve anlaşılır olmasını sağlayan, kod tekrarını önleyen prensipler bütünüdür.

  • Yazılımda sürdürülebilirliği desteklemek adına kullanılan prensiplerdir.

Yazılımda Sürdürülebilirlik: Sürdürülebilir yazılımlar üretmek, yazılım geliştirme sürecinde çevresel, sosyal ve ekonomik etkileri dikkate alarak, uzun vadeli sürdürülebilirlik hedeflerine uygun yazılımlar oluşturmaktır.

SOLID Prensiplerinin amacı;

  • Geliştirdiğimiz yazılımın gelecekte gereksinimlere kolayca adapte olması,

  • Yeni özellikleri kodda bir değişikliğe gerek kalmadan kolayca ekleyebileceğimiz

  • Yeni gereksinimlere karşın kodun üzerinde en az değişimi sağlaması,

  • Kod üzerinde sürekli düzeltme hatta yeniden yazma gibi sorunların yol açtığı zaman kaybını da minimuma indirmektir.

Bu prensipler uygulanarak uygulamalarımızın büyürken, karmaşıklığın büyümesini engellemiş oluruz. “Temiz kod” yazmak için bu prensiplere uygun yazılım geliştirmelisiniz.

Şimdide prensiplerimizden bahsedelim

S- Single- responsibility principle(SRP)

Bir sınıf (nesne) yalnızca bir amaç uğruna değiştirilebilir, o da o sınıfa yüklenen sorumluluktur, yani bir sınıfın(fonksiyona da indirgenebilir) yapması gereken yalnızca bir işi olması gerekir. (Linux çekirdeği örnek verilebilir) Değiştirmek ve güncellemek daha kolaydır.

//SRP'yi ihlal ediyoruz, çünkü sınıf ekstra sorumluluğa sahip
public class Employee
{
   //Kendi sorumluluğu
   public int CalculateSalary()
   {
     return 100000;
   }
  //Kendi sorumluluğu
   public string GetDepartment()
   {
     return "IT";
   }

  //Ekstra sorumluluk(save)
  public void Save()
  {
     //Çalışanı veritabanına kaydet
  }
}

SRP’ye uygun olabilmesi için Save’i ayrı bir class’da tutmalıyız.


public class Employee
{
   public int CalculateSalary()
   {
     return 100000;
   }
   public string GetDepartment()
   {
     return "IT";
   }
}


public class Employee Repository
{
    public void Save (Employee employee)
    {
      //Çalışanı veritabanına kaydet
    }
}

O- Open- closed principle

Bir sınıf ya da fonksiyon halihazırda var olan özellikleri korumalı ve değişikliğe izin vermemelidir. Yani davranışını değiştirmiyor olmalı ve yeni özellikler kazanabiliyor olmalıdır.

public class Account
{
public string Name { get; set; }
public string Address { get; set; }
public double Balance { get; set; }

public double CalculateInterest (string accountType)
{
   if (accountType == "Saving")
   {
      return Balance * 0.3;
   }
   else
   {
      return Balance * 0.5;
   }
}

Yukarıdaki kodu aşağıdaki gibi düzenlememiz gerekiyor =>


public class Account
{
   public string Name { get; set; } 
   public string Address { get; set; } 
   public double Balance { get; set; }
}
interface IAccount
{
   double CalculateInterest (Account account);
}

public class SavingAccount: IAccount
{
  public double CalculateInterest (Account account)
  {
      return account. Balance * 0.3;
  }
}


public class OtherAccount: IAccount
{
   public double CalculateInterest (Account account)
   {
      return account. Balance * 0.5;
   }
}

L- Liskov substitution principle

Kodlarımızda herhangi bir değişiklik yapmaya gerek duymadan alt sınıfları, türedikleri(üst) sınıfların yerine kullanabilmeliyiz.


//Base/ Parent/ Superclass 

public class Employee
{
  public virtual int CalculateSalary()
  {
    return 100000;
  }
  public virtual int CalculateBonus()
  {
    return 10000;
   }
}

public class Permanent Employee : Employee
{
  public override int CalculateSalary()
  {
    return 200000;
  }
}


public class Contractual Employee : Employee
{
   public override int CalculateSalary()
   {
     return 150000;
   }
   public override int CalculateBonus(){

      throw new NotImplementedException();
   }
}

I-Interface segregation principle

Sorumlulukların hepsini tek bir arayüze toplamak yerine daha özelleştirilmiş birden fazla arayüz oluşturmalıyız.

public interface IVehicle
{
   void Drive();
   void Fly();
}
public class FlyingCar: IVehicle{
   public void Drive()
   {
      Console.Write("Drive car");
   }

  public void Fly()
  {
    Console.Write("Fly car");
  }
}
public class Car: IVehicle{
  public void Drive()
  {
    Console.Write("Drive car");
  {
  public void Fly()
  {
    throw new NotImplementedException();
  }
}

Yukarıdaki kodu aşağıdaki gibi düzenlememiz gerekiyor =>

public interface IDrive
{
  void Drive();
}
public interface IFly
{
  void Fly();
}
public class Car: IDrive{

   public void Drive()
   {
      Console.Write("Drive car");
   }

}

public class FlyingCar : IDrive, IFly
{
  public void Drive()
  {
    Console.Write("Drive car");
  }
  public void Fly(){
    Console.Write("Fly car");
  }
}

D- Dependency ınversion principle

Sınıflar arası bağımlılıklar olabildiğince az olmalıdır özellikle üst seviye sınıflar alt seviye sınıflara bağımlı olmamalıdır.

public class DataAccessLayer
{
   public void AddCustomer (string name)
  {
      // müşteriyi veritabanına ekle
     FileLogger logger = new FileLogger(); 
     logger.Log("Customer added: " + name);
  }
}
public interface ILogger
{
  void Log(string message);
}
public class FileLogger: ILogger
{
  public void Log(string message)
  {
  }
}

public class DataAccessLayer
{
   //DI 
   private ILogger logger; //bağımlılıklar soyutlandı 
   public DataAccess Layer (ILogger logger)
   {
      this.logger = logger;
   }
  public void AddCustomer (string name)
  {
     // müşteriyi veritabanına ekle
    logger.Log("Customer added: " + name);
  }
}

Sonraki yazılarımda görüşmek üzere :) Mutlu kodlamalar 🚀