Layered Architecture Pattern in Spring Boot

Bu yazımızda bir rest backend projesinin olmazsa olmazı olan Layered Architecture Pattern ‘i bir Spring Boot projemize entegre edeceğiz.

Bu başlığı aslında SOLID’ in bir uygulaması olması amacılığı ile oluşturdum. Çünkü SOLID’ in her aşamasını bu yapı sayesinde kullanabiliyoruz.

Layered Architecture Pattern bize ne sağlar?

  • Katmanlı mimari sayesinde open/closed kullanımı sağlar; gereksiz bir layer i close ederek kullanıcıdan gizleyebiliriz veya developer team (geliştirme ekibi) içerisinde readonly olarak dependecy ederek kullanmamıza olanakta sağlar.
  • Kurumsal projelerde olmazsa olmazdır. Sistemli kod geliştirmesi sağlar. Developer team (geliştirme ekibi) uyum sağlaması kolay olur.
  • Yazılım Bakımı ve sonradan geliştirilebilirliği kolaylaştırır.
  • Kullanıcı ile daha doğrusu client ile iletişimi kuracak layer e api dersek; api katmanının export war/jar olarak oluşturursak; api katmanı da diğer katmanları kendine dependecy olarak alacağı için closed bir yapı kurmuş oluruz.
  • Her katmanın iletişimini interface bir class ile kurarsak: otomatik olarak; Single Responsibility, Interface Segregation, Liskov Substitution ve Dependency Inversion kurallarına uymamıza teşvik oluruz.

Projemizde bu şekilde katman katman her bir işlevi ayırsakta: ilgili işlemler ilgili katmanlarda yer alsa. Katmanlar arası interface’ ler ile bağlantı kursak: bu akış bizi SOLID prensiplerini uygulamaya ve clean code yazmamıza olanak sağlar mı? Evet. bu kabul gören ve globalleşen her ülkede kullanılan bir yaklaşımdır. GitHub üzerinden max star almış bir proje indirin ve bakın. Hangi dilde olursa olsun SOLID’ e uygun bir layer akışı kurulur.

Bu akışta katmanların isimleri veya görevleri resimdeki gibi tavsiye edilenle aynı olmak zorunda değildir. Projenize uygun işlevlere uygun bir katman yapısı kurmanız gerekir. Katmanların ayrımını belirlerken; işlev olarak mesela data katmanında veritabanı veya veri kaynağı ile ilgili işlemlerin yapılacağını öngördüğümüzde bu bir katman olmalıdır diyebiliriz. Ya da günde 1 defa çalışacak ve config bilgisine göre SAP programına kayıt bırakacak bir api geliştirmeniz gerekti. Bunun için ayrı bir katman oluşturup bunun adına processor diyebilirsiniz. Kısaca katmanları belirleyen şeyler yaptığı işlevler olmalıdır. Bu düşünce çevresinde mimarimizi oluşturursak clean code yakalayabiliriz.

Yukarıdan aşağı bir akış görüyoruz. Client ilk katman olan presentation yani sunum katmanına bir request (istek) ile geliyor. Bu katmanda gerekli validasyonlar sağlanabilir. Eğer istek atan kişi gelmesi gerektiği gibi geldi ise business katmanı bir aracı katmandır bu katman ile service katmanına inersiniz. Service katmanında request bilgisi ile ilgili bir işlem yapılması gerekebilir. Bu katmanda eğer varsa gerekli işlemler yapılır veriye erişim gerekirse persistence katmanı ile data layer e inilir burada veri seti ile ilgili işlemler yapılarak kullanıcuya aşağıdan yukarı bir dönüş yapılır.

Sonuç olarak projenize göre katmanlarınız değişir. Analizi iyi yapılmış bir yazılımın mimarisini doğru kurarsanız kaliteli bir yazılım geliştirirsiniz.

Kaynak

https://www.oreilly.com/library/view/software-architecture-patterns/9781491971437/ch01.html

Uygulamaya Giriş

Şimdi bir yazı dizisine başlayacağız. Bir mikroservis projesi oluşturacağız. Bu sebeple örnek bir layered architecture oluşturdum, bu mimariyi burada anlatıyor olacağım.

Benim projem bir rest backend projesidir ve java arka planda spring boot ı kullanır jdk11 ile çalışır ve proje bağımlılığı şu şekildedir.

Mimari Tasarım

Proje de 4 katman kullanıyorum. Main project im var 4 katmanı da içinde barındıran projenin tamamı. Main projectimin adı root olsun; 4 katman: api, service, repository ve domain. Gördündüğü gibi domain katmanını ortak yaptım. Hepsinde kullanılıyor. Peki sizce domain layer in diğer layer lara olan bağımlılığı solid’ e ters gelmiyor mu? evet ters geliyor ama domain layered architecture de ayrı bir design pattern’ dir. Analizi uygun projelerde kullanılabilir. Buna sistemin mimarisini tasarlayan yazılımcı karar vermedilir. Konumuza dönecek olursak.

Senaryo

Request Geldi. (1)

api katmanım benim rest controller’ imin yer alacağı yani globaldeki adı presentation yani sunum katmanıdır. Client i bu katmanla karşılarım; Kullanıcının bana ilettiği json request @RestController ve @RequestBody ile domain modelimin içinde yer alan dto class’ lara dönüşür. Buna RequestDto diyelim. Bana gelen RequestDto ilgili api’ ye ait uygun validasyon şartlarını sağlıyor ise [X]– (2); / Sağlamıyor ise [Y] – (3).

Y: Bad request- (3)! geri dönen request uygun olmayan bir response oluşturur.

X: service katmanı-(2) mda interface aracılığı ile controller den gelen akışı alırım. Service katmanında bu request bilgilerini işlemem gerekiyorsa işlerim; veri seti gerektiriyor ise [A] -(5) / – Gerektirmiyorsa [B] -(4);

B: 200 OK ResponseDto-(4)apinin sağladığı uygun bir dönüş şekli.

A: Repository -(5) yani veri seti erişimi domain layer aracılığıyla dto ların entity class larına dönüşümü ve veri seti ile ilgili gerekli işlemlerin yapılması. Aşağıdan yukarı 200 OK ve Uygun bir ResponseDto dönüştürülerek dönülmesi -(6).

Paint te anca bu kadar çizebildim biliyorum şekiller kan ağlıyor ama idare edelim 🙂

Proje Yapısı

Gelelim proje yapımıza.

Uzaktan genel görünümü aşağıdaki gibi.

Detayına inersek;

Root Yapısı

Açıklamaları rahat olsun diye resim üzerine yazdım. Gördüğümüz gibi root projesi bir parent ve kendine bağlı modüller barındırıyor bunlarda child info olarak görüyoruz.

Şimdi modüller arasındaki ilişkilere bakalım.

Api Katmanı

parent ini söyledik. dependecy olarak service katmanını aldı. çünkü yukarıdan aşağı service katmanına akışı iletecek.

Service Katmanı

Service katmanı ise repository kendisine bağımlı kıldı. çünkü akışta service katmanı uygun ise veri seti işlemi için data katmanına inecekti.

Dolayısıyla api katmanı service katmanını almıştı service katmanı repo yani data katmanını kendine bağımlı kılmıştı şimdi dolaylı olarak api katmanı da service katmanına bağlı olan repo katmanını istese direk kullanabilir. Ama spring boot annotation ile @service @ repository konfigürasyonları koyarak buna engel olacağız tabii.

Data Katmanı

bu katmanda kendine domain katmanını bağlı kıldı. Dolayısıyla bağımlılıklar şöyle oldu.

Domain Katmanı

Domain katmanı repository den bağımlı olarak tüm katmanların içinde kullanılabilir oldu.

Özetle,

api-> service

service -> repository

repository->domain

Kapsam

api-> service, repository, domain

service-> repository, domain

repository-> domain

katmanlarına erişebilir oldu.

Sonuç

Katmanlı mimari projeye göre değişkenlik gösterebilir. Ben domain model ve katmanlı mimari baz alarak kendi mimari yapımı oluşturdum.

Api katmanımda paketleme biçimi war olarak setledim. Uygulamayı api export’ u ile bir tomcat sunucusu üzerinden çalıştırabilir olduk.

Örneğin data katmanında veri seti bağlamı için data projesinin pom xml bilgisine kullanılacak veritabanı bilgileri girilir. Bu sayede veritabanı etkileşimi sadece data katmanında olur. Katmanlı mimari bu ve buna benzer bağımlılıkları da kolaylaştırır.

Global desteklenen bir proje mimarisi oldu. Bu proje oluşturduğumuz microservices projesinin temelini oluşturuyor olacak.

Uygulamalar

Layered Architecture Pattern in Spring Boot Uygulamasına erişmek için bağlantıya gidin.

Spring Boot Rest Backend with Postgres CRUD Uygulamasına erişmek için bağlantıya gidin.

Leave a Reply

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir