6 min read

Katmanlı mimari (n-layer / n-tier architecture) nedir?

Bir monoliti hem mantıksal, hem de fiziksel olarak bölümlere ayırarak, böl-ve-yoket yaklaşımı ile katmanlı mimariye çevirebiliriz.
Katmanlı mimari (n-layer / n-tier architecture) nedir?

Katmanlı mimariyi anlayabilmek için öncelikle, katmanlı mimari kullanılmayan bir yazılımı incelemek gerekir. Çünkü katmanlı mimari dediğimiz yöntem, monolit şeklinde yani parçalara bölünemeyen bir programın yaşam döngüsünde karşılaşılan zorlukların analiz edilmesi sonucu ortaya çıkmış bir çözümdür. Bir monoliti hem mantıksal, hem de fiziksel olarak bölümlere ayırarak, böl-ve-yoket yaklaşımı ile katmanlı mimariye çevirebiliriz.

Şunu belirtmek isterim ki, "katmanlı mimari tek ve mükemmel bir yöntemdir" diyemeyiz. Üstelik bazı senaryolarda katmanlı mimariyi tercih etmeniz gereksiz yere zaman ve emek kaybına neden olabilir. Bu yüzden katmanlı mimarinin sadedce sık görülen bir probleme önerilmiş olan ve beğenilen bir yaklaşım olduğunu hatırlamakta fayda var.

Her şey küçükten başlar.

Bir proje düşünün, son derece basit bir amaçla yazılmış olsun. Örneğin, küçük çaplı bir ticari işletmenin web sitesi için yazdığınız bir ASP.NET MVC uygulamasını düşünelim. Basit bir veritabanınız oluşturup burada verilerini sakladığınız dinamik bir MVC web uygulaması yazdınız.

Ve proje büyür..

Zaman geçtikçe projeye yeni eklemeler yapmanız istendi. Yeni eklemeleri yapıp, derleyip projeyi deploy ederek başarıyla güncellediniz. Derken işletmenin yeni ihtiyaçları için bazı ek uygulamalar da yapmanız istendi. Örneğin satış ve pazarlama ekipleri için tabletlerinde görebilecekleri yönetim programları, insan kaynakları ve muhasebe çalışanları için yardımcı uygulamalar, vb. Uygulamanın çapı büyüdükçe projede size yardımcı olacak ekip arkadaşları aramaya çıktınız.

Neyse ki güvenilir iki kişi ile anlaştıktan sonra, projeyi bir versiyon kontrolü sistemine yükleyerek artık 3 kişilik bir ekip halinde geliştirmeye devam ettiniz. Derken işletme sahibi diğer işletmeleri için de bu projenin benzerlerini yapmanızı talep etti. Proje ekibini 6'ya çıkarıp, aynı projenin benzerlerini yazdırmaya koyuldunuz.

Bu noktada bazı işlemlerinizde kullandığınız ORM'nin yetersiz kaldığını farkettiniz ve bazı uygulamalarda kullandığınız ORM'leri değiştirmeye karar verdiniz.

Ah keşke: yazılımda kelebek etkisi

Bu aşamada farkedeceğiniz bir "keşke" olacaktır: bu proje keşke modüler bir yapıda olsaydı. En ufak bir değişiklik gerektiğinde, herhangi bir kişi sadece o kısmı değiştirir, gerisine hiç bakmasına gerek bile kalmazdı. Şimdi ise en ufak bir değişiklikte bütün projeyi baştan aşağıya test etmek iyice can sıkıcı bir hal almaya başlamıştır. Hatalar ve takip edilemeyen bug'lar çıkmaya başlar, üstelik bir bug'ı düzelttiğinizde genellikle bir başka noktada aklınıza bile gelmeyecek bir işlemi bozmuşsunuzdur. Zaman kısıtlaması ve projenin gitgide karmaşıklaşması bunları bırakın düzeltmeyi, takip bile edilemez hale getirmiştir.

Sıkı ve gevşek bağlılık (tight coupling vs loose coupling)

Burada gördüğünüz problemin kaynağı "bağlılık" (coupling) tır. Sıkı bağlılık (tight coupling), bir yerde yazdığınız kod parçalarının başka yerdekileri direkt olarak çağırması ile sanki bir örümcek ağı gibi birbirine bağlantı hatları kurması anlamına gelir. Bunun sonucunda bir noktada yaptığınız değişiklik bir kelebek etkisi gibi ona bağlı olan diğerlerine, oradan da bağlı olan başkalarına etki edecektir. Bunun da takibi ve kontrolü bir noktadan sonra imkansız hale gelmeye başlar.

Bu problemin çözümü gevşek bağlılıktır (loose coupling). Bu yöntemde bağımlılık kodlar arasında direk hatlar ile sağlanamaz, sadece belirli noktalarda sağlanabilir. Bir benzetmeyle açıklarsak, ülkeler arasındaki gümrük geçişlerinde olduğu gibi bağımlılıkları belirli noktalarda toplayarak, takibini ve idaresini çok kolaylaştırmış oluruz.

Ülkelerde gümrük kapıları olmasaydı her sınır kasabasına yüzlerce hatta binlerce jandarma yerleştirmemiz gerekirdi. Aynı şekilde sıkı bağımlılıkta olduğu gibi kodlarınızı diğerlerini direkt olarak çağırmakta özgür bırakırsanız, belki de yüzlerce ya da binlerce noktaya kontrol koymanız gerekir.

1.Bağlar nasıl gevşetilir: mantıksal soyutlama

Peki teoride anlaşılmış olabilir, fakat uygulamada bunu nasıl yapabiliriz? Yani sıkı bağlarla yazılmış bir programın bağlarını nasıl gevşeteceğiz? Burada ilk olarak interface kavramına başvururuz: "program to an interface" adı verilen tasarım desenini hepimiz biliyoruz. İşte bu desenin esprisi burada devreye giriyor. Bir metot çağırırken tip olarak somut sınıflar yerine soyut interface'leri kullandığınızda, sıkı bağlar gevşek hale gelir.

Eğer siz kodlarınızda bir sınıfı ismiyle değil de, onun ait olduğu bir interface adını vererek çağırırsanız, yıldızlı bir "pekiyi"yi hak ettiniz demektir. Çünkü bundan sonra çağırdığınız sınıfta nasıl bir değişiklik yapılırsa yapılsın (hatta belki çağırdığınız sınıfın yerine başka sınıf bile getirilmiş olabilir - onu DI başlığı altında göreceğiz) sizin açınızdan hiçbir problem yaşanmayacaktır.

Ah keşke: koduma dokunma

Projenize istek üzerine yeni projeler ilave ettikçe kod tekrarı yaptığınızı da görürsünüz. Bazı şeyleri devamlı kopyala-yapıştır kullanarak veya hafızadan yeniden yazmışsınızdır. Keşke bunları toplayıp ayrı birer kütüphane olarak yazsaydınız, tek yapmanız gereken yeni projelerde bunlara referans vermek olacaktı.

Üstelik sık kullandığınız kodların birinde bir düzeltme yaptığınızda, daha önceden aynı yeri kopyaladığınız diğerlerini elle arayıp, bulup düzeltmeye çalışmak da büyük bir zaman ve emek kaybıdır. Oluşacak hataların takibine ise hiç girmeyelim..

Bütün bunların üzerine bir de 5-6 kişinin bu projelerin üzerinde devamlı geliştirme yaptığını düşünelim. Ve bir kişinin yaptığı bir güncelleme yüzünden diğerlerinin 3 günlük emeğinin yerle bir olduğu, durduk yere doğru çalışan projelerin hata vermeye başladığı, haliyle geliştiriciler arasında kavga çıktığı durumlar da görülmeye başladıysa, katmanlı mimariye bir şans verme zamanınız gelmiş demektir.

Buradaki "keşke"nin çözümü programı çeşitli kütüphaneler olacak şekilde, yani fiziksel olarak bölmektir. Bu şekilde her ekip kendi projesi üzerinde çalışıp test edecek, ve bir ekibin yaptığı iç değişiklikler sanki bir kara kutu gibi diğer ekipler için görünmez olacak. Kütüphaneler aynı şekilde kullanılmaya devam edileceğinden, kullanan ekipler bundan etkilenmeyecek, hatta değişiklik olup olmadığından haberleri bile olmayacak. Testler de kolaylaşacak ve bir hatanın hangi bölümden kaynaklandığını tespit etmek çok kolaylaşacak.

Buradaki bir avantaj da şudur: buna benzer başka projeler yapmanız gerektiğinde burada kullandığınız bölümleri aynen kullanabilirsiniz. Örneğin sadece arayüzü veya iş mantığı bölümlerini değiştirerek zamandan büyük bir kazanç elde edersiniz.

2.Proje nasıl modüler hale getirilir : fiziksel bölümleme

Buraya kadarki her şey tamamsa, yani bağlantıların uç noktalarını sınıflar yerine interface'lere bağlayarak gevşettiyseniz, bundan sonra projenin zaten belirgin parçalara bölünmeye başladığını görebilirsiniz. Veritabanı işlemleri, bazı iş mantığı kısımları, arayüz kodları bir bakışta ayrı birer küme gibi görünmeye başlar. İşte burada bıçağı vuracağımız noktalar, iki farklı bölüme ait olduğu belli olan kodların birbirini çağırdığı noktalardır.

Katmanlı mimari ile bir projeyi bölerken, kodların hangi amaca hizmet ettiğine bakarak işe başlarız. Genelde veri erişimi, iş mantığı ve sunum / kullanıcı arayüzü katmanları yeterli olur.

Veri katmanı

Projenizde kullandığınız modeller ve veritabanı işlemlerini düzenleyen sınıflar bu kütüphanede yer alır. Başlangıç projemizde controller içerisinde veritabanına getir, ekle, sil gibi emirler veriyorduk. Artık bunları ayrı birer sınıf yazarak veri katmanına göndermemiz gerekiyor.

İş katmanı

Arayüz ile veri katmanı arasında yapılacak işlerin detaylarının bulunduğu sınıflar bu kütüphanede bulunur. Genelde herşeyin controller içine yazıldığı monolit uygulamalarda bu kodların çıkarılıp ayrı sınıflar halinde bu katmana aktarılması gerekir.

Sunum katmanı

Projenizde kullanıcının gördüğü ekranları tanımlayan her şey bu uygulamada bulunur. Bu katmanda kesinlikle veritabanı veya iş mantığı bulundurmamak gerekir ki yaptığımız bölümleme işlemi boşa gitmesin.

Örneğin MVC uygulamasında sadece iş katmanında gelen verileri view'lara aktararak gösterilmesini sağlayan controller'lar bulunmalıdır. Yani başta her şeyi içerisinde tanımladığınız controller'lardan iş mantığı ve veritabanı kodlarını çıkardığımızda geriye kalanlar sunum katmanı için yeterlidir.

Son söz.

Bu yazıda katmanlı mimarinin ne olduğunu ve bize hangi açılardan yardımcı olabileceğini gördük. Unutmamak gerekir ki mükemmel çözüm diye bir şey yoktur. Siz de kendi senaryonuza göre katmanlı mimari uygulayabilir, belki 5-6 katman kullanabilirsiniz. Önemli olan kullandığınız bu yöntemin sizi zaman ve emek israfından kurtarmasıdır.

Eğer bu avantaj sizin senaryonuzda yoksa veya çok azsa, katmanlı mimari uygulamayabilirsiniz. Burada son kararı her zaman maliyet analizi üzerinden vermeniz doğru olacaktır. Yani attığınız taş ürküttüğünüz kurbağaya değecek mi, bundan emin olarak hareket etmenizde fayda var.

Devam yazısında DI yani Dependency Injection ile bu katmanların bağımlılığını sanki bir duvar örermiş gibi kesin bir ayrımla iyice zayıflatacağız. Hiç bir katmanın kodu, bir diğerini direkt olarak çağıramayacak. Bu sayede tam anlamıyla ölçeklenebilir bir katmanlı mimari yapmış olacağız. Bir sonraki yazıda görüşmek üzere, hoşçakalın.