Selamlar,
Yazılım geliştirme dünyasında, özellikle de karmaşık iş kurallarına sahip sistemlerde, doğru
modelleme yaklaşımını seçmek, uygulamanın sürdürülebilirliği, performansı ve güvenilirliği
açısından büyük önem taşır. Bu kapsamda, Anemic Domain Model (ADM) ve Rich Domain
Model (RDM), yazılım projelerinde en sık karşılaşılan iki modelleme yaklaşımıdır. Her iki
model, iş kurallarının ve veri yönetiminin nasıl ele alınacağı konusunda farklı yöntemler sunar.
Anemic Domain Model (ADM), veri odaklı bir yaklaşımı benimser ve domain nesnelerini veri
taşıyıcıları olarak ele alır. ADM’de, iş kuralları ve veri ayrı katmanlarda bulunur. Domain
nesneleri yalnızca veriyi saklarken, iş kuralları genellikle servis katmanında yer alır. Bu
yaklaşım, modelin basit bir yapıda olmasını sağlar fakat domain nesnelerinin sadece veri
taşıması ve iş kurallarını içermemesi, karmaşık iş süreçlerinde bazı dezavantajlarada sebep
olabilmektedir.
Öte yandan, Rich Domain Model (RDM), veriyi ve iş kurallarını tek bir yapı altında toplar.
Domain nesneleri, yalnızca veriyi saklamakla kalmaz, aynı zamanda o veri ile ilgili iş
kurallarını da kapsar. Bu modelde, domain nesneleri gerçek dünya varlıklarını daha anlamlı bir
şekilde temsil eder. Veri ve iş mantığı arasında güçlü bir encapsulation (kapsülleme) sağlanır.
RDM’nin bu kapsayıcı yapısı, sistemin daha tutarlı, güvenli ve bakımının kolay hale gelmesini
sağlamaktadır.
Anemic Domain Model (ADM)
Anemic Domain Model (ADM), yazılım geliştirmede veri odaklı bir yaklaşımı benimser. Bu
modelde, domain nesneleri çoğunlukla sadece veri taşıyan yapılar olarak işlev görür ve
herhangi bir iş kuralını içermez. İş kuralları ve davranışlar, domain nesnelerinden ayrı olarak
servis sınıflarında tanımlanır. ADM, nesneleri veriyi saklayan ve bu veriyi servisler aracılığıyla
işleyen yapılara dönüştürür. Örneğin, Product, Order veya Customer gibi nesneler sadece veriyi
taşırken, ProductService veya OrderService gibi servisler, iş mantığını uygulayan katmanlardır.
ADM’nin Özellikleri:
- Veri Odaklı Yapı: Domain nesneleri veri taşıyan nesnelerdir. İş kurallarını taşımazlar.
- Servis Katmanı: Tüm iş kuralları, domain nesnelerinden bağımsız servis katmanında yer
alır. - Basitlik: Domain nesnelerinin sadece veri taşıması, yapıyı basit hale getirir. Özellikle
küçük projelerde veya az sayıda iş kuralına sahip sistemlerde, yönetimi kolay bir yapı
sunar.
ADM’nin Avantajları
- Basitlik: Domain nesnelerinin yalnızca veri taşıması, mimariyi basitleştirir. Bu da,
geliştiriciler için modelin anlaşılmasını ve yönetimini kolaylaştırabilir. - Katmanlı Mimariye Uygunluk: İş kurallarının servis katmanında tanımlanması,
özellikle çok katmanlı mimarilerde daha kolay organizasyon sağlar.
ADM’nin Dezavantajları
- Anlamsız Domain Nesneleri: Domain nesneleri sadece veriyi taşıdığında, gerçek
dünyadaki varlıkları tam olarak temsil edemezler. Domain nesneleri anlam kaybeder,
çünkü kendi iş kurallarını koruyamazlar. - Encapsulation Eksikliği: Veri ve iş mantığı birbirinden ayrı olduğu için encapsulation
zayıflar. Domain nesneleri, kendi verilerini koruma kapasitesini kaybeder. Bu durum, iş
kurallarının ihlal edilme riskini artırır. - Kod Bakımı ve Tutarsızlık Riski: İş mantığı farklı servis sınıflarında dağıldığında,
kodun bakımı zorlaşır. Farklı servislerde dağınık halde bulunan iş kuralları, tutarsızlık
ve karmaşıklık yaratabilir.
Şimdi ADM ile kurgulanmış bir örnek üzerinden durumu daha iyi kavrayalım;
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
}
public class ProductService
{
public void UpdatePrice(Product product, decimal newPrice)
{
if (newPrice <= 0)
{
throw new ArgumentException("Invalid Price");
}
product.Price = newPrice;
}
public void ReduceStock(Product product, int quantity)
{
if (quantity > product.StockQuantity)
{
throw new InvalidOperationException("Insufficient stock.");
}
product.StockQuantity -= quantity;
}
public void ApplyDiscount(Product product, decimal discountPercentage)
{
if (discountPercentage <= 0 || discountPercentage > 100)
{
throw new ArgumentException("Invalid Discount");
}
product.Price -= product.Price * (discountPercentage / 100);
}
}
Yukarıdaki kod örneğini değerlendirmek gerekirse buradaki Product sınıfı yalnızca veriyi
taşıyan basit bir nesnedir. ProductService sınıfı ise ürünle ilgili tüm iş kurallarını içerir. Fiyat
güncelleme, stok azaltma ve indirim uygulama gibi işlemler bu sınıfta tanımlanmıştır. Burada
Product sınıfı veri taşıma haricinde hiçbir işlevselliğe sahip değildir.
ADM’de iş kurallarının ayrı servislerde yer alması nedeniyle doğrudan Product sınıfına erişim
sağlandığında veri tutarsızlığı yaratılabilir. Örneğin, servis sınıfı dışında Product sınıfının
fiyatına doğrudan erişilip hatalı bir güncelleme yapılabilir. Aşağıda bu sorunu gösteren kod
parçası yer almaktadır.
public void Execute()
{
var product = new Product
{
Id = 1,
Name = "Laptop",
Price = 1000,
StockQuantity = 10
};
var productService = new ProductService();
productService.UpdatePrice(product, 900);
product.Price = -200;
}
Burada görüldüğü gibi önce bir Product nesnesi tanımlanmış ardından ProductService sınıfında
yer alan UpdatePrice metodu ile Price güncellemesi yapılmuştır. Buraya kadar aslında çok net
bir sorun yok fakat bir sonraki satırda görüldüğü gibi ProductService sınıfında yer alan
UpdatePrice metodu çağrılmadan da Price güncellemesi yapılabilmiştir. Bu durum iş kuralının
ihlaline ve yanlış kullanıma sebep olmuştur.
Rich Domain Model (RDM)
Rich Domain Model (RDM), iş kurallarını domain nesnelerinin içine alarak veri ve iş mantığını
birleştirir. Bu modelde, domain nesneleri yalnızca veriyi taşımaz, aynı zamanda o veriye ait iş
kurallarını ve davranışları da kapsar. RDM, domain nesnelerinin gerçek dünya varlıklarını daha
anlamlı şekilde temsil etmesini sağlar. Her domain nesnesi kendi verisini korur ve iş mantığını
kendi içinde barındırır.
RDM’nin Özellikleri:
- Veri ve İş Mantığı Birlikte: Domain nesneleri, hem veriyi hem de iş kurallarını kapsar.
- Encapsulation: Veri ve iş mantığı bir arada tutulduğu için encapsulation ilkesi güçlenir.
Domain nesneleri, dışarıdan gelen yanlış erişim ve manipülasyonlara karşı daha
güvenlidir. - Anlamlı Domain Nesneleri: Domain nesneleri kendi davranışlarını ve kurallarını
içerdiğinden, model daha tutarlı ve anlaşılır hale gelir.
RDM’nin Avantajları
Tutarlılık ve Modülerlik: Domain nesneleri kendi iş kurallarını kapsadığından, tutarlılık
artar ve iş kurallarının ihlali zorlaşır
Encapsulation ve Güvenlik: Domain nesneleri kendi verisini korur, dışarıdan
müdahaleyi sınırlandırır.
Kodun Okunabilirliği ve Bakımı: İş mantığı ilgili nesnenin içinde saklandığı için, kod
daha anlaşılabilir ve yönetimi daha kolaydır.
Şimdi de biraz önce ADM yi anlatırken verdiğimiz kod örneğinin aynısını RDM’de yapıp
aradaki farkı inceleyelim.
public class Product
{
public int Id { get; private set; }
public string Name { get; private set; }
public decimal Price { get; private set; }
public int StockQuantity { get; private set; }
public Product(int id, string name, decimal price, int stockQuantity)
{
if (price <= 0) throw new ArgumentException("Invalid Price");
if (stockQuantity < 0) throw new ArgumentException("Invalid Quantity");
Id = id;
Name = name;
Price = price;
StockQuantity = stockQuantity;
}
public void UpdatePrice(decimal newPrice)
{
if (newPrice <= 0)
{
throw new ArgumentException("Invalid Price");
}
Price = newPrice;
}
public void ReduceStock(int quantity)
{
if (quantity > StockQuantity)
{
throw new InvalidOperationException("Insufficient stock.");
}
StockQuantity -= quantity;
}
public void ApplyDiscount(decimal discountPercentage)
{
if (discountPercentage <= 0 || discountPercentage > 100)
{
throw new ArgumentException("Invalid Discount");
}
Price -= Price * (discountPercentage / 100);
}
}
Bu RDM kod örneğinde Product nesnesi artık kendi iş kurallarını içerdiği için dışarıdan yanlış
güncelleme yapılması imkansız hale gelmiştir(Property ler private set yapılmıştır). Fiyatı
güncellemek, stoğu azaltmak veya indirim uygulamak gibi işlemler, yalnızca ilgili metodlar
aracılığıyla yapılabilir. Bu sayede, encapsulation ilkesi tam anlamıyla sağlanmış olur. Şimdi
tıpkı ADM’de olduğu gibi ilgili metotları çağıran metodu RDM ye göre tekrar yazalım;
public void Execute()
{
var product = new Product(1, "Laptop", 1000, 10);
product.UpdatePrice(900);
product.Price = -200;//Derleme sırasında hata verir
}
Burada görüldüğü gibi yine Product nesnesi oluşturulmuş bu sefer ProductService gibi bir
service aracılığıyla değilde doğrudan Product nesnesi üzerinden güncelleme yapılmıştır.
Ardından product.Price = -200; ile iş kuralını ihlal edecek bir güncelleme yapılmıştır fakat
property private set olduğu için derleme zamanında hata alacağı için ilgili yanlış kullanım hiç
yapılmamış olacaktır.
Burada dikkat edilmesi gereken diğer nokta ise görüldüğü gibi RDM sonrası Product sınıfı
validasyon da yapabilmektedir. Örneğin ReduceStock metodu içinde quantity kontrolü
yapılmaktadır. Bu durum iş kurallarının tek bir yerden yönetilmesini sağlayıp hem bakımı
kolaylaştırmaktadır hem de Product sınıfına bakan yeni bir developer iş kuralları hakkında çok
daha net fikir sahibi olmaktadır. Product sınıfı sadece veri taşımayıp aslında iş kurallarınıda
içerdiği için bir nevi dökümantasyon görevide görmektedir. Aynı durumu ADM özelinde
değerlendirirsek orada farklı farklı servislerden Product üzerindeki propertyler
değiştirilebileceği için bu iş kurallarının dağılmasını, yönetimin ve bakımın zorlaşmasına sebep
olmaktadır.
Son olarak ADM ve RDM yi Domain Driven Design yaklaşımıyla inceleyelim.
Domain-Driven Design (DDD), karmaşık yazılım sistemlerini iş gereksinimlerine uygun ve
sürdürülebilir hale getirmeyi amaçlayan bir yaklaşımdır. DDD, domain modelinin, iş kurallarını
ve veri yapısını gerçek dünya varlıklarını yansıtacak şekilde tasarlanmasını önerir. Bu
bağlamda, DDD Rich Domain Modeli önermektedir.
DDD’ye göre, domain nesneleri kendi iş kurallarını kapsamalıdır. ADM, domain nesnelerini
veriyi taşıyan yapılara dönüştürürken RDM, nesneleri anlamlı hale getirir. DDD, encapsulation
ilkesine önem verir. ADM’de iş kuralları domain nesnesinin dışında tanımlandığı için
encapsulation sağlanamaz. RDM ise encapsulation sağlayarak domain nesnelerini güvenli hale
getirir. DDD, modüler bir yapı önerir. ADM’de iş kuralları farklı servis sınıflarında
dağıldığından, modelin anlaşılması zorlaşabilir. RDM ise her domain nesnesinin iş kurallarını
içerdiğinden daha modüler bir yapı sunar.
Sonuç olarak Anemic Domain Model (ADM) ve Rich Domain Model (RDM) arasındaki temel
fark, domain nesnelerinin veriyi nasıl ele aldığı ve iş kurallarını nasıl kapsadığıdır. ADM basit
bir yapı sunar; fakat karmaşık sistemlerde iş mantığının dağılması ve iş kurallarının ihlal
edilebilmesi gibi sorunlara yol açabilir. RDM ise, veri ve iş kurallarını birleştirerek daha tutarlı,
anlamlı ve güvenli bir yapı sağlar.
Özellikle karmaşık iş kurallarına sahip sistemlerde, RDM daha modüler, kapsayıcı ve güvenilir
bir modelleme yaklaşımı sunar. Domain-Driven Design (DDD) perspektifinden bakıldığında,
RDM’nin encapsulation, tutarlılık ve anlaşılabilirlik açısından sağladığı avantajlar, sistemin
uzun vadede sürdürülebilirliğini artırır.
ADM basit projeler için uygun olabilirken, karmaşık iş kurallarına sahip büyük projelerde RDM
daha tutarlı, bakımı kolay ve iş gereksinimlerine uyumlu bir yapı sunar.
İyi çalışmalar.