Microservice Architecture

Son dönemlerde sıklıkla bahsedilen microservice mimarisini araştırmayı ve öğrendiklerimi blog yazısı haline getirmeye niyetlendim. Microservice mimarisine geçmeden monolithic mimari hakkında kısaca bir özet geçelim.

Monolithic/Layered mimari aslında traditional SOA yaklaşımıdır. Standart web uygulamalarında, server side uygulama clientlardan gelen requestleri işleyip, veritabanından verileri çekip-güncelleyip sonrasında uygun html çıktısı olarak kullanıcılara göstermektedir. Tüm bu işlemler tek bir çatı altında toplanmıştır.

Tüm componentler tek bir yapı içerisinde birbirlerine bağlı durumdadırlar. Manageability (yönetim), maintenance (bakım) vb avantajlar nedeniyle tercih edilmektedir. Ancak büyüyen sistemler yönetimi zorlaştırmaktadır.

  • Uygulama büyüdükçe sistemin tekrar baştan ayağa kaldırılması uzun sürecektir.
  • Sistem içerisinde herhangi bir yapıyı tekrardan update etmek ve ettikten sonra tüm sistemi tekrardan deploy etmek zorunda kalabiliriz. Birbirine bağlı yapılar yeri geldiğinde  sorun çıkartabilir. Componentte yapılan değişim diğer componenti etkileyebilir.
  • Sistem içerisinde bulunan componentleri aynı dil ile geliştirilmek zorundayız.
  • Monolithic mimari olan sistemlerde scaling işlemi uygulama kopyaları oluşturularak, load balancer kullanılarak yapılır. Büyük uygulamalarda sıkıntı yaratacaktır. Küp yaklaşımında x ekseninde büyümeye tekabül eder. Birazdan inceleyeceğimiz microservice mimarisi y ekseninde büyümeye denktir.

  • Yeni teknolojileri veya dilleri sisteme adapte etmek zor olacaktır.

Bazı dezavantajlarını saydık. Avantajlarından birine değinecek olursak, componentler tek bir yapı içerisinde bulunduğundan birbirleri ile iletişimleri kolaydır. Nispeten küçük boyutlu ve karmaşıklığı az olan uygulamalarda tercih edilmelidir. Hızlı başlangıç için uygulamalara hız katar ancak uygulama boyutu arttıkça yönetilebilme sorunları ortaya çıkar.

Şimdi gelelim microservice mimarisinin nimetlerine ve getirdiği dezavantajlara. Martin fowler’ın sitesinde bulunan makalede detaylı bahsedilmektedir. Aslında microservis mimarisinin mantığı çok uzun zamandır biliniyor. Son dönemlerde popülaritesi artmıştır.

Microservis tabanlı uygulamalarda, componentler birbirinden ayrılmıştır ve ihtiyaç olduğu zaman birbirleri ile haberleşmektedirler. Microservis mimarisi mevcut uygulamanın boyutunu servislere bölüp azaltma amacındadır. Componentler birbirinden bağımsız tanımlanabilir. Yapılacak küçük bir değişim yüzünden tüm sistem tekrardan re-deploy edilmek zorunda değildir. Servislerin kendi aralarında haberleşmesi önem taşımaktadır.

Arayüz tamamen backend yapısından ayrılmıştır. Backend yapısı kendi içerisinde farklı servislere ve veritabanlarına ayrılmıştır. Bazı servisler NoSQL veritabanı kullanırken bazı servisler klasik veritabanı kullanabilir. Her servis üzerinde farklı yazılım ekibi çalışabileceği gibi her servis farklı bir dil kullanılarak yazılabilir. Servisler boyut olarak küçüktürler ve scale edilebilmeleri daha kolaydır.

Microservice mimarisine geçmeden önce uygulamamızın ihtiyacını karşılayıp karşılamadığını iyi anlamalıyız. Gereksiz yere kullanmaktan kaçınılmalıdır.

Microservice mimarisinin getirdiği dezavantajlara bakacak olursak;

  • Fazla zor bir case olmamasına rağmen geliştiriciler servisler arası mesajlaşma işini halletmelidir. Genelde servisler REST yolu ile iletişim kurarlar. Alternatif olarak async tabanlı AMQP protokolünü kullanabilirler.
  • Servisleri farklı yapılar ile geliştirme avantajı olsada yeri geldiği zaman karmaşıklığa yol açabilir.
  • Birbirinden bağımsız veritabanları kullanılan servislerde, verilerin birbirleri ile tutarsız olmaları sıkıntı yaratabilir. Servisler arasında kullanılan verilerin tutarlılığını sağlamak için Event-driven mimari kullanılabilir. Veritabanında bulunan veri değiştiği zaman servis olay mesajı olarak bilgilendirme yapar. Buna göre diğer servisler verilerini günceller.
  • Deployment süreci zorlaşabilir.

Uygulamanın boyutu küçükse ve fazla logic yoksa monolithic mimari tercih edilmelidir.

Kaynakça

DIP – IoC – DI ve IoC container kavramları

Daha önce SOLID prensiplerini anlatırken bahsettiğimiz Dependency Inversion Principle yani bağımlılıkların tersine çevrilmesi prensibinin nasıl gerçek örnekler üzerine implement edileceğinden bahsedeceğim.  Bu prensip altında kullanılan ve birbirleri ile karıştırılan konuların üzerinden geçeceğim.

İyi bir yazılım sistemi geliştirirken kullandığımız elemanlar birbirlerine az bağımlı (loosely coupled) olmalıdır. OOP ile geliştirdiğimiz nesneler esnek olmalıdır ve birbirlerine az bağlı olup değişimlerden az etkilenmelidir. Sistem reusable olmalıdır, kodlar ise encapsulated olacak şekilde geliştirilmelidir. Herhangi bir component diğer  bir component’in ne yaptığı ile ilgilenmemelidir.

En Kullanışlı 2 yöntem abstraction ve interface yapıları ile inşa etmektir. Eğer componentler ileride değişikliğe uğrayacak ise onları concrete tanımlamak yerine, interface yardımı ile oluşturmalıyız.

Aşağıdaki resme bakarak genel kavramlar daha iyi netleşmektedir.

image2

Dependency Inversion Principle (DIP): Yazılım geliştirirken kullanılan SOLID prensiplerinden biridir. Bir sistemin nesnelerinin birbirlerine olan bağımlılıkların az olması için yapılması gerekenleri anlatır. Ancak nasıl gerçek uygulamalar üzerinde uygulanacağını (problem çözümünü) anlatmaz. Bize tanımlama yapar.

Yüksek seviyeli componentler tanımlama yapar ve alt seviyeli componentler onlara bağlı olur. Yani üst componentler alt componentlere bağlı olmaz. Böylece tam tersi olur, bağımlılıklar ters çevrilerek sistem esnek olur. Hem üst seviye, hem de alt seviyeli componentler abstractionlara (soyutlamalara) bağlı olur.

“Abstractions should not depend on details, Details should depend on abstractions.”

Özet olarak DIP prensibi bize sistemin loosely coupled, bağımsız, modüler ve test edilebilir olması gerektiğini söyler.


Inversion of Control (IoC): DIP prensibini uygulayan tasarım şablonudur. Herhangi bir yapıyı yöneteni invert etmektedir. Sınıf veya sistem içerisindeki herhangi bir modülün kullanacağı bağımlılıkları dışarıdan üretip kullanması gerektiğini söyler. Soyutlama yapmamızı sağlar.

Eğer alt seviyeden bağımsız bir üst seviye component oluşturmak istiyorsak, alt seviye componentlerin nesne oluşturmaması için kontrolü invert edip nesne oluşturma işini üst seviye componentler tarafından yapılmasını sağlamalıyız.

IoC yapmak için 3 yol  bulunur. (Yukarıda olan şemada 2 yol bulunuyor.)

  • Interface inversion  (Interfaceler invert ediliyor.)
  • Flow inversion (Akışı invert et)
  • Dependency creation & binding (kendi içinde 3’e ayrılır. en çok kullanılan yöntem DI)

Dependency Injection (DI): IoC pattern’ı uygulamak için yapılmış implementasyondur. Bağımlı nesneleri oluşturma ve bağlama işini sınıfın içinde değil dışarıda yapmaktadır.

Normal şartlarda herhangi bir sınıfın kullanacağı sınıflar, o sınıfın içerisinde tanımlanır. Böylece sınıf, oluşturulan nesnelere bağımlı olur (Tightly coupled). Dependency injection kullanarak bu bağımlı nesneler dışarıda oluşturulur. 3 tane yolu vardır. Kendimiz DI yönetimi oluşturabileceğimiz gibi hazır olarak kullanılmaya hazır IoC framework yapılarından birini kullanarakta yapabiliriz.

  • Constructor Injection: Sık kullanılan bir DI yoludur. Dışarıda oluşturulan bağımlılıkları, aktarılmak istenen sınıfa constructor üzerinden göndeririz. Repository sınıfı içerisinde sadece Save() metodu olan boş bir sınıftır ve IRepository interfaceden türetilmiştir. Main içerisinde oluşturulan repository nesnesi, transaction nesnesine constructor ile enjekte ediliyor. Dbrepository yerine farklı bir repository bağlasak bile transaction sınıfı bağımlı olmadığından sıkıntı olmayacaktır. Çünkü transaction sınıfı içerisinde repository interface ile tanımlanmıştır.

dip1

dip2

  • Setter Injection: Sınıf içerisinde bağımlı sınıfı örneklemek için kullanılacak bir değişken tanımlanır. O değişken set edilerek bağımlılık enjekte edilir. Transaction içerisinde tanımlanmış Repository değişkeni main içerisinde nesne tanımlanırken set ediliyor.

dip3

dip4

  • Interface Injection: Fazla kullanılan bir yol değildir. Inteface içinde metod oluşturulur ve bağımlılık o metod ile aktarılır.

Ioc Container: Dependency Injection yapmak için kullanılan frameworklere denir. Nesne oluşturmasını denetler ve nesnelerin yaşam döngülerini kontrol eder. Sistem çalıştığı zaman ihtiyaç olan bağımlı nesneleri doğru şekilde üretir. C# ile kullanılan IoC containerlar aşağıda gösterilmiştir.

Kaynakça

Observer Design Pattern

Behavioral (davranışsal) tasarım kalıplardan olan observer pattern sık kullanılır. One to many ilişkili birden fazla nesneden oluşur. Bir nesne değiştiği zaman, ona bağlı diğer nesnelerde otomatik olarak değişmektedir. Olay (event) bazlı değişimler olmaktadır.

Aslında observer pattern c#’da bulunan event yapısı ile aynıdır.

Subject: Ana nesnedir. Bu nesne içerisinde diğer nesnelerin içinde bulunduğu liste vardır. Yani diğer nesneler(observers) subject’e bağlıdır. Birden fazla observer tek bir subject’e bağlanabilir. Notify() metodu ile observerların içerisinde bulunan update() metodunu çağırır. Attach() metodu ile nesne bağlarız. Detach() metodu ile nesneleri ayırma işlemini yaparız.

Observer: Subject’e bağlıdır. Ana nesnede değişim olduğu zaman observer içerisinde bulunan update() metodu subject tarafından çağrılır. Böylece her observerler meydana gelen değişimden etkilenir.

Yukarıda bahsettiğim subject ve observer nesnelerini metodları aşağıdaki uml şeması ve sequence diyagramı ile gösterilmiştir. Notify() ile mevcut tüm observer nesnelerinin update() metodları çağrılmaktadır. Böylece olan değişimlerden observerlar etkilenir. Concreteobserver nesnesinde, subject tarafından çağrılan update() metodu içerisinde mevcut durum güncellenir. Concretesubject ise değişim olduğu zaman observerlara bildirim yollar.

 

observeruml
uml şeması

sequence diyagram
sequence diyagram

Örnekler: Observer pattern çalışma mantığını örnekler ile anlatalım.

  • Verilerin 3 farklı sunum şekli tanımlanmıştır. Bunlar observer, veri kaynağı ise subject olarak tanımlanmıştır. Subject üzerinde yapılan herhangi bir değişiklik observerlar üzerinde uygulanır. Observer nesneleri veriyi aynı yerden alırlar ancak birbirlerinden haberleri yoktur. Birden fazla observer bulunabilir.

observer-spreadsheet-example

  • Bir diğer örnekte sorular sorulup kullanıcıların cevapladığı yaygın platform quora üzerinden olsun. Sorulan soru subject olsun. Bu soruyu takip eden 13 kişi olsun. Takipçiler observer nesneleri olacaktır. Mevcut soruya yeni bir cevap yazıldığı zaman soruyu takip eden herkes bildirim almaktadır.
  • MVC (model view controller) mimarisi observer pattern için bir örnektir. Modelin(subject), viewlar(observers) ile ayrışmasını sağlar. Model üzerinde herhangi bir değişim olduğu zaman tüm viewlar etkilenecektir.
  • Event management (olay yönetimi) yapılırken kullanılır.

Kısaca tanıtım yaptıktan sonra kod kısmına geçelim. Github üzerinden koda erişebilirsiniz.

Örnekte ürün market ilişkisi observer pattern ile gösteriliyor. Ürünler subject olarak, marketler observer olarak tanımlanmıştır. Ürünlerin fiyatları değiştiği zaman tüm marketler bu değişimden haberdar olacaktır.

Ürünler için abstract olarak Product sınıfı tanımlanmıştır. Bu sınıftan yeni ürünler yani subjectler türetilecektir. Attach() metodu içerisinde shops listesine marketler eklenmektedir. Yani fiyat değiştiği zaman güncellenecek olan observerlar burada bağlanıyor. Detach() metodu ile tam tersi olarak listeden marketler çıkarılmaktadır. Fiyat ve ürün ismi olarak 2 değişken döndürülmektedir.

abstractsubject

  ProductA sınıfı bu abstract sınıftan türetilmiştir. Aynı şekilde birden fazla ürün yani subject oluşturup onlara farklı farklı observerlar bağlayabiliriz.

concretesubject

Concrete observer sınıfı ile subjectlere bağlanacak nesneler oluşuyor. Bu sınıf içerisinde Update() metodu içeren bir interfaceden kalıtım almaktadır. Subject içerisinde bulunan Notify() metodu içerisinde observer içerisindeki update metodu çağrılmaktadır. Böylece ne kadar nesne üretilmiştir ise hepsi değişimden haberdar olacaktır.

observer

Programı çalıştıran kod aşağıda gösterilmiştir. Önce observer ve subject nesnelerini oluşturduk. Ardından subject nesnelerine observerları attach() metodu ile bağladık. Ardından fiyat değişimleri yapınca her bir observer nesnesinin update() metodu çağrılmaktadır.

programcode

Ekran çıktısı

output

Kaynakça

Adapter Design Pattern

Daha önce planladığım ancak yazmayı ertelediğim tasarım şablonlarına devam ediyorum. Yazmaya başladığım şablon structural(yapısal) tasarım desenlerinden olan adapter tasarım şablonudur. Kısaca tanımını yapalım.

Adapter design pattern ile genellikle sistemimize uymayan sınıfları veya nesneleri, sistemimize adapte etmek için kullanırız. Çevremizde bir çok sistem adaptör mantığını kullanılarak birbirleri ile etkileşir. Örneğin hafıza kart adaptörleri; hafıza kartını bilgisayarımıza direkt olarak takamazsak adaptör kullanarak takarız ve işlemimizi gerçekleştiririz. Şarj için kullanılan adaptörler de bu kapsama girer. Yazılım geliştirme süreçlerinde de aynı mantık geçerlidir. Sistemimize yeni eklemek istediğimiz özellikleri barındıran arayüzü uyumsuz sınıfları veya nesneleri bu şablonu kullanarak sistemimize uyumlu hale getirmekteyiz. 3.parti kütüphaneleri projemize uyumlu hale getirmek gibi.

Temel olarak 2 uyumsuz arayüz arasında köprü görevi görür. 2 çeşit adapter pattern uygulaması vardır. Birincisi ve aşağıdaki uml’de gözüken sistem sınıf adapter yapısıdır. Miras tabanlı adapter işlemi yapar. Diğeri ise object tabanlı adapter yapısıdır. Bu yapı delegate yolu ile işlem yapar.

  • ITarget : ITarget arayüzü client tarafında kullanılan işlemleri gerçekleştirir. Kullanılan ana arayüz sınıfıdır.
  • Client : ITarget arayüzü ile etkileşime girmektedir. Adaptee edilmek istenen sınıf ile uyumsuzdur.
  • Adaptee : Sisteme eklemek istenilen özelliklerin bulunduğu arayüz sınıfıdır. ITarget arayüz sınıfı ile uyumlu değildir.
  • Adapter : Adaptee arayüzünü ITarget arayüzü ile bağlamaktadır. İçerisinde adaptee nesnesini barındırır. Adaptee yapısında olan özellikleri ve metodları adaptee üzerinden sağlamaya yaramaktadır.

Adapter tasarım şablonunu kullanarak basit bir örnek sistemi inceleyelim.

1- IEmployee sınıfı sistemde kullanılan ana arayüzdür. Void tipli salary metodu tanımlanmıştır.

1

2- Employee sınıfı bu arayüzü uygulamaktadır. Salary metodu içerisinde her çalışanın maaş değeri, constructordan dönen isim değeri eklenerek ekrana yazılır.

2

3- Manager sınıfı (adaptee) sisteme eklenmek istenmektedir. Bu sınıfta SalaryBonus metodu bulunmaktadır. Bu metod kullandığımız arayüze uymamaktadır.

3

4- EmployeeAdapter bizim adapter sınıfımızdır. Ana arayüzü ve eklenecek olan(adaptee) sınıfını uygulamaktadır.

4

5 – Çalışan Listesi oluşturuluyor. İki elemean normal employee sınıfından oluşturulmaktadır. Diğer eleman ise adapter sınıfından oluşturuluyor. Show metodu ile tüm çalışanlar listelenmektedir.

5

6 – Ekran görüntüsü aşağıdaki gibidir. John ve Jane adlı çalışanların maaş bilgisi gösterilmektedir. Mark adlı managerin maaş bonusu gösterilmektedir.

6

Adapter design pattern kullanarak yapılmış basit bir örneği inceledik. Daha kapsamlı örnekler internette mevcuttur.

 Kaynakça

Abstract Factory Pattern

Creational design patterns kategorisinde bulunan ve çok kullanılan abstract factory design pattern konusunda yazacağım. Uzunca bir anlatımdan ziyade bu tasarım şablonu kullanılmış bir örnek göstereceğim. Kaynakça olarak paylaşacağım linkler detaylı olarak araştırmak için yeterli olacaktır.

 “Provide an interface for creating families of related or dependent objects without specifying their concrete classes.”

Birbiri ile ilişkili veya bağımlı nesneleri onların concrete (somut) sınıflarını oluşturmadan create edilmesini sağlıyor. Tasarım şablonunu uygulamak için  nesnelerin aynı abstract class veya interface ile oluşturulmuş olması gerekmektedir. Nesnelerin arayüzleri veya soyut yapıları ile ilgilendiği için yeni bir nesne eklemek nispeten kolaylaşıyor. Abstract factory sınıf uml yapısı gösterilmiştir;

abstract

 Bu tasarım desenini ev yapımını örnek alarak anlatacağım. Ev oluşturmak için Kapı, duvar ve çatı gibi sınıflar oluşturup bu sınıfları ev fabrikası soyut sınıfı üzerinde tanımlayarak, o soyut sınıfı kullanarak ev yaratılmaktadır.

  1- Kapı soyut sınıfı oluşturduk ve ondan türetilmiş 3 tane sınıf ürettik.

doorobject

2- Aynı şekilde duvar ve çatı için soyut sınıf ve onlardan türetilmiş sınıflar ürettik.

wallandroofobject

3- Evleri üreteceğimiz ev fabrikası soyut sınıfını oluşturduk. Bu soyut sınıfı içersinde kapı, duvar ve çatı sınıflarını üretmesi için soyut metod olarak tanımlama yaptık.

housefactory

4- Ev fabrikası soyut sınıfından 2 tane ev sınıfı (villa ve apartment) ürettik. Oluşturulan bu sınıfların içerisinde ev fabrikası soyut sınıfında üretilmiş soyut metodları override ile ezdik ve gerekli tanımlamaları yaptık.

5- Aşağıda bulunan estate sınıfı ev oluşturmak için kullanılır. Constructor içinde ev fabrikası, kapı, çatı ve duvar için kullanılacak sınıfların isimleri alınarak ev için uygun nesneler oluşturulmaktadır. Gerekli parametreler ile nesne oluşturmaları yapılıyor. Ardından oluşturulan ev tipi ve nesneler console.writeline ile ekrana basılacaktır.

 6- Öncelikle oluşturmak istediğimiz tipinin nesnesini oluşturuyoruz. Ardından ev oluşturma işlemi için estate sınıfı çağrılacaktır. Constructor içine gerekli parametreler yollanıyor. Bu parametreler tanımlanan ev nesnesi,kapı,çatı ve duvar isimleridir.

createabstraact

 7-  Ekran çıktısı aşağıda gösterildiği gibidir.

main

 

Ne zaman kullanmalıyız ?

  • Sistemin nesne üretiminden bağımsız olması gerektiği durumlarda,
  • Aynı arayüz veya soyut yapıdan oluşan bir sistem ise tercih edilebilir.

Kaynaklar:

SOLID Prensipleri

SOLID prensipleri, nesne tabanlı programlamada (OOP) ve tasarım mimarisinde kullanılan 5 tane prensiptir. Bu prensiplerin baş harfleri ile SOLID tanımı oluşmuştur. Kodun kolay anlaşılmasını sağlar. Bu prensipler ile loosely coupled (az bağımlı), reusability (yeniden kullanılabilinir) ve extendable (geliştirilebilir) mimari oluşturmamızı sağlar. Yazdığımız proje her zaman aynı kalmamaktadır. Projenin gelişime açık olması önemlidir. SOLID prensiplerine uygun yazılım projesi geliştirirsek projelerimiz her zaman esnek olur. Projenin kod bakımından ağırlaşmasının önüne geçer.

Bu prensipler bir hedef olarak düşünülebilir. Yaptığımız projeyi bu prensiplere mümkün olduğunca bağlı kalarak yazmaya çalışmalıyız.Aşağıda gösterilen resimde bu 5 prensip gösterilmektedir. Bunları kısaca anlatmayı düşünüyorum. Daha sonrasında her prensip ile ilgili örnekleri barındıran linkleri yazıya ilave edeceğim.

solid

  •   Single Responsibility Principle = Yaptığımız tasarım sade ve anlaşılır olmalıdır. Her sınıfın sadece tek bir görevi olmalı ve sadece o görevden sorumlu olmalıdır. Eğer bir sınıf için birçok görev tanımı yaparsak, ileride yapmak istediğimiz değişiklikler olunca işimiz zorlaşacaktır. SRP örnek

srp

 

  •  Open-Closed Principle = Bu prensip tanımına göre, tasarımımız gelişime açık değişime kapalı olmalıdır. Yarattığımız modüllerde kalıcı büyük değişiklikler yapmaktan ziyade hata düzeltme gibi kontrollü işlemler yapmalıyız. Büyük çaplı değişiklikler yapmak istediğimiz zaman mevcut kodda değilde o değişimi farklı bir modül üzerinden yapabiliriz. SRP ve OCP prensiplerini birbirlerinin tamamlayıcısı olarak görebiliriz. Her zaman bu değişimleri abstract sınıf veya interface sınıf kullanarak yapmalıyız. OCP örnek

openclosedprinciple

 

  • Liskov Substitution Principle = Liskov yerine geçme prensibi olarak adlandırılır. Bu prensibe göre alt sınıflardan oluşturulan nesnelerin, üst sınıfların nesneleriyle yer değiştirdiklerinde aynı davranışı göstermek zorundadır. Child sınıflar, base sınıfların tüm özelliklerini kullanmak zorundadır. Bu örnekte kapsamlı olarak anlatılmaktadır.

image

  • Interface Segregation Principle = Interface (Arayüz) ayırım prensibi olarak adlandırılır. Kullandığımız arayüze gereğinden fazla özellik eklersek, oluşturduğumuz modüller bunların hepsini kullanmaya ihtiyaç duymayabilir. Bazı özelliklere ihtiyaç duymayan modüller bu özellikleri gereksiz olarak eklersek kullanışsız bir tasarım olacaktır. Interface yapısında her modülün kullanmadığı özellikler bulunuyorsa yapmamız gereken oluşturduğumuz interface yapısını bölmektir. ISP örnek

oop-principles-14-638

 

  • Dependency Inversion Principle = Bağımlılığı tersine çevirme prensibidir. Üst seviye modüller alt seviyeli modüllere bağımlı olmamalıdır. Alt sınıflarda yapılan değişimler üst sınıfları etkilememelidir. Her iki seviyeli modülde soyutlamalara bağlı olmalıdır. Ayrıca soyutlamalar fazlaca detaya boğulmamalıdır. Üst seviyeli modüller, alt seviyeli modüller ile abstract yapılar veya interface yapıları ile ilişki kurmalıdır. DIP örnek.

 

 

Kaynaklar

Design principles , Overview of SOLID Principles in C# , Wikipedia , SOLID–Adım Adım Tanımak (video anlatım),

Dependency kavramı ile ilgili detaylı bir yazı

Software Design Patterns (Yazılım Tasarım Şablonları)

Herkese merhabalar. Yazılım dünyasında sıkça bahsedilen ve önemli olan yazılım tasarım şablonları ile ilgili yazı dizisi yazmaya karar verdim.

Yazılım tasarımı sırasında sıkça karşılaşılan problemlere çözüm için tasarlanmış yazılım şablonlarına denir. Birçok farklı durum için o problemi çözmek için tasarlanmış kalıplardır. Bu tanımlamalar kullanılarak yazılım tasarımı yapılmaktadır. Yazılımcıların sistem veya uygulama geliştirirken kabul ettiği en iyi tasarım alıştırmalarından oluşmaktadır.

Tasarım şablonları programlama dillerinden bağımsız olarak tanımlanmışlardır. Ancak nesne tabanlı dillerine uygun tasarım şablonları daha fazla yaygınlaşmıştır. Bu şablonlar nesneler ve sınıflar arasındaki ilişkileri ve etkileşimleri göstermektedir. Yazılımı yapacak olan kişi elinde olan soruna göre bu şablonları özelleştirerek kullanacaktır.

Test edilebilir ve kanıtlanmış bu yapıları kullanarak yazılım geliştirme sürecini hızlandırmaktayız. Kaliteli yazılım tasarımı yapmak için projeyi hayata geçirdikten sonra çıkacak problemleri yazılım geliştirme esnasında çözmeliyiz. Tekrar kullanılabilir tasarım şablonları ile oluşacak büyük sorunların önüne geçebiliriz.

Tasarım şablonları yazılım dünyasında,  (Design Patterns: Elements of Reusable Object-Oriented Software) adlı 1994 yılında yazılmış kitap sayesinde adından söz edilir hale gelmiştir. Kitabı yazan 4 yazar Gang of Four olarak adlandırılır.

Bu kitaba göre tasarım şablonları 3 gruba ayrılır;

  • Creational Patterns ( Yaratımsal Şablonlar )
  • Structural Patterns ( Yapısal Şablonlar )
  • Behavioral Patterns ( Davranışsal Şablonlar )

ooppatterns

Yukarıda gösterilen resimde her belirtilen tasarım şablonu grubunda kullanılan yaklaşımlar gösterilmektedir.

Creational Patterns ( Yaratımsal Şablonlar ):

Yazılım nesnelerinin nasıl yaratılacağı hakkında genel öneriler sunmaktadır. Mevcut duruma uyarlanarak nesne yaratma problemleri ile mücadele etmektedir. Düzensiz oluşturulan nesneler tasarım problemlerine yol açabilir. Nesne yaratımını kontrol ederek karmaşıklıkları önleme amacındadır. Uygulamaya nesne oluştururken esneklik katmaktadır. Asıl amacı, iyi bir yazılımın içinde barındırdığı nesnelerin nasıl yaratıldığından bağımsız tasarlanması gerekliliğidir.

Modern yazılım geliştirmede nesnelerin birbirleri arasında oluşan ilişki önemlidir. Herhangi bir şablon olmadan oluşturulan büyük yazılım modelleri, yeni bir özellik eklenmek istediği zaman veya eklenecek yeni bir özellik olduğunda işlemi zorlaştıracaktır. Ayrıca yeniden kullanılabilirik imkanı azalacaktır.

Ne zaman sisteme eklememiz düşünülebilir?

  • Sistemin nesne yaratımlarından bağımsız olması gerektiğinde
  • Birbiri ile bağı olan nesneleri kullanacağımız zaman
  • Nesneleri nasıl oluşturduğumuzu gizlemek istediğimiz zaman ve sadece oluştukları interfaceleri göstermek istediğimizde.
  • Sınıfların örneklemelerinin çalışma zamanında tanımlanması
  • Temelde tek bir sınıf instantination varsa ve kullanıcı sürekli bu örneklemeye erişmek isterse

Aşağıda gösterilen sınıf diyagram birçok yaratımsal tasarım şablonunda ortaktır.

Creator = Nesne arayüzünü tanımlar ve nesne döndürür.

ConcreteCreator = Nesne arayüzünü implement etmektedir.

Creational_Pattern_Simple_Structure

Structural Patterns ( Yapısal Şablonlar )

Yapısal tasarım şablonları ile dizaynı kolaylaştırarak sınıflar arasındaki iletişimi düzene sokmak için kullanılırlar. Sınıflar ve nesnelerin büyük yapıları nasıl oluşturacağı tanımlanır.

Behavioral Patterns ( Davranışsal Şablonlar )

Nesnelerin davranışları ve birbirleri ile olan ilişkileri ile ilgilenir. Davranışsal şablonları kullanılarak nesnelerin birbileri ile olan iletişimin esnekliği artmaktadır.

Tasarım şablonlarını tanıtarak giriş yapmış olduk. Sonraki yazılarımda Yaratımsal şablonlardan başlayarak, her grupta bulunan yaklaşımları örnekler ile anlatmaya çalışacağım.

Yararlandığım kaynaklar:

Software design pattern

Design Patterns: Elements of Reusable Object-Oriented Software