Modular Monolith Nedir? Domain Boundary, Coupling ve Evrimsel Mimari Perspektifi

Modular Monolith Nedir? Domain Boundary, Coupling ve Evrimsel Mimari Perspektifi konusunu anlatan renkli 3D teknik illüstrasyon

Modular Monolith, tek bir deployment birimi içinde iş sorumlulukları belirgin modüller kurmayı hedefler. Her modül kendi modelini ve verisini yönetir; diğer modüllerle modülün sunduğu contract’lar üzerinden iletişim kurar.

modular-monolith-architecture

Tek deployment, uygulama parçalarını aynı release birimi içinde tutar. Ancak bu yapının bakımı, modül sınırlarını kodda ve veri erişiminde korumayı gerektirir. Aynı process’teki parçalar, sınırsız veri erişimi ve internal model paylaşımıyla sıkı bağlanır.

Coupling ve cohesion

Cohesion, bir modüldeki sorumlulukların birlikte ne kadar anlamlı olduğunu; coupling ise başka modüllere olan bağımlılıklarını anlatır. Bunlar tasarımı değerlendirmek için yararlıdır, ancak tek başlarına sistemin sağlığını ölçmez. Değişikliklerin kaç modülü etkilediğine, testlerin kapsamına ve release koordinasyonuna da bakmak gerekir.

Sık birlikte değişen iki parçada process sınırı, contract ve deployment koordinasyonunu ortadan kaldırmaz. Aynı koordinasyon bu kez API veya event contract’ları üzerinden devam eder; ayrıca network çağrıları serialization, latency ve partial failure maliyeti ekler.

Modular Monolith içinde sınırları korumak

Bir modülün başka modülün internal entity, repository veya DbContext tiplerini kullanması, uygulama sözleşmesi yerine iç implementasyona bağımlılık kurar. Tercihim, modülün gereken işlemleri küçük bir application contract ile sunmasıdır. Aynı deployment içinde contract diğer ihtiyaçları karşılıyorsa in-process çağrıyla ilerleyin; modülerlik için HTTP zorunlu değildir.

  • Assembly ayrımı ve internal erişim belirleyicisiyle dışarı açılan tipleri sınırlayın.
  • Project reference’larını dependency kurallarına göre sınırlandırın.
  • Architecture testleri ve code review ile sınır ihlallerini kontrol edin.

Interface kullanmak veya projeleri ayırmak tek başına doğru boundary garantisi vermez. Ayrıca InternalsVisibleTo, seçilen friend assembly’ye internal üyelere erişim verir; erişimi neden açtığınızı belirleyin. Compile-time kontrollerin kapsamı dışındaki veri erişimini ve runtime bağımlılıklarını da inceleyin.

Sınırları iş modeli üzerinden belirlemek için Domain Boundary ve DDD değerlendirmesine bakabilirsiniz.

Data ownership ve ortak database

Tek database kullanmak, bütün modüllerin her tabloyu yönetmesi gerektiği anlamına gelmez. Tabloların, migration’ların ve yazma kurallarının sahibi belli olmalıdır. Schema’ları modül sahipliğine göre ayırırsanız bu ilişkiyi görünür hale getirirsiniz. Ancak gerçek erişim sınırını uygulama kuralları ve gerektiğinde database permission’ları kurar.

Başka modülün private tablosuna bağlanan bir sorguda, kolon değişikliğinin o sorguya etkisini de yönetmeniz gerekir. Reporting ihtiyacı varsa sahibinin yönettiği bir read contract, view veya projection değerlendirin. Her okuma için yeni bir servis ya da message broker eklemek gerekmez. Data Ownership yazısı bu seçeneklerin transaction ve bakım maliyetlerini ele alıyor.

Modular Monolith ve transaction sınırı

Tek process, kendiliğinden ACID sağlamaz. Atomiklik; veritabanı provider’ına, connection’a ve transaction kapsamına bağlıdır. EF Core, varsayılan davranışla transaction destekleyen provider üzerinde tek SaveChanges çağrısının değişikliklerini birlikte kaydeder. Buna karşılık birden fazla save veya context’i aynı iş birimine dahil ederken kapsamı açıkça yönetmek gerekir.

Aynı relational database üzerinde çalışan context’ler, aynı DbConnection ve DbTransaction paylaşarak ortak transaction kullanabilir. Ayrıntılar EF Core transaction dokümantasyonunda yer alıyor. Bu koordinasyon modülleri birbirine bağlar; dolayısıyla ileride ayrı deployment’a geçerken maliyetini yeniden değerlendirmek gerekir.

Database commit’i ile dış API çağrısını veya mesaj teslimini aynı local transaction korumaz. Bu nedenle Modular Monolith’te de database commit sonrasındaki dış çağrı başarısızlığını tasarlayın. Gereksinime göre outbox, idempotency veya compensation seçeneklerini değerlendirin.

Microservices’te eventual consistency her işlem için zorunlu değildir. Bir servisin kendi verisi üzerinde local transaction kullanması service bağımsızlığına aykırı değildir. Ancak birden fazla servisin verisini kapsayan iş akışında atomiklik ihtiyacını ve bağımsızlık hedefini birlikte değerlendirmek gerekir. Saga, local ACID transaction’ın yerini aynı garantilerle alan bir mekanizma değildir.

İletişim ve deployment maliyeti

In-process çağrı, network transport ve serialization maliyetini taşımadığı için daha basit bir iletişim yolu sunar. Strong typing de çağrı sözleşmesinin bir bölümünü compile-time’da kontrol eder; business davranışının doğru olduğunu garanti etmez.

Uzak çağrılarda timeout, retry bütçesi ve idempotency’yi ayrıca tasarlayın. Bununla birlikte network’ün her sistemde en büyük darboğaz olduğunu varsayamayız. Database sorgularını, CPU yükünü ve senkron beklemeleri de ölçün; böylece kök nedeni hangi verinin desteklediğini görebilirsiniz.

Modular Monolith ne zaman ayrı servislere dönüşmeli?

Önce çalışan boundary’leri ve data ownership’i netleştirmek, parçalamanın maliyetini değerlendirmeyi kolaylaştırır. Belirli bir capability’nin bağımsız kapasite, release veya failure isolation ihtiyacı güçlendiğinde ayrı deployment’ın faydasını işletim maliyetiyle karşılaştırın. Ancak bu ihtiyaçların her biri için Microservices zorunlu değildir. Örneğin hedefi ayrı worker veya pipeline iyileştirmesi karşılıyorsa servis ayrımının ek maliyetini üstlenmeyin.

Kararı service sayısıyla değil, release süresi, gecikme, hata oranı ve operasyon yükündeki değişimle değerlendirin. Microservices’e geçiş sinyalleri ilk adayın seçimini ayrıntılandırıyor. Microsoft’un mimari değerlendirmesi de bağımsız deployment’ın faydalarını veri tutarlılığı ve işletim maliyetiyle birlikte ele alıyor.

Yanlış bölünmüş bir sistemi Microservices yapmak, problemi çözmez. Sadece problemi dağıtır.

By tanju.bozok

Senior .NET Engineer | Backend architecture, distributed systems & real-time communication