Tasarım Kalıpları – I: Giriş

Tasarım Kalıpları (Design Patterns), uzun süredir en hararetli ve en saygın kavramlardan addediliyor, kaliteli programlamanın, gerçek nesne-merkezli yazılım geliştirmenin olmazsa olmazlarından görülüyor. Yersiz bir anlayış da değil tabi. Ben de uzun süredir bu konuda yazmak istiyordum. Hatta bu yazıya çok önce başladım ama yayınlanması bugüneymiş.

Tasarım Kalıpları, Design Patterns’in dilimizdeki bir kaç karşılığından birisi. “Design”in “Tasarım” olarak çevrilmesinde problem yok. Peki ya “pattern”i nasıl çevirmeli? Asıl derdim tabi olarak bu kelimenin nasıl çevrileceğinden çok anlamıdır. Şöyle anlatabilirim İngilizce’deki pattern kelimesinin anlamını: Ben ufakken devamlı annemin bana ördüğü kazakları ve süveterleri giyerdim. Annem hamarat bir kadındır ve dikiş, örgü vs. konularında da eğitimlidir. Çok sıklıkla, sokakta giderken kadınların beni durdurup, “örneğini” almak için kazağımı incelediklerini hatırlarım. Kadınların benim kazağımdan almaya çalıştıkları şey, bizim dilimizde “örnek”, İngilizce’de ise “pattern”dır. Zaten Mariam-Webster sözlüğündeki açıklamalardan birisi de “something designed or used as a model for making things <a dressmaker’s pattern>” şeklindedir. Bu yüzden model kelimesi belki daha iyi karşılardı “pattern”ı. Bu anlamda bence kalıp, desen ya da şablon anlamlı ve uygun çevirilerdir. Ama örüntü gibi kelimelere alışamadığımı belirteyim.

Yazılım dünyasına bu kelimenin girişi yazılımcılarla değil Christopher Alexander isimli bir mimar ile oldu. Kendisi yüzyıllar boyunca insanlığın bina ettiği yapılardaki mimari özellikler üzerine çalışırken “design pattern” kavramını geliştirdi. Alexander tasarım şablonları ile ilgili olarak şöyle demektedir: “Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.

Bu güzel tanımı dilimizde ifade edecek olursak: “Her bir kalıp (önce) ortamımızda tekrar tekrar olan bir problemi tanımlar ve sonra da bu problem için çekirdek bir çözümü tarif eder öyle ki siz bu çözümü bir milyon defa kullansanız bile, hiç birisini aynıyla iki defa kullanmazsınız.

Bu anlamda tasarım kalıbi, bir bağlamda sıklıkla karşılaşılan tasarım problemine genel (generic), soyut (abstract) ve tekrar kullanılabilen (reusable) bir çözümdür. Tasarım kalıpları soyutturlar, diller seviyesinde değil tasarım seviyesinde ifade edilirler. Bundan dolayı tasarım kalıpları anlatılırken sıklıkla class ve sequence diyagramlarını kullanırız. Tasarım kalıpları soyut olduklarından, her uygulanmalarında, bağlama ve ihtiyaca göre şekillendirilirler. Bu yüzden aynı tasarım kalıbını defalarca uygulasanız bile hiç bir iki uygulamanız birbirisinin aynısı olmayabilir.

Tasarım kalıpları, temel nesne-merkezli prensipleri kullanarak doğru sorumlulukları bulmamıza (finding responsibilities), değişimi göz önüne alarak bu sorumlulukları nesnelere dağıtmamıza (highly-cohesive objects) ve nesneleri, aralarında az bağımlılık olacak şekilde (lowly-coupled objects) kurgulamamıza yardımcı olur. Bir başka deyişle tasarım kalıpları, yüksek birliktelikli ve düşük bağımlılıklı yapıları nasıl kurgulayacağımızı, sıklıkla karşılaşılan problemler bağlamında, model olarak ortaya koyar. Bu anlamda tasarım kalıplarını kullanmadan doğru düzgün bir tasarım yapamayız desek sanırım abartmış olmayız. Çünkü tasarım kalıplarının çözdüğü ve bir kısmını hemen aşağıda sıraladığım problemler, her ortamda sıklıkla karşımıza çıkan problemlerdir.

Tasarım kalıplarının modelledikleri problemlerden bazıları şunlardır:

  • Nesneleri nasıl yaratırız?
    • Karmaşık nesneleri nasıl yaratırız?
    • Nesne ailelerini nasıl yaratırız?
  • Bir sınıftan sadece bir ya da belirli sayıda nesne nasıl yaratırız?
  • Nesnelere erişimi nasıl kontrol ederiz?
  • Nesneler arasındaki bütün-parça ilişkisini nasıl tasarlarız?
  • Bir işi yapmanın pek çok yolu varsa bunları nasıl ifade ederiz?
  • Emir-komuta ya da olay-bilgilendirme zincirini nasıl oluştururuz?
  • Bir sürü nesne arasındaki haberleşmeyi nasıl yönetiriz?
  • Bir nesneye çalışma zamanında yetkinlik nasıl kazandırırız?
  • Karmaşık duruma sahip olan nesneleri nasıl yönetiriz?
  • Nesnenin durumunu nasıl saklar ve sonra yine ulaşırız?
  • Birden fazla nesneyi nasıl yönetiriz?
  • Aynı işi birden fazla nesneye nasıl uygularız?

Bir tasarım kalıbının temelde dört bileşeni vardır:

  • İsmiki o şablonu, problemi ve çözümüyle birlikte ayırt etmemizi sağlar,
  • Problem ki hangi bağlamda nasıl ortaya çıktiğını ifade eder,
  • Çözüm ki parçaları ve aralarındaki ilişkileri ifade eder,
  • Sonuçlar ki kazanılan ve kaybedilenleri ifade eder.

Tasarım kalıpları çoğu defa bize, normalde nesne-merkezli programlama dili kullanmamıza rağmen prosedürel anlayışla yazılım geliştirmeye düşmekten kaçınmamızı sağlar. Bu yüzden normalde tek bir metot altında pek çok “if” ile yaptığımız “functional decomposition” tarzındaki yapıları, nesne seviyesinde nasıl ifade edeceğimizi bize öğretir.

Aslında “tasarım kalıpları” kavramı yayıldıktan sonra sadece tasarımın değil farklı konuların da kalıpları ortaya çıkmaya başladı. Bu sebeple “security patterns”, “performance patterns” gibi kavramlar oluştu. Bu anlamda ele aldığımız “tasarım kalıpları”, karmaşıklığı ve değişimi yönetmek amacıyla oluşturulmuş, iş alanından ve mimari katmanlardan bağımsız modellerdir. Programlama dillerine has tipik kullanımlar ya da kalıplar da mevcuttur. Örneğin Java’da bir Map nesnesinin üzerindeki değerlerin alınması için yaptığımız tipik işlemler vardır. Bu gibi dile özel yaklaşımlara, kalıplara “idiom” denir.

Tasarım kalıpları tipik olarak sınıf seviyesinde ifade edilirler. Mimari kalıplar ise daha çok modüller ve katmanlar (layer/tier) bazında ifade edilirler.  Örneğin Model-View-Controller (MVC) mimari bir kalıptır. Ayrıca mimari kalıpların, tasarım kalıplarından beslendiği de söylenebilir.

Tasarım kalıplarını şu amaçlarla öğreniriz:

  • Tekerleği yeniden keşfetmemek, var olan ispatlanmış çözümleri kullanmak. Tasarım kalıpları yukarıda saydığımız ve sayamadığımız problemleri çözerek, tekrar kullanılabilen, faydası ispatlanmış modeller ortaya koyar.
  • Formal ve yaygın bir dil oluşturmak. Tasarım kalıpları, formal bir kalıp dili (pattern language) oluşturmaktadır. Bu dilin yazılım geliştiriciler arasında yayılması, anlaşmayı kolaylaştıracak, ifade gücümüzü arttıracaktır.
  • Tasarıma uygun, yüksek soyutlama gücü kazandımak, detaylardan sıyrılıp, daha yüksek hedefler cinsinden düşünmek. Bu anlamda tasarım kalıpları daha iyi bir yazılım geliştirici hatta mühendisi olmanın en temel gerekliliklerindendir.

Tasarım kalıpları üzerine ilk çalışmalar, yukarıda da bahsettigim gibi Christopher Alexander tarafindan yapılmıştır. Sonrasinda Trygve Reenskaug, Smalltalk’la MVC (Model-View-Controller) üzerine çalışmışlardır. Benzer şekilde 80’li yıllarda Kent Beck ve Ward Cunningham, Smalltalk ile tasarım kalıpları uzerine calışmalar yapmışlardır. 1994 yılında ise Gang of Four (GoF) – Dörtlü Çete olarak adlandırılan Eric Gamma, Richard Helm, Ralph Johnson ve John Vlissides, ünlü “Design Patterns” kitabını yazmışlardır.    

Dörtlü çete kitaplarında 3 farklı kategoride toplam 23 tane kalıba yer vermişlerdir:

  • Creational – nesneleri yaratmakla ilgili olan 5 tane,
  • Structural – nesneler arasindaki yapısal iliskileri ifade eden 7 tane,
  • Behavioral – nesnelerin çalışma zamanı davranışlarını değiştirmek için 11 tanedir.

Sonrasında çıkan kitaplarda başka şablonlara da yer verilmiştir ama genelde tasarım kalıpları denince bu 23 tanesi anlaşılır.

Şimdilik burada bırakalım. Sonraki yazılarda bu konuya devam ederiz.

Bol tasarımlı ve dahi kalıplı günler dilerim 🙂

Toplam görüntülenme sayısı: 6242