Dependency Inversion Principle DIP – Tasarım Prensibi

31 Ağu

Bu tasarım prensibi, uygulamalardaki alt ve üst sınıflar arasındaki bağımlılıklardan dolayı ortaya çıkmıştır. Alt sınıfları, ana işleri yapan sınıflar olarak düşünelim. Üst sınıflar da alt sınıflara bağlı olarak işlemler yapan sınıflar olarak düşünelim. Yani üst sınıflar bazı işlemleri gerçekleştirebilmek için alt sınıflara muhtaçtır. Doğal olarak üst sınıflar, alt sınıflardan oluşturulmuş nesneleri kullanarak süreci işleteceklerdir. Ancak üst sınıfların direk alt sınıf nesnelerine bağlı olması bir takım zorlukları beraberinde getirmektedir. Bu zorlukların başında sıkı bağ oluşumu gelmektedir. Sıkı bağlılık ise gelişimi ve test edilebilirliği olumsuz etkileyen bir durumdur.

Yazılım tasarımında sıkı bağlılığı ortadan kaldıran çözüm ise nesneleri direk kullanmak yerinde soyut nesneler yani arayüzler (interface) kullanmaktır. Yani üst sınıflar, nesnelerin kendisini tanımak yerine soyut nesneleri tanırlar.

Bir örnek üzerinden kötü ve iyi kod tasarımlarını inceleyelim.

Sıkı Bağlı Tasarım


public class DisplayServiceManager
{
     readonly AnalogDisplayService service = new AnalogDisplayService();

     public DisplayServiceManager(AnalogDisplayService service)
     {
         this.service = service;
     }

     public void StartService()
     {
         service.Start();
     }

     public void StopService()
     {
         service.Stop();
     }

}

public class AnalogDisplayService
{
     public void Start()
     {
          // Start analog display.
     }

     public void Stop()
     {
          // Stop analog display.
     }

}

Bu tasarımda örnek olarak görüntü yönetimini yapan DisplayServiceManager adında, üst sınıf olan bir servis yöneticisi oluşturulmuştur. Bu üst sınıf AnalogDisplayService adında bir alt sınıfı kullanmaktadır. Yukarıda belirttiğimiz gibi, üst sınıf alt sınıf nesnesini somut olarak kullanmıştır. Yani üst sınıf, servisleri tanımaktadır. Bu da alt sınıflara sıkı bağlılık oluşturmaktadır. Bu durumda DigitalDisplayService adında yeni bir ihtiyaca karşılık, yönetici üst sınıfın yapısı değişecek.

Yani şu anki durumumuz şu şekildedir:

Üst Sınıf + Alt Sınıf

Oysa istenen durum şu şekildedir:

Üst Sınıf + Soyut Nesne + Alt Sınıf

Bağımlılığa yeni bir boyut kazandıran tasarımı ise şu şeklide yapabiliriz.

Dependency Inversion Yöntemiyle Tasarımı


public class DisplayServiceManager
{
       private IDisplaySerivce service;

       public DisplayServiceManager(IDisplaySerivce service)
       {
            this.service = service;
       }

       public void StartService()
       {
            service.Start();
       }

       public void StopService()
       {
            service.Stop();
       }

}

public interface IDisplaySerivce
{
     void Start();
     void Stop();
}

public class AnalogDisplayService : IDisplaySerivce
{

     public void Start()
     {
        // Start analog display.
     }

     public void Stop()
     {
        // Stop analog display.
     }

}

Bu kod, Dependency Inversion prensibinin uygulandığı bir koddur. Sıkı bağlılığın IDisplayService arayüzü sayesinde ortadan kalktığını görmüş olduk. Yeni eklemeler için DisplayServiceManager sınıfında değişikliğe gerek kalmadı. Esnek bir yapıya sahip olduk.

Interface Segregation Principle ISP – Tasarım Prensibi

26 Ağu

Bu tekniği, arayüz ayırma prensibi olarak adlandırabiliriz. Uygulamalarımızda bağlı kalmaya çalıştığımız soyut nesnelerle çalışma ilkesi, bazı yanlış hamleler sonucu başımıza iş açabilir. Soyutluk kavramını da bazı kurallara göre işletmeliyiz. Bize soyut nesne sağlayan 3 tane metodu olan bir interface ürettiğimizi varsayalım. Bu interface den türeyen bir de sınıf oluşturalım. Benzer şekilde bir sınıf daha türetelim. İkinci sınıfımız interface nesnemizin tek bir metodunu kullanıyor ve diğer iki metodu işe yaramıyorsa, doğru yolda değiliz demektir.

Cümlelerden ziyade bir örnek üzerinden anlatmak daha isabetli olacaktır.

Örneğimizde aşağıdaki gibi IUser tipinden iki seviyeli LowLevelUser ve HighLevelUser kullanıcı tipleri oluşturuyoruz. LowLevelUser sadece programları update edebilir. HighLevelUser ise hesap oluşturup hesap silebilir. Ancak LowevelUser tipinin CreateAccount metodu tetiklendiğinde NotImplementedException hatası ile karşılaşırız.


public interface IUser
{
      void UpdateProgram(string programme);
      void CreateAccount(string accountName);
      void DeletaAccount(string accountName);
}

public class LowLevelUser : IUser
{
      public void UpdateProgram(string programme)
      {
         // Start update service
      }

      public void CreateAccount(string accountName)
      {
         throw new NotImplementedException();
      }

      public void DeletaAccount(string accountName)
      {
          throw new NotImplementedException();
      }

}

public class HighLevelUser : IUser
{
      public void UpdateProgram(string programme)
      {
          // Start update service
      }

      public void CreateAccount(string accountName)
      {
          // Start create service
      }

      public void DeletaAccount(string accountName)
      {
          // Start delete service
      }
}

IUser arayüzünü parçalayarak işimize yarar hale getirmeliyiz. Yani alt arayüzler oluşturmalıyız.

Bu ayrımı şu şeklide yapabiliriz:


public interface IUpdater
{
      void UpdateProgram(string programme);
}

public interface IAccountManager
{
      void CreateAccount(string accountName);
      void DeletaAccount(string accountName);
}

public class LowLevelUser : IUpdater
{
      public void UpdateProgram(string programme)
      {
          // Start update service
      }
}

public class HighLevelUser : IUpdater, IAccountManager
{
      public void UpdateProgram(string programme)
      {
         // Start update service
      }

      public void CreateAccount(string accountName)
      {
         // Start create service
      }

      public void DeletaAccount(string accountName)
      {
         // Start delete service
      }
}

LowevelUser seviyeli kullanıcı tipinin sadece update işlemlerine yetkili olduğu için UpdateProgram metodunu içeren IUpdater arayüzünden türetilmiştir. Aynı şekilde HighLevelUser ise hesap yönetimlerinden sorumlu olduğu için CreateAccount ve DeleteAccount metodlarını içeren IAccountManager arayüzünden türetilmiştir.

Bu sayede arayüz ayırım tasarım prensibinin amacına ulaşabilmiş oluyoruz.

Liskov’s Substitution Principle LSP – Tasarım Prensibi

23 Ağu

Bu ilkenin benimsediği ana fikir şu şekildedir: “Alt sınıflardan oluşan nesneler üst sınıfların nesneleriyle yer değiştirdiklerinde aynı davranışı sergilemelidir.” Yani kullanıcılar (client) tarafında alt sınıf ve üst sınıfın kullanımı bir fark göstermemelidir.  Cümlelerle ifade etmek anlaşılır olsa da, kavramı örneklerle güçlendirmekte fayda var.


public abstract class Employee
{
     public abstract string GetDepartment();
}

public class ITEmployee : Employee
{
     public override string GetDepartment()
     {
          return "Information Technology Department";
     }
}

public class HumanResource : Employee
{
      public override string GetDepartment()
      {
         return "Human Resources Department";
      }
}

Yukarıdaki örnekte Employee adında bir üst ve bu sınıftan türetilmiş ITEmployee ve HumanResource alt sınıfları gösterilmiştir. Bu yapıya göre, alt sınıflar üst sınıf gibi kullanılabilir. Nasıl olduğunu şu şeklide client tarafında gösterebilriz.

static void Main(string[] args)
{
     Employee employee1 = new HumanResource();
     Employee employee2= new ITEmployee();

     Console.WriteLine(employee1.GetDepartment());
     Console.WriteLine(employee2.GetDepartment());
}

Employee tipine ait nesne(employee1), HumanResource veya ITEmployee gibi kullanılabilmiştir. Yani alt sınıflar, üst sınıfın işini üstlenebilmektedir. Yani yer değiştirme işlemi başarıyla gerçekleştirilebilmektedir.

LSP temelde Open Closed prensibinin özel bir türü veya uzantısı gibidir. Çünkü OCP den olduğu gibi LSP de de genişlemeye açık bir yapı sözkonusudur.

Open Closed Principle OCP – Tasarım Prensibi

20 Ağu

İyi kodun üretilmesi, bazı kurallara dikkat ederek mümkün olabilmektedir. Bu kurallarda biri de kodun sürekli gelişebileceğinin göz önünde bulundurulmasıdır. Sonuçta biz bir inşaat mühendisi değil, yazılımcıyız. İnşaat mühendisinin yaptığı yapıyı değiştirmesi neredeyse imkansızdır. Ancak yazılım mühendisinin üretimini her zaman geliştirme ve değiştirme imkanı vardır. Ancak bazen öyle kodlar yazarız ki kodumuzu, içerisine beton dökülmüş gibi bir hale sokar, kodu tekrar düzenleme ve yenileme işlemini imkansızlaştırırız.

Kodlama sırasında birçok değişiklik, uygulamalara yeni özellikler eklerken ortaya çıkmaktadır. Kodda yapılandırma işleminin, kodumuzu en az seviyede etkilemesini amaçlamalıyız. Kodun en az seviyede etkilenmesini sağlamak için kodu üretirken bazı durumları göze alarak hareket etmemiz gerekir. Örneğin mevcut kod zaten bir test işleminden geçerek üretilmiş olabilir. Yeni eklemelerle mevcut test durumlarını yeşilden kırmızıya düşürmemek gerekir. Özetle kodumuz geliştirilmeye açık (Open), değiştirilmeye kapalı(Closed) olmalıdır.

Bu tasarım ilkesini bir örnek üzerinden anlatmaya çalışalım. Öncelikle, open closed tasarım ilkesinin kullanılması için bir sebebimizin olması gerekir. Yani durduk yere bu prensip ortaya çıkmış değil. Hatalı bir çözümün sonucunda ortaya çıkmış olmalı.


public class FileGenerator
{
    private readonly FileBase baseFile;
    public FileGenerator(FileBase bBase)
    {
          baseFile = bBase;
    }

    public string Create()
    {
      if (baseFile is PDF)
      {
         var item = baseFile as PDF;
         return item.Create();
      }

      if (baseFile is WORD)
      {
         var item = baseFile as WORD;
         return item.Create();
      }

      return null;
    }
}

public class FileBase
{
}

public class PDF: FileBase
{
   public string Create()
   {
       return "PDF File";
   }
}

public class WORD : FileBase
{
     public string Create()
     {
        return "WORD File";
     }
}

Bu örneğimizde FileBase tipindeki bir temel tipten türetilmiş WORD ve PDF tipleri oluşturulmuştur. Bir tane de dosya oluşturma işlemini gerçekleştirecek olan FileGenerator tipi oluşturulmuştur. FileGenerator sınıfının Create metodu, base tipine göre dosya üretimi yapmaktadır. Buraya kadar hesaplanan  düzenek çalışır vaziyettedir. Ancak bu düzenekte bazı sorunlar vardır. Bunlar:

  • FileGenerator tipi, dosya tipleriyle (WORD, PDF) birebir ilgilenmekte. Yani nesnelere direk eriştiğinden sıkı bağlılık sözkonusu.
  • Yeni bir dosya tipi eklendiğinde FileGenerator sınıfının Create metodunda değişiklik yapılmak zorunda. Oysa değişikliklere kapalı bir sistem olmalı. Ne kadar dosya tipi oluşturulursa oluşturulsun, FileGenerator sııfı etkilenmemeli. Yani gelişime açık sistem olmalıdır.
  • FileGenerator tipine ait create metodunun testleri her yeni ekleme

[Test]
public void FileGenerator_Generates_PDF()
{
    var file = new FileGenerator(new PDF());
    var created = file.Create();
    Assert.AreEqual("PDF file",created);
}

Yani yukarıdaki tes metodu, WORD için, PDF için çalışırken, FileBase tipinden türetilmiş EXCEL şeklinde yeni bir tip için çalışmayacaktır. Create metodunda değişiklik isteyecektir.

Bu gibi dezavantajları göz önünde bulundurarak yeni bir yapı tasarlayalım.


public class FileGenerator
{
    private readonly IFileBase fileBase;

    public FileGenerator(IFileBase fileBase)
    {
         this.fileBase = fileBase;
    }

    public string Create()
    {
         return fileBase.Create();
    }
}

public interface IFileBase
{
     string Create();
}

public class PDF : IFileBase
{
    public string Create()
    {
        return "PDF file";
    }
}

public class WORD : IFileBase
{
    public string Create()
    {
        return "WORD file";
    }
}

Bu tasarımda, FileGenerator ile dosya tipleri arasında IFileBase interface ile bir esneklik sağlanmıştır. Bu sayede FileGeerator tipinin sadece temel tip olan IFileBase tipinden haberi vardır. WORD, PDF gibi tipleri tanımaz. Bu yüzden yeni eklemeler(örn. EXCEL) FileGenerator sınıfında hiçbir etki yapmayacaktır.Yani değişikliğe kapalı (Cosed) şartını sağlamış olduk. İstediğimiz kadar yeni dosya tipi üretebiliriz. Böylece genişlemeye  de açık (Open) olma şartını sağlamış olduk.

Artık birim(metod) testler de değişikliklere dayanıklı hale gelmiş oldu. Yeni bir tip üretip testten geçirebiliriz.

Sürekli değişikliklere rahat cevap verebiliriz ve müşterilerden gelen yeni dosya tiplerine karşı hazırlıklıyız.

Tekrar görüşmek ümidiyle…

Blog sayfam 1 yaşında

19 Ağu

Bugün 19 ağustos 2012. Bir yıl önce web dünyasına açtığım blog sayfam bugün ilk yaşına girdi. Yeni yaşında sayfamın temasını da değiştirmek istedim.

Blog maceram nasıl mı başladı?

Genelde bir işi yapmayı hedeflediğimde, genelde o işi bir takvime bağlarım. Ancak blog sayfamı şu zaman başlarım bu zaman başlarım derken epey zaman geçirmiştim. Bir gün, “ben bu işe başlıyorum artık” dedim. Hemen alan adı ve hosting işlemlerini halledip yazılarımı yazmaya başladım. Demek ki bazı şeyleri yapmak için plan yapmaya gerek yokmuş.

Aklıma takılan sorunları ve çözümlerini yazarak başladım işe. Ardından unutmaya meyilli olduğum,  yani sık kullanmadığım konular hakkındaki yazılarımı da eklemeye başladım siteme. Derken uzadı uzadı gitti. Bir senede epeyce birikim yapmışım.

Eğer blog yazmaya başlamasaydım, unuttuklarımı bana(kendi dilimle) hatırlatacak bir hatıra defterim olmayacaktı. Diğer taraftan, yazdıklarımı diğer geliştiricilerle de paylaşılmış oldum. Bazen olumlu geri dönüşler almak gerçekten hoşuma gidiyor.

Bence her programcı cesur olmalı ve bir blog sayfası tutmalı. Nasıl biz zor durumda kaldığımızda başkalarının paylaşımlarından faydalanıyorsak, başkaları da zor durumda kaldığında bizden faydalanabilmelidir.

Single Responsibility Principle SRP – Tasarım Prensibi

16 Ağu

Bu tasarım prensibi, her işten tek sınıfın sorumlu olmasını benimsemektedir. Yani bir sınıfta değişiklik yapmak için iki nedeniniz varsa, bu sınıfı ikiye bölmeniz gerekir. Böylece  her bir sınıf, ayrı bir sorumluluğu üstlenmiş olur. Eğer bir sınıfa birden fazla sorumluluk yüklersek, sınıftaki değişiklikler sırasında işleyişi bozabiliriz.

Örnek uygulama ile devam edelim.


public class EmailService: IEmailService
{
      public void sendEmail(string email)
      {
          if(isUserAuthorized())
          {
              // email gönder
          }
      }

      private bool isUserAuthorized()
      {
           // veritabanına git
           // query user
           // user varsa ve yetkiliyse
           return true;
      }

}

Yukarıdaki EmailService sınıfı, hem Email gönderme işlemini yapmaktan hem de kullanıcının veritabanında olup olmadığını kontrol etmekle sorumludur. Yani kullanıcı kontrolü ve Email gönderme işlemleri farklı işlemler. Bu durumda sınıfta değişiklik yapmak için iki nedenimiz var. Bunu şu şeklide Single Responsibility Prensibine uygun hale dönüştürebiliriz:


public class EmailService: IEmailService
{
      public void sendEmail(string email)
      {
         if(MembershipService.IsUserAuthorized("bayram"))
         {
             // email gönder
         }
      }
}

public class MembershipService
{
      public static bool IsUserAuthorized(string user)
      {
          // veritabanına git
          // query user
          // user varsa ve yetkiliyse
          return true;
      }
}

Bu durumda her sınıf kendi sorumluluğunu yerine getirmiş oldu.

Kitap – Programming Entity Framework

14 Ağu

ADO.NET mimarisinin en önemli araçlarından biri olan Entity Framework mimarisini ustasının ağzından dinleyebileceğiniz bir kitap.

Entity Framework yapısının temellerindeki yaklaşımları adım adım anlatmaktadır. Bu yaklaşımları aşağıdaki gibi sıralayabiliriz:

  • Code First
  • Database First
  • Model First

Bunun yanında SQL sorgularının ORM aracıyla kullanılması, Stored procedure kullanımı gibi konularada yer verilmektedir.

ORM araçlarının temelinde yatan entity mantığı derinlemesine irdelenmektedir.

Kitabın dili ingilizce olmakla beraber anlaşılır şekildedir.

Umarım zevkle okursunuz.

Kod Kata

13 Ağu

Kod kata hakkında buradaki yazımızdan bilgi edinebilirsiniz. Kod katalarının videolar şeklinde kaydedilerek toparlandığı bir de web sitesi mevcut. Bu site, Özcan Acar tarafından hazırlanan www.kodkata.com adlı internet sitesidir. Benim de hazırladığım video kataları yayınladığım bir platformdur. Böyle bir çalışmayı üstlenen ve yürüten Özcan Acar’a teşekkür ediyorum.

Çevik Süreç Prensipleri – Agile Principles

9 Ağu

Bu yazıda çevik süreçlerde benimsenen 12 prensibi ingilizce ve türkçe anlamlarıyla açıklamaya çalıştık. Çevik süreçlerde proje geliştirenlerin bu ilkelere uyması gerekmektedir. Şunu da belirtmekte fayda var ki, çevik süreçler bir yazılım geliştirme metodu değildir. Yazılım geliştirme disiplinidir. Belli kurallar dahilinde ilerlemeyi amaçlayan bir disiplindir. Aşağıdaki ilkelerle de bu disiplini anlamaya çalışalım.

EN: “Our highest priority is to satisfy the customer through early and continuousdelivery of valuable software.

TR: “En önemli önceliğimiz, çalışır haldeki programları kısa sürelerde oluşturup teslim ederek müşteriyi tatmin etmektir.

Müşterinin tatmin olması demek, müşterinin yaptırdığı projenin ilerleyişini görerek eksikliklerinin giderilmesi ve aklındaki soru işaretlerinin ortadan kalkmasıyla olu. Bu sadece yazılım işinde değil diğer sektörlerde de böyledir. Örneğin inşaat işi yaptırıyorsa sık sık gidip inşaat alanını gezer. Müşteri işin istediği gibi ilerlediğini gördüğünde tatmin olur. İş bitiminde de müşteri isteklerini karşılayan bir proje teslim edilmiş olur.

 EN: “Welcome changing requirements, even late in development. Agile processes harness change for the customer’s competitive advantage.”

TR: “Yazılımdaki değişiklikler hoş karşılanmalıdır. Bu değişiklikler yazılım süresini uzatsa bile hoş karşılanmalıdır. Çünkü çevik süreçler değişiklikleri müşterinin rekabet avantajını korumak için kullanılır.

EN: “Deliver working software frequently, from a couple of weeks to a couple of months, with a preference for the shorter timescale.”

TR: “Birkaç hafta ile birkaç ay gibi kısa zaman dilimlerine çalışan yazılımları oluştur.

Müşteriye plan ya da belgeleri teslim etmek değil çalışan programları sunmak gerekir. Teslimatlar arasındaki değişim, gelişimin göstergesidir.

EN: “Business people and developers work together daily throughout the project.”

TR: “Müşteri ve programcılar proje boyunca beraber çalışır.

Projenin çevik olması; müşteri, programcılar ve hissedarların beraber etkileşim içerisinde olmasını gerektirir. Müşteri veya programcı tarafındaki gereksinimlerin anında giderilmesi sağlanır.

EN: “Build projecsts around motivated individuals, give them the environment and support they need and trust them to get the job done.”

TR: “Motivasyonu yüksek bireylerle proje oluştur. Onlara ihtiyaç duydukları ortamları sağlayarak işi yapabilecekleri konusunda onlara güven.”

Bireyler en önemli başarı faktörüdür. Her birey takımın bir parçasıdır. Bireyler, kendilerine duyulan güvenle motive olurlar. Bu şekilde kendilerini önemser ve işe verirler. Yardımlaşma ve dayanışmayla, bilgi bakımından kısa sürede aynı standartlara gelirler.

EN: “The most efficient and effective method of conveying information with and within a development team is face-to-face conversation.”

TR: “Bilgi alışverişinde en etkili yöntem yüz yüze görüşmektir.

Çevik süreçlerde insanlar birbirleriyle konuşurlar. Ekip, konuşarak sorunların çözümüne daha kolay oluşur.

EN: “Working software is the primary measure of progress.”

TR: “Çalışan yazılım, sürecin işlediğinin birincil göstergesidir.

Çevik projelerde sürecin ölçütü, o anda müşterinin ihtiyacını karşılayan bir yazılımın ortaya koyulmasıyla belirlenir. Sunulan ilerleme raporları veya dökümantasyonlar ile ölçüm yapılmaz. Dökümanlar yalan söyleyebilir fakat çalışan uygulama gerçekleri söyler. Bu da çevik süreçlerin müşteri lehine olduğunu gösterir.

EN: “Agile processes promote sustainable development. The sponsors, developers and users should be able to maintain a constant pace indefinitely.”

TR: “Çevik süreçler sürdürülebilir gelişimi destekler. Müşteriler, yazılımcılar ve kullanıcılar bir arada çalışabilmelidirler.

Süreç istikrarlı bir şekilde ve rutin bir tempoda ilerlemelidir. Motivasyonun bozulmaması açısından aşırı iş yükü ve fazla mesai hoş karşılanmaz. Görevler, ekibe adil bir şekilde dağıtılır.

EN: “Continuous attention to technical excellence and good design enhances agility.”

TR: “Teknik mükemmelliğe sürekli özen gösterilmesi ve iyi tasarım, çevikliği güçlendirir.

Hızlı ilerlemek için, yazılımın temiz ve sağlam tutulmasıyla olur. Bu yüzden tüm ekip en kaliteli kodu üretmek için kararlıdır. Hataları gidermeyi ve kod iyileştirmelerini refactoring sırasında gerçekleştirebilirler.

EN: “Simplicity – the art of maximizing the amount of work not done – is essential.”

TR: “Baitlik esastır.

Çevik takım üyeleri, hedeflerine uygun en basit çözümü uygularlar. Karmaşık ve gereksiz kod yazmaktan kaçınırlar. Bugün yarın şu da lazım olur diye iş yapmazlar. Günün ihtiyaçlarına uygun en basit çözümü sunarlar.

EN: “The best architectures, requirements and designs emerge from self-organizing teams.”

TR: “En iyi mimariler, gereksinimler ve tasarımlar kendi kendine organize olan takımlardan çıkar.

 Çevik ekipler kendi kendine organize olabilirler. Sorumluluklar ekibe eşit şekilde paylaştırılır.  Bu sorumlulukları yerine getirmek için en iyi yol belirlenir.

EN: “At regular intervals, the team reflects on how to become more effective, then

tunes and adjusts its behavior accordingly.”

TR: “Takım, nasıl daha etkili olabileceği konusunda kendini belirli aralıklarla sorgular ve buna göre davranışlarını belirler.

 Çevik bir ekip sürekli olarak, kuralları, ilişkileri, sözleşmeleri ve organizasyon yapısını ayarlar.