Web API'leri Geliştirme — Mikro Servis Mimarisi, SOLID, DDD, Onion Mimarisi, Temiz Mimari, CQRS
Üzeyir AYDIN
01 NisHarika bir proje mimarisi için bilinmesi gerekenler
Merhabalar bugün öğrenirken biraz zaman alan bir konudan bahsedeceğim. Bu alanda yetkinliklerimi geliştirmeye ve her geçen gün daha fazla bilgi edinmeye çalışıyorum. Öğrenirken çok fazla soru sormak, alınan cevaplar üzerinde düşünmek ve hatta bir makale yazmak çok faydalıdır. Konu ile ilgili sorularınızı çekinmeden sorunuz.
Bu konuda nasıl gideceğim?
SOLID ilkelerine uygun orta seviye bir Web API yazmadan önce bilmemiz gerekenlerden bahsedeceğim. Bir sonraki yazımda uygun bir Web API geliştireceğim. Amaç iyi bir başlangıç yapmak ve bir varlık oluşturduktan sonra aşağıda belirttiğim başlıklara uygun bir yol izlemektir.
Ne hakkında konuşacağım?
- Mikroservis Mimarisi
- .Net Çekirdek Bağımlılık Enjeksiyonu
- SAĞLAM
- Onion mimarisi
- Temiz Mimari
- DDD (Etki Alanına Dayalı Tasarım)
Kodlama kısmında nelerden bahsedeceğim?
Burada bir mikro hizmet ile onion mimarisini kullanacağım.
- .Net Çekirdek 5
- depolar
- CQRS ve MediatR
- Varlık Çerçevesi | Önce Kod
- MySQL
Mikroservis Mimarisi
Microsoft'un kendi kaynağı olan ve buradan indirebileceğiniz .NET Microservices: Architecture for Containerized .NET Applications adlı kitapta mikroservisler şu şekilde anlatılıyor:
Adından da anlaşılacağı gibi, bir mikro hizmet mimarisi, bir dizi küçük hizmet olarak bir sunucu uygulaması oluşturmaya yönelik bir yaklaşımdır. Bu, yaklaşımın ön uç için de kullanılmasına rağmen, bir mikro hizmet mimarisinin esas olarak arka uca yönelik olduğu anlamına gelir. Her hizmet kendi sürecinde çalışır ve HTTP/HTTPS, WebSockets veya AMQP gibi protokolleri kullanarak diğer süreçlerle iletişim kurar.
Her mikro hizmet, belirli bir bağlam sınırı içinde belirli bir uçtan uca etki alanı veya iş yeteneği uygular ve her biri bağımsız olarak geliştirilmeli ve bağımsız olarak dağıtılabilir olmalıdır. Son olarak, her bir mikro hizmet, ilgili etki alanı veri modeline ve etki alanı mantığına sahip olmalıdır ve farklı veri depolama teknolojilerine (SQL, NoSQL) ve farklı programlama dillerine dayalı olabilir.
Bir mikro hizmetin boyutu ne olmalıdır?
Bir mikro hizmet geliştirirken, önemli nokta boyut olmamalıdır. Bunun yerine, önemli olan nokta, her hizmet için geliştirme, dağıtım ve ölçek özerkliğine sahip olmanız için gevşek bağlı hizmetler oluşturmak olmalıdır. Elbette, mikro hizmetleri tanımlarken ve tasarlarken, diğer mikro hizmetlere çok fazla doğrudan bağımlılığınız olmadığı sürece, bunları mümkün olduğunca küçük yapmaya çalışmalısınız.
Mikro hizmetin boyutundan daha önemli olan, sahip olması gereken dahili uyum ve diğer hizmetlerden bağımsız olmasıdır.
Neden bir mikro hizmet mimarisi?
Kısacası uzun süreli çeviklik sağlar. Mikro hizmetler, karmaşık, büyük ve yüksek düzeyde ölçeklenebilir sistemlerde, her birinin ayrıntılı ve özerk yaşam döngülerine sahip, bağımsız olarak dağıtılabilir birçok hizmete dayalı uygulamalar oluşturmanıza olanak sağlayarak daha iyi bakım yapılmasını sağlar. Ek bir avantaj olarak, mikro hizmetler bağımsız olarak ölçeklenebilir.
Bir birim olarak ölçeklendirmeniz gereken tek bir monolitik uygulamaya sahip olmak yerine, belirli mikro hizmetlerin ölçeğini genişletebilirsiniz. Bu şekilde, uygulamanın ölçeklenmesi gerekmeyen diğer alanlarını ölçeklendirmek yerine, talebi desteklemek için yalnızca daha fazla işlem gücüne veya ağ bant genişliğine ihtiyaç duyan işlevsel alanı ölçekleyebilirsiniz. Bu, daha az donanıma ihtiyaç duyduğunuz için maliyet tasarrufu anlamına gelir.
SOLID İlkelerini ve Bağımlılık Enjeksiyonunu Kullanın
SOLID ilkeleri, DDD modelleriyle bir mikro hizmet geliştirmek gibi herhangi bir modern ve kritik görev uygulamasında kullanılacak kritik tekniklerdir.
SOLID, beş temel ilkeyi gruplayan bir kısaltmadır:
• Tek Sorumluluk ilkesi
• Açık/kapalı prensibi
• Liskov ikame ilkesi
• Arayüz Ayrımı ilkesi
• Bağımlılığı Tersine Çevirme ilkesi
SOLID daha çok uygulamanızı veya mikro hizmet iç katmanlarınızı nasıl tasarladığınızla ve bunlar arasındaki bağımlılıkları ayırmayla ilgilidir. Etki alanıyla değil, uygulamanın teknik tasarımıyla ilgilidir.
Son ilke olan Bağımlılık Tersine Çevirme ilkesi, altyapı katmanını diğer katmanlardan ayırmanıza olanak tanır ve bu da DDD katmanlarının daha iyi ayrıştırılmış bir şekilde uygulanmasına olanak tanır.
Dependency Injection (DI) , Dependency Inversion ilkesini uygulamanın bir yoludur. Nesneler ve bağımlılıkları arasında gevşek bağlantı elde etmek için bir tekniktir. Doğrudan ortak çalışanları başlatmak veya statik referanslar kullanmak yerine, bir sınıfın eylemlerini gerçekleştirmek için ihtiyaç duyduğu nesneler sınıfa sağlanır.
Çoğu zaman, sınıflar bağımlılıklarını yapıcıları aracılığıyla bildirerek Açık Bağımlılıklar İlkesini takip etmelerini sağlar. Dependency Injection, genellikle belirli Inversion of Control (IoC) kapsayıcılarına dayanır. ASP.NET Core, basit bir yerleşik IoC kapsayıcı sağlar, ancak Autofac veya Ninject gibi favori IoC kapsayıcınızı da kullanabilirsiniz.
SOLID ilkelerini takip ettiğinizde, sınıflarınız doğal olarak küçük, iyi çarpanlara ayrılmış ve kolayca test edilmiş olma eğiliminde olacaktır. Ancak sınıflarınıza çok fazla bağımlılık enjekte edilip edilmediğini nasıl bilebilirsiniz?
DI'yi yapıcı aracılığıyla kullanırsanız, yalnızca yapıcınız için parametre sayısına bakarak bunu tespit etmek kolay olacaktır. Çok fazla bağımlılık varsa, bu genellikle sınıfınızın çok fazla şey yapmaya çalıştığının ve muhtemelen Tek Sorumluluk İlkesini ihlal ettiğinin bir işaretidir.
Etki Alanına Dayalı Tasarım (DDD)
DDD ileri bir teknoloji veya özel bir yöntem değildir. DDD, karmaşık yazılım sistemlerinin geliştirilmesinde ve bu karmaşık projelerin hayata geçirilmesinde sıklıkla karşılaşılan temel sorunlara çözüm bulmaya çalışan bir yaklaşımdır.
Programcı Eric Evans tarafından 2004 yılında yayınlanan Etki Alanına Dayalı Tasarım: Yazılımın Kalbinde Karmaşıklıkla Mücadele adlı kitabında tanıtılan ve popüler hale getirilen etki alanı güdümlü tasarım, yazılım geliştirme için geçerli olduğu için etki alanı kavramının genişletilmesi ve uygulanmasıdır. DDD üç temel ilkeye odaklanır:
Çekirdek etki alanına ve etki alanı mantığına odaklanın.
Karmaşık tasarımları etki alanı modellerine dayandırın.
Uygulama modelini geliştirmek ve alanla ilgili ortaya çıkan sorunları çözmek için alan uzmanlarıyla sürekli işbirliği yapın.
Katmanlı Mimari DDD'nin
en temel kavramlarından biri 4 katmanlı mimarisidir.
- Etki Alanı Katmanı
- Uygulama katmanı
- Sunum Katmanı
- Altyapı Katmanı
Bu konu onion mimarisi ile daha iyi anlaşılacaktır.
onionmimarisi
Diyagramda olduğu gibi, geleneksel katmanlı mimari, 'UI' -> 'İş Mantığı' -> 'Veri' hiyerarşisine sahiptir. Avantajlı getirilerinden çok bu mimarinin zorluklarından ve bu zorlukların bize getirdiği maliyetten bahsetmekte fayda var diye düşünüyorum.
Görüldüğü gibi geleneksel katmanlı mimaride uygulamayı oluşturan katmanlar arasında sıkı bir bağlılık vardır ve her katman, altındaki katmana hiyerarşik olarak bağlıdır. Ayrıca kullanıcı arayüzü sade olup sadece 'Business Logic' katmanı ile haberleşir ve 'Data' katmanı ile direkt iletişime izin verilmez. Böylece bir tasarım düzenlense ve güvenlik sağlanmış olsa bile bu tasarım büyük ve karmaşık uygulamalar için yetersiz kalmaktadır. Bunun nedeni, 'Veri' katmanının merkezi bir role sahip olmasıdır.
Görüldüğü gibi Onion Architecture'da katmanlar dairesel bir şekilde iç içedir. Soğana benzediği için bu ismi almıştır. Aslında her katmanın görüntüden ziyade işlevsellik açısından tek bir iç katmana bağımlı olmasının soğan anatomisini canlandırması nedeniyle bu şekilde atfedildiğini söyleyebiliriz.
Etki Alanı Katmanı genellikle kurumsal mantık ve varlıkları içerir. İş kavramlarını, iş durumu hakkındaki bilgileri ve iş kurallarını temsil etmekten sorumludur. İş durumunu yansıtan durum, depolamanın teknik detayları altyapıya devredilmesine rağmen burada kontrol edilir ve kullanılır. Bu katman, iş yazılımının kalbidir.
Etki alanı katmanı, işletmenin ifade edildiği yerdir.
Uygulama Katmanı, Yazılımın yapması gereken işleri tanımlar ve ifade edici etki alanı nesnelerini sorunları çözmeye yönlendirir. Bu katmanın sorumlu olduğu görevler, işletme için anlamlıdır veya diğer sistemlerin uygulama katmanlarıyla etkileşim için gereklidir. Bu tabaka ince tutulur. İş kurallarını veya bilgisini içermez, ancak yalnızca görevleri koordine eder ve bir sonraki katmandaki etki alanı nesnelerinin işbirliklerine yönelik işleri delege eder. İş durumunu yansıtan bir durumu yoktur, ancak kullanıcı veya program için bir görevin ilerlemesini yansıtan bir duruma sahip olabilir.
Uygulama Katmanı, Arayüzlere ve türlere sahip olacaktır. Temel fark, Etki Alanı Katmanının tüm kuruluş için ortak olan türlere sahip olması ve dolayısıyla diğer çözümler arasında da paylaşılabilmesidir. Ancak Uygulama Katmanı, Uygulamaya özgü türlere ve arabirimlere sahiptir.
Sunum Katmanı , İdeal olarak, Kullanıcının Erişebileceği Projeyi koymak istediğiniz yerdir. Bu bir WebApi, Mvc Projesi vb. olabilir.
Altyapı Katmanı biraz daha zor. Altyapınızı eklemek istediğiniz yer burasıdır. Altyapı her şey olabilir. Belki DB'ye Erişmek için bir Entity Framework Çekirdek Katmanı veya Kimlik Doğrulama için JWT Belirteçleri veya hatta bir Hangfire Katmanı oluşturmak için özel olarak yapılmış bir Katman. ASP.NET Core WebApi Projesinde Onion Mimarisini Uygulamaya başladığımızda daha fazlasını anlayacaksınız.
Kalıcılık Katmanı
DbContext, taşıma ve veritabanı yapılandırma işlemleri bu katmanda gerçekleştirilir. Ayrıca Uygulama katmanındaki arayüzler burada uygulanmaktadır.
Onion Mimarisinin Avantajları
- Onion Architecture, uygulama katmanlarının sadece iç katmana mimari bağımlılığı sayesinde Sıkı Kaplin ortadan kaldırır ve Gevşek Akuple sağlar.
- Projeyi sorumluluklarına göre katmanlara ayırdığı için Endişelerin Ayrımı ilkesine de uygundur.
- Katmanlar ilişkisel olarak içe bağımlıdır. Bu nedenle, bu onun bakımını kolaylaştırır.
- Birim testleri, uygulamanın diğer modüllerinin etkisi olmadan ayrı katmanlar için oluşturulabildiklerinden daha iyi test edilebilirlik sağlar.
Temiz Mimari
Temiz mimarilerin her biri aşağıdakileri sağlayan sistemler üretir:
- Çerçevelerden Bağımsız. Mimari, bazı özellik yüklü yazılım kitaplıklarının varlığına bağlı değildir. Bu, sisteminizi sınırlı kısıtlamalarına sıkıştırmak yerine bu tür çerçeveleri araç olarak kullanmanıza olanak tanır.
- Test edilebilir. İş kuralları, UI, Veritabanı, Web Sunucusu veya başka herhangi bir harici unsur olmadan test edilebilir.
- UI'den bağımsız. Kullanıcı arayüzü, sistemin geri kalanını değiştirmeden kolayca değişebilir. Bir Web Kullanıcı Arayüzü, örneğin iş kurallarını değiştirmeden bir konsol kullanıcı arayüzü ile değiştirilebilir.
- Veritabanından Bağımsızdır. Oracle veya SQL Server'ı Mongo, BigTable, CouchDB veya başka bir şey için değiştirebilirsiniz. İş kurallarınız veritabanına bağlı değildir.
- Herhangi bir dış ajanstan bağımsız. Aslında, iş kurallarınız dış dünya hakkında hiçbir şey bilmiyor.
Yazılımı katmanlara ayırarak ve Bağımlılık Kuralına uyarak, ima edilen tüm faydaları olan, özünde test edilebilir bir sistem yaratacaksınız. Sistemin veritabanı veya web çerçevesi gibi harici parçalarından herhangi biri geçersiz hale geldiğinde, bu eski öğeleri en az sorunla değiştirebilirsiniz.
CQRS ve MediatR
Komuta ve Sorgu Sorumluluğu Ayrımı (CQRS) Greg Young tarafından tanıtıldı ve Udi Dahan ve diğerleri tarafından güçlü bir şekilde desteklendi. Daha ayrıntılı olmasına rağmen, CQS ilkesine dayanmaktadır. Komutlara ve olaylara ve isteğe bağlı olarak asenkron mesajlara dayalı bir kalıp olarak kabul edilebilir.
Çoğu durumda, CQRS, okumalar (sorgular) için yazmalardan (güncellemeler) farklı bir fiziksel veritabanına sahip olmak gibi daha gelişmiş senaryolarla ilgilidir. Ayrıca, daha gelişmiş bir CQRS sistemi, güncellemeler veritabanınız için Olay Kaynağını (ES) uygulayabilir, böylece mevcut durum verilerini depolamak yerine olayları yalnızca etki alanı modelinde depolarsınız.
Ancak, bu yaklaşım bu kılavuzda kullanılmamaktadır. Bu kılavuz, yalnızca sorguları komutlardan ayırmaktan oluşan en basit CQRS yaklaşımını kullanır. CQRS'nin ayırma yönü, sorgu işlemlerini bir katmanda ve komutları başka bir katmanda gruplayarak elde edilir.
Her katmanın kendi veri modeli vardır ve kendi kalıp ve teknoloji kombinasyonu kullanılarak oluşturulur. Daha da önemlisi, iki katman, bu kılavuz için kullanılan örnekte (mikro hizmet siparişi) olduğu gibi aynı katman veya mikro hizmet içinde olabilir. Veya farklı mikro hizmetlerde veya süreçlerde uygulanabilirler, böylece birbirlerini etkilemeden ayrı ayrı optimize edilebilirler ve ölçeklenebilirler.
CQRS, bir okuma/yazma işlemi için diğer bağlamlarda bir tane olan iki nesneye sahip olmak anlamına gelir. Daha gelişmiş CQRS literatüründe öğrenebileceğiniz denormalize edilmiş bir okuma veritabanına sahip olmak için nedenler vardır.
Ancak, amacın, sorguları kümeler gibi DDD modellerinden gelen kısıtlamalarla sınırlamak yerine sorgularda daha fazla esnekliğe sahip olmak olduğu bu yaklaşımı burada kullanmıyoruz.
Çözüm
Mikro hizmet mimarisi, otonom hizmetler biçiminde birçok bağımsız alt sisteme dayalı, dağıtılmış ve büyük veya karmaşık, kritik öneme sahip uygulamalar için tercih edilen yaklaşım haline geliyor. Mikro hizmet tabanlı bir mimaride uygulama, bağımsız olarak geliştirilen, test edilen, sürümlendirilen, dağıtılan ve ölçeklenen bir hizmetler topluluğu olarak oluşturulmuştur. Her hizmet, ilgili herhangi bir özerk veritabanını içerebilir.
Bir projenin iyi bir proje olması için iyi bir kod mimarisine sahip olması gerekir. Burada en büyük etken bağımsız servisler yaratmaktır. Bir işlev diğerine ulaşmamalı ve erişilebilirlik katmanlar halinde olmalıdır.
Müşteri Girişi
Hesabınızı yönetmek için giriş yapın