Enis Kurtay YILMAZ

C# Örneğiyle: Katmanlı Mimari de Ne?

Her projemizde veya her fikrimizde ilk bu canlanıyor, “Nasıl yapsak?”, Veri buradan gelir, bunu da buradan set ederim, diğer tarafa implement etmen kolay ama sanki şurada bir sorun var..”.

Günün sonunda bir şekilde kod yazmaya başlıyoruz, uygulamamız için bir başlangıcı öyle ya da böyle yapıyoruz. Fakat herkesin bir şekilde kullandığı, özellikle hiç bilgisi olmadıklarını gözlemlediğim genç arkadaşlara katmanlı mimariyi dilim döndükçe anlatmak istiyorum.

Sürç-i lisans edersem, affola.

Hangi makarnayı seversin? Spagetti mi, Lazanya mı?

Spagetti vs Lazanya

Öğrenci olanların hemen zihninde canlanmıştır. Kettle’a sıcak su koy, hemen spagetti makarnaları at içerisine 15–20 dk sonra hazır. Fakat yedikçe makarnalar iç içe geçer. Lazanya da ne ki? Çok uğraştırır. Kat kat yapacaksın, Unu ayrı, kıyması ayrı, fırını ayrı, gırla mevzu var ama çok lezzetlidir değil mi?

Bunlar çipetpet ama lezzetli çipetpet değil..

İşte bizim aradığımız koddaki lezzette bu olmalı, Lazanya gibi kat kat yapacağız. Katmanlı mimari yaklaşımı ile unu ayrı, kıymayı ayrı, fırını ayrı hazırlayacağız ve lezzetli bir ürün çıkaracağız.

Katmanlı mimari için çokça yaklaşım var. Orion Architecture, N Tier Architecture aslında hepsinin çıktığı daha doğrusu anlatmak istediği nokta ortak. Yapıları ayır, SOLID prensiplerini uygula, uygulama içerisinde kafasına göre erişilmesini engelle, herkes kendisine ait işi yapsın (single responsibility principle) ve alt-üst ilişkilerini koru. Aslında mevzu bu kadar basitken nasıl uygulayacağız?

(SOLID için ayrı bir makale yazacağım)

Mahşerin üç atlısı: Presentation, Business, Data

Bir uygulamada aşağı yukarı talep edilen şeyler bellidir. Hemen hemen her projede ilgili işin kapsamına bağlı olacak şekilde; belirli bir iş kuralı olur. Bu iş kuralına göre belki veri(leri) sisteme kayıt edilir ve belki kullanıcı(lara) verileri gösterilir.

Kodları indirmek için: https://github.com/eniskurtayyilmaz/TeacherManagement

Hatta şöyle örneklendirelim: Bir web sitemiz var, içerisinde öğretmenleri kayıt ediyoruz ve öğretmenlere ait dersleri de yöneten bir öğretmen-ders sistemimiz olsun. Buna Öğretmen Bilgi Sistemi (ÖBS) diyelim.

Konuyu anlamak için bazı noktalar Best Practice değildir. Örneğin katmanlar arası model dönüşüm-geçişler, web request modellerinin yaklaşımı, Dependency Injection göz ardı edilmesi.

  1. E tabii yöneten bir şey derken, demek ki uygulamayı kullanacak kişilere bir şeyler göstermeliyiz. (Sunum Katmanı — Presentation Layer)
  2. Biz bu verileri kafamıza göre gelişi güzel koymayacağız ya, bir kontrol etmek gerekir. (İş Katmanı — Business Layer)
  3. Veriyi nerede tutacağız? (Veri Katmanı — Data Layer)

Kafadan yapıyı ayırmaya başladık bile. Ancak buradaki en önemli şey var. Bir kod bloku içerisine spagetti tarzında upuzun kod yazmamamız gerektiği. Yani web sayfasını göstereceğimiz ilgili controller içerisinde aşağıdaki örnekteki gibi DbContext’i çağırarak, hem validation, hem de CRUD işlemlerini yapmayacağız.

Asla Böyle Spagetti Kod Yazmıyoruz — Single Responsibility Prensibine Aykırı

Sakın yukarıdaki resmi dikkate alıp, bu şekilde geliştirme yapmayınız 🙂

Bizim asıl öncelikli amacımız yapıları ayırmak. Görsel de göreceğiniz gibi önce yapılarımızı ayıracağız

Mahşerin Üç Atlısı: Sunum, İş, Veri katmanı

ÖBS’de bizim yapımız bu görselde gibi olacak, yapılar ayrı, herkes kendi alanından sorumlu hale getireceğiz. Burada belirli kriterimiz olacak:

  1. İlgili işleme ait web sayfasına gelen istek parametreleri var ise (Adı, Soyadı veya Pagination’a ait aktif kayıt numarası vb.), bunu bir model olarak geliştirmeli ve Presentation katmanında tanımlanmalı (Örn. TeacherWebInsertRequestModel, CourseWebUpdateRequestModel, TeacherWebViewResponseModel) — TeacherManagement.Presentation

2. Gelen isteğe ait modeli belirli bir iş kuralına göre hesaplayacak, kontrol edecek veya veri tabanına kayıt edilmesini isteyecek isek, o zaman bunu Business katmanında yapmamız gerekiyor. Örneğin bir veri tabanına kayıt için önce bizim bir validation yapmamız gerekiyor.

Presentation tarafındaki modeli, Business katmanına gönderebilmek için, Business katmanına özgü RequestDTO ve ResponseDTO nesneleri de oluşturmalıyız. Tabii bunlar ilgili işleme ait ilgili metot(lar) için olmalı ve bu metot(lar) ilgili sınıfta tutulmalı, Presentation katmanı sadece Interface üzerinden erişmeli.

Business katmanındaki kod bloğu
Presentation Katmanından Business Katmanına Transfer (Automapper daha iyi çözüm olabilir sizin için)

3. Verileri bir veri tabanına veya bir web servis üzerinden bir yerlere kayıt edeceksek, bunu Data katmanında yapmamız gerekir. Tabii buna özgü de modellerimiz olmalı. Eğer bir web servisi web reference olarak eklediyse, bu iş çok kolay. Ama veri tabanındaki bir tablo ise, o zaman bunu tabloya özgü hale getirmemiz lazım. Unutmayın, yapacağımız Data katmanı, Business katmanı tarafından sadece Interface üzerinden erişmeli. Yalnız buradaki modellerimiz genelde yapımızın son noktası olduğu için, metot içerisine her metoda özgü bir model yapmamıza gerek kalmayabilir.

Data katmanındaki Teacher nesnesi, veri tabanında tutulan tablomuzun bir modeli aslında
Data katmanına erişecek kişinin kullanacağı metotlar.

Eğer repository kısmını bile GenericRepository yaklaşımında bir şeyler yaparsanız; bugün X veri tabanından, yarın Y veri tabanına geçişinizi bile rahatça yönetebilirsiniz. Hatta Generic Class yaklaşımı sayesinde BaseEntity’den türeyenleri sadece dikkate al bile diyebilirsiniz (10 puanlık bir yaklaşım, araştırınız lütfen)

Business katmanından Data katmanına geçişin son durumu.

Yukarıdaki görselde gördüğünüz gibi Business katmanından, Data katmanına geçişimiz ve ilgili modelimizin veri tabanına aktarımını gerçekleştirdik.

Buradaki asıl mesele, katmanlara arasında ilgili üst katmana ait veri modelinin alt katmana göre hazırlanması ve veri modellerinin dönüşümü.

“İyi de biz neden modeller yaratıyoruz ki, direk veri tabanına veya web servise gitsek olmaz mı?” dediğiniz duyar gibiyim.

Olmaz.

Çünkü biz katmanları ayırtmakla mükellefiz. Ayrıca bunun yönetimi daha kolay oluyor.

Diyelim ki bu projemize öğretmene ait dersleri de tutmak istiyoruz. Bakalım faydasını görebilecek miyiz?

  1. Data katmanında Course diye bir model oluşturalım ve CourseRepository’de CRUD işlemlerini yapalım.
Course modelinin içeriği
Data katmanında yer alan Course nesnesinin veri tabanına CRUD işlemleri

2. Business katmanında iş kuralımızı yönetelim. Fakat iş kuralımız ne olacak? Mesela her dersin bir öğretmeni olur, değil mi? O zaman dersi sisteme kayıt ederken önce Business katmanında öğretmenin varlığını kontrol etmek lazım?

Course için hazırlanan Business katmanında, Teacher Business nesnesini kullandık ve kontrollerimizi yaptık.

3. Business katmanındaki derse ait veri dönüş nesnemize eklenen öğretmen bilgisini dönmek istersek? O da kolay..

Course için hazırlanan Business katmanında, Teacher Business katmanından dönen ResponseDTO modelimizi kullandık.

4. Presentation katmanında dersi kaydettikten sonra, kursa ait öğretmenin sistemdeki Id bilgisi vermek zorunda mıyız, sadece full ismini gösterse diyebilirsiniz. Hani belki “….. derse ait ….. öğretmene kaydınız yapılmıştır” gibi bir mesaj çıkarmak için yeterli olabilir. İşte Presentation katmanındaki response modelimiz bu günler için var 🙂

Presentation katmanındaki InsertCourse metoduna özgü bir response model yazdık.

Kişisel Blog Adresim: eniskurtayyilmaz.com

Twitter Adresim: ekurtayyilmaz

Kaynak Kodlar: https://github.com/eniskurtayyilmaz/TeacherManagement