3 Mayıs 2025 Cumartesi

N Layer - Clean Mimari - Moduler Monoltic -

 N Layer

Bir uygulamanın componenetlerini her biri belirli görevlerden sorumlu ayrı katmanlara ayıran bir yazılım tasarım desenidir. Bu mimaride, her katman yalnızca endişelerin net bir şekilde ayrılmasıyla katmanlarla iletişim kurar. Katmanlı mimarinin temel amacı, benzer işlevlere sahip bir uygulamanın componentlerini yatay mantıksal katmanlara ayırmaktır. Benzer componenler genellikle aynı katmanlara yerleştirilir. Katmanlar birbirinden izole olduğu için bir katmanda yapılan değişiklik diğer katmanları etkilemez. Bu bir monolitic uygulamadır.




Sorun: Yukarıdaki görsele bakarsak UI Katmanı Business katmanına, Business katmanı ise Data Access katmanına bağımlıdır.Business Katmanı, Dataları almak için yada Veritabanına data kaydetmek için Data Access katmanına talepte bulunur. Bir çok bussines logic, Store procedurlerde bulunur ve Data access katmanı bu store procedureleri execute eder. Store procedurlerin execute edilmesi sonucu elde edilen result Business katmanına, Business katmanından da UI katmanına return edilir.

 Katmanlar birbirine yüksek oranda bağımlıdır. Katmanların birbirine sıkı şekilde bağımlı olması kodun zamanla sürdürülebilirliği ve değişiklik yapılmasını zorlaştıracaktır. Örneğin Data Acces katmanında kullanıdğımız bir ORM toolunu yeniden düzenlemek veya değiştirmek istersek bu bizim için  zor olacaktır. Bussiness katmanında da değişiklik yapmamız gerekir.


Yukarıdaki görseli incelersek eğer Repository altındaki DecreaseProductsQuantity metodu product'ın QuantityOnHand metodu üzerinde işlem yapıyor. Burada Business logic'e ait olan bir rule İnfrastructure katmanı altında bulunan ProductRepository clası içerisinde yapılıyor. Bu bussiness rule buradan alınıp Product entity sınıfına taşınmalıdır. Eğer taşınmazsa bu yapıda uygulamamız sıkı bir şekilde Data access layera bağımlı olur.

Çözüm: Katmanlar arasındaki bağımlılığı gevşek bağımlı olacak şekilde düzenlemeliyiz. Dependency injection ve İnterface adapterlar kulanarak n-layer mimariyi clean arthitecture dönüştürebiliriz.



Clean Arthitecture

Gevşek bir şekilde bağlanmış bağımsız katmanlar elde etmemizi sağlar. Bu da bize kodumuzu kolayca test edebilmeyi ve üçüncü taraf kütüphaneleri kolayca değiştirebilmemizi sağlar. N - layer arthitecturede Data Access katmanındaki ORM tooluna olan bağımlık burada giderildi. 

İç katmanlar dış katmanlar hakkında hiç bir bilgiye sahip değildir(Dependency Rule). Domain katmanında belirtilen interface adapterlar, infrasttucture katmanında implemente edilir. Böylece Infrastructure katmanında, Domain katmanında belirtilen interfaceleri implement eden üçüncü taraf kütüphaneler oluşturulabilir. Bu üçüncü taraf kütüphane değişikliği domain katmanını hiç bir şekilde etkilemez.  Bu bir monolitic uygulamadır.



Application katmanı tarafından expose edilen interfaceler, İnfrastructure katmanı tarafından implement edilir. İnfrastructure katmanı altında DependencyImjection extention sınıfı içerisinde bu DI bağımlılıkları yer alabilir. Infrastructure altındaki DependecnyInjection extention clası UI katmanı altındaki program.cs altına eklenmesi gerekebilir. Bu yüzden UI katmanının infrastructure katmanına bağımlı olduğu durumlar olabilir. Kesik çizgi ile gösterilmiştir.


DecreaseQuontityOnHand Business Rule, Product Entity clası içerisinde yapılıyor. Business Rule infrastructure altındaki ProductRepository kısmından alınıp Product Entity clasına taşındı.



Aşağıdaki görselde de ProductRepository içerisinde Product clası içerisinde bulunan DecreaseQuontityOnHand  metodu call ediliyor. Bunun bize en büyük faydası business rule'lar infrastructure katmanınan alınıp Domain katmanındaki Entity sınıflarına taşınmış oluyor. Böylece business rulelar Infrastructure katmanında olmayacak ve biz de clean arthitectureyi sağlamış olacağız.  Amacımız business ruleları gerçekten Core katmanında tutmak. 


Sonuç: N-Layer arthitectureye dependecy invertion uygulayarak Business katmanının Data access katmanına bağımlılığı kaldırmak onu clean arthitecture yapmaz. Clean arthiture'nin en büyük özelliği Application Katmanı ile Domain katmanının olması ve Application katmanında busisness logic'in domain katmamında da domain logic'in entityler içerisinde uygulanarak rich entity model olmasıdır.

Sorun: Uygulamaya herhangi bir yeni feature eklerken yada var olan featureyi değiştirirken genellikle tüm katmanlarda geliştirme yaparız. Dolayısıyla iş birimi aynı anda birden fazla yeni özellik talep ettiğinde kod tabanı yönetimi zorlaşır. 


Çözüm: Moduler Monolitic Mimari Kullanmak.


Moduler Monolitic(monolitic)

Uygulama mantığımızı her biri birbirinden bağımsız ve izole olan modullere ayırıyoruz. Her modülün kendi iş mantığı ve gerkirse kendi veritabanı olmalıdır. Ayrıca her modül ihtiyacı olan mimariyi uygulayabilir. Aşağıdaki görsele bakarsak Product ve Basket modülü n-layer mimari ile oluşturulmuşken Order modülü clean mimari ile oluşturulmuştur. Böylece her bir modülün katmanlarını kendi içinde değiştirebiliriz ve  diğer modülleri etkilememiş oluruz. Böylece monolitic mimarimiz bibirinden bağımsız modüllere ayrıştırılmış olur ve her bir modül kendi ihtiyaçlarına uygun olarak geliştirilir. Her modülün bağımlılığı azaltılmış olur ve diğer modülleri etkilemeden bir modülü geliştirebilir veya değiştirebiliriz. Projede çalışan ekipler sadece kendi modüllerine odaklanır. Modülleri bağımsız olarak deploy etmek veya ölçeklendirmek istersek artık micro servis mimarisini düşünmeye başlayabiliriz.



Dezavantajları

  • Moduler monolitic bir uygulamada aynı anda birden fazla programlama dili kullanamayız.
  • Hiç bir modül bağımsız olarak deploy edilemez ve ölçeklendirilemez. Dikey olarak (CPU) ölçeklendirme sınırlarına ulaştığımızda artık yatay olarak ölçeklendirmeyi(Load balancing)  yada  micro servis mimarisine geçmeyi düşünmemiz gerekir. 
Bir proje güçlü tutarlılık gerektiriyorsa ve tutarlılık zorunlu ise ayrıca bağımsız olarak deploy edilmesi yada ölçeklendirilmesi gerekmiyorsa projeye micro servis yerine moduler monolitic ile başlanmalıdır.

Moduller Arası İletişim

Moduler Monolitic bir uygulamanın tüm modülleri aynı sunucuda olduğu için modüller arası iletişimde network call'a gerek yoktur. Bu nedenle modüller arasında iletişim kurmak hızlı ve kolaydır. Moduller birbirinin metodlarını çağırır.

Moduller arası iletişim Inter Process Communication (IPC) (Türkçesiyle: İşlemler Arası İletişim) olacaktır. IPC, Aynı bilgisayar üzerinde ya da ağ üzerinden çalışan farklı processlerin (işlemlerin) birbiriyle veri alışverişi yapabilmesini sağlayan yöntem ve mekanizmaların genel adıdır. Modern uygulamalarda, farklı görevler genellikle farklı işlemler (process'ler) tarafından gerçekleştirilir. Bu işlemler, bazen aynı uygulamanın farklı parçalarıdır, bazen tamamen bağımsız programlardır. Ancak bu işlemlerin birbiriyle koordinasyon içinde çalışması ve veri paylaşması gerekebilir. IPC bu ihtiyacı karşılar. Memory-based IPC (Paylaşılan Bellek vb.) İki process, aynı bellek bölgesini paylaşır ve buradan veri okur/yazar.

Deployment

Monolitik Mimarinin güvenilir olmayan ve bir modüldeki tek bir hatanın tüm monolitik mimariyi çökertebileceği single point of failure noktasıdır. Tüm geliştirme ekipleri, değişikliklerini single source code repository'e commit eder.


Desing Moduler Monolitic

Moduler monolitic'in uygulandığı örnek mimari aşağıdadır. Bu görsellede modüller sırasıyla Product, Basket, Shipment, Paymentdır. Modulleri birbirlerinden izole edilerek modüler monolitik mimari kullanılarak uygulamaya eklenmek istenen yeni özellikler çok hızlı bir şekilde geliştirilir ve uygulanır. Bu mimaride hala büyük ve tek  bir ilişkisel veritabanı vardır, ancak product ve order şemasını ayırabilir ve bunları bağımsız olarak yönetebiliriz.





Yukarıdaki görselde gördüğümüz üzere her bir modülün kendi UI katmanı vardır. Buda uygulama geliştirken her bir UI katmanın yönetilmesi karmaşıklığı sorununu doğurur. Bunu çözmek için HeadLess arthitecture uygulanabilir.


Avantajları: ,

  • Frontend ve Backend ekipleri ayrı ayrı çalışabilir.
  • Farklı platformlar (web, mobil, kiosk, smartwatch) aynı API'yi kullanabilir.
  • UI ve API ayrı ayrı  deploy edilebilir, ayrı sunuculara taşınabilir.
  • UI ve iş mantığı ayrıldığı için daha kontrollü erişim sağlanabilir. BackEnd de hiç bir bağımlılık olmadan Frontendde değişiklik yapılıp deploy edilebilir. Çünkü artık backend ve frontend olmak üzere 2 farklı projemiz var. Load balancer kullanarak backenp için 3 farklı instance ayağa kaldırabilirken frontend için 2 farklı instance ayağa kaldırabiliriz. Artık frontend ve backend birbirinden bağımsız bir şekilde ölçeklendirilebilir ve deploy edilebilir.

Sorun: Backend ve Frontend load balancer ve yatay ölçeklendirmeyle milyonlarca   tarafiği yönetse bile  uygulamada sadece bir tane ölçeklenemeyen ilişkisel bir veritabanı olduğu için belli bir kapasiteden sonra bu veritabanı, mimarimiz için dar boğaz olacak ve yanıt veremeyecek hale gelecektir. Timeout exception hataları almaya başlarız. Backend tarafı modullere bölünmüş olsada hala tek bir monolitic uygulamadır ve modul bazında deploy yada ölçeklendirme yapamayız.  Örneğin yoğun bir indirim haftası kampanyası var. Diğer modüllerden bağımsız olarak sadece  Order modülünü ölçeklemek istiyoruz fakat bunu yapamayız. Bunun için tüm uygulamayı ölçeklememiz gerekmektedir.





Hiç yorum yok:

Yorum Gönder