Yazılım geliştirme sürecinin en önemli kısımlarından biri proje alt yapısının, mimarisinin hazırlanmasıdır. Genelde bu süreç hızlı geçilerek tabiri caizse bodoslama olarak kodlama kısmına geçilir. Proje ilerleyip modüller çoğaldıkça karışıklıkta beraberinde gelir. Bunun yanında hızla değişen ve gelişen devops tarafı da işin içine girince, tasarım desenlerinin (design pattern) ne derece önemli olduğu bir kez daha ortaya çıkmaktadır. (minimum bağımlılık)

Nedir Bu Dependency Injection?

Yazılımda bağımlılıkların dışarıdan enjekte edilmesi işlemidir. Özellikle micro servis mimarisinin popüler olduğu bu dönemde modüllerin, servislerin ve katmanların birbirleri arasındaki bağımlılıkları en aza indirilmelidir. İşte tam bu duruma çözüm sağlamaktadır.

Konu kelimelerle biraz havada kalmış olabilir. Gelin bu konuyu, yazılım projelerinin olmazsa olmazı log mekanizması üzerinde basit bir örnekle açıklayalım.

public interface ILog{   void LogWrite();}

ILog interface’imizi kullanarak iki tane class oluşturalım. Biri göndereceğimiz logu database, diğeri .txt dosyasına yazsın.

DatabaseLog.cs

public class DatabaseLog:ILog{  public void LogWrite()  {     // Database'e yazma işlemleri yapılacak.    Console.WriteLine("database loging");  }}

TextLog.cs

public class TextLog:ILog{  public void LogWrite()  {     // Txt dosyasına yazma işlemleri yapılacak.    Console.WriteLine("text loging");  }}

Evet iki classımızı da ILog’dan türeterek oluşturduk. Şimdi sıra geldi bunları kullanacak bir LogManager yazmaya.

ILogManager.cs

internal interface ILogManager{  void LogWrite();}

LogManager.cs

class LogManager: ILogManager{  private ILog _log;  public LogManager(ILog ILog)  {    _log = ILog;  }  public void LogWrite()  {    _log.LogWrite();  }}

Evet geldik dananın kuyruğunun koptuğu yere 🙂 LogManager sınıfımızın contractor’na baktığımızda ILog tipinde parametre aldığını göreceğiz. Yani ILog tipinde bir class’ı enjekte edeceğiz. LogManager sınıfımız örnekte göründüğü üzere dışarıdan gelen nesneyi bilmemektedir, bunun yerine hangi tipte geleceğini bilmektedir. Peki enjekte etmek yerine kullanmak istediğimiz yerde bu sınıfı direk çağırarak kullansaydık ne olurdu? Bunu da bir senaryo ile açıklayalım.

Proje, geçen zaman içinde yüzlerce belki binlerce sayfaya ulaşacak ve asıl sorun o zaman başlayacaktır. Loglama olarak txt loglama kullandığımızı düşünelim ve tüm sayfalarda ilgili class’ı direk çağırarak kullandığımızı varsayalım. İleride txt log yerine başka bir log yapısına geçmek istediğimizde (örn: database log) bu sınıfı kullandığımız heryerde değişiklik yapmamız gerekecek. (İşte tam da burada bağımlılıkların azaltılmasının önemi ortaya çıkmaktadır.)

Evet peki bu enjekte işlemini nerede ve nasıl yapacağız. Standart .net framework’ünde bu işlemi ninject, autofac, unity gibi paketlerle yapmaktaydık. .Net core tarafında ise bu yapı bütünleşik olarak gelmektedir ve konfigürasyonu çok kolaydır.

Uygulama .Startup’ında ayağa kalkan (tetiklenen) ConfigureServices’ methoduna sadece kullanmak istediğimiz log alt yapısını (ilgili class ve interface’i) eklememiz yeterli olacaktır.

public void ConfigureServices(IServiceCollection services) {   // Database log için      services.AddScoped<ILog, DatabaseLog>();  // Txt log için      services.AddScoped<ILog, TextbaseLog>();}