Oyun Kitabı

DDD- Yazılımı Veritabanına Göre Değil, İşe Göre Tasarlamak (Ddd Yazilimi Veritabanina Gore Degil İse Gore Tasarlamak)

Domain-Driven Design nedir? Veritabanı odaklı tasarımın sınırlarını, ortak dilin gücünü ve DDD'nin ne zaman gerçek bir yatırım olduğunu anlatan rehber.

A software model shaped by business language rather than database tables

Aynı domain, büyüyen kararlar

Bu bölüm boyunca tek bir e-ticaret sipariş sistemi düşünelim. İlk yıl Order, müşterinin seçtiği ürünleri ve toplam tutarı taşıyan basit bir kayıttır. CRUD bunun için yeterlidir.

1. yıl → sipariş oluştur, listele, güncelle
2. yıl → kampanya ve indirim
3. yıl → iade ve kısmi ödeme
4. yıl → taksit, stok rezervasyonu ve teslimat
5. yıl → fraud kontrolü ve ülkeye göre vergi

Her yeni ihtiyaç, Order sınıfına yalnızca alan eklemez; yeni bir karar ekler. Domain, yazılımın değil, işletmenin çözmeye çalıştığı problemdir. Bu örnekte domain; siparişi güvenle kabul etme, ücretlendirme, ödeme, iade ve teslimatı yönetme işidir.

Önce problem: kod neden işin dilini kaybeder?

Bir ürün ilk günlerinde çoğu zaman basittir: tabloyu çizer, endpoint'i yazar, kaydı ekleriz. Bu yaklaşım yanlış değildir. Ancak fiyatlandırma, iade, risk, teslimat ve yetki kuralları çoğaldığında sistemin değeri tablolarda değil; bu kararların doğru uygulanmasındadır.

Veritabanı → Table → CRUD → Service katmanı → dağınık iş kuralları

İş dünyası → Ortak dil → Domain modeli → Kod → görünür kararlar

DDD, teknolojiyi reddetmez. Tasarımın başlangıç noktasını değiştirir: şema değil, işin anlamı.

Kavramlar ilk geçtiği yerde

📦 Domain
Sistemin çözmeye çalıştığı iş alanı: örneğin sipariş, kredi veya sigorta.

📦 Domain modeli
İşin kurallarını, kavramlarını ve geçişlerini kodda temsil eden model.

📦 Ubiquitous Language / Ortak Dil
İş uzmanı, ürün ve yazılım ekibinin aynı kavram için aynı adı kullanması.

📦 Core Domain
Ürünü gerçekten farklılaştıran ve en yüksek karar karmaşıklığını taşıyan iş alanı.

PlaceOrder bir teknik çağrıdan fazlasıdır: sipariş verme niyetini taşır. Başarılı olduğunda OrderPlaced bir iş gerçeği olur. İsimler işin dilini taşımıyorsa, ekip her yeni özellikte yeniden tercüme yapar.

Aynı sipariş neden farklı katmanlarda bozulur?

Ürün ekibi “Preferred Customer” dediğinde geliştirici yalnızca Status = 1 görüyorsa, aynı kavram iki farklı dile bölünür. Bir sonraki kampanya kuralı hangi anlama göre yazılacaktır? Ortak dil bu belirsizliği daha kod yazılmadan azaltır.

Benzer şekilde order.Status = Paid tek başına güvenli bir davranış değildir:

order.Status = Paid
  ↓
Ödeme gerçekten doğrulandı mı?      → bilinmiyor
Stok rezerve edildi mi?             → bilinmiyor
Sipariş iptal edilmiş olabilir mi?  → bilinmiyor

order.ConfirmPayment(payment)
  ↓
ödeme kanıtını doğrular
gerekli iş kuralını çalıştırır
geçersiz geçişi reddeder

Davranışın amacı setter'ları yasaklamak değildir. Amaç, iş kuralının tek bir sahibi olmasını sağlamaktır. Ekip büyüklüğü de bu maliyeti değiştirir: bir veya iki kişinin kısa ömürlü uygulamasında CRUD'un basitliği kazanır; ondan fazla kişinin yıllarca geliştirdiği, kavramların sık değiştiği üründe ortak dil ve açık sahiplik daha hızlı geri döner.

CRUD neden uzun süre harika çalışır?

Ekip küçük, ürün tekil ve kurallar azsa Controller → Service → Repository → Database akışı hızlı ve anlaşılırdır. Basit kayıt ekranları, yönetim panelleri ve kısa ömürlü prototipler için bu basitlik gerçek bir avantajdır. DDD, CRUD'a karşı bir ideoloji değildir.

Kırılma, aynı tabloya daha fazla kayıt eklenince değil; aynı modelin farklı iş niyetlerini temsil etmek zorunda kalınca başlar. Bir Order bir anda kampanya, vergi, indirim, iade, stok rezervasyonu, teslimat ve risk kontrolü için kullanılır.

Database-first
OrderRow → status = 2 → UpdateOrderStatus()

Business-first
Order → ConfirmPayment() → ReserveInventory() → StartFulfilment()

İlk yaklaşım veriyi değiştirir; ikincisi iş kararını görünür kılar. Sorun kodun kısa veya uzun olması değildir. Sorun, modelin işin nedenlerini saklamasıdır.

Ortak dil: tercüme vergisini kaldırmak

İş uzmanı “tercihli müşteri” derken kod UserStatus = 1 diyorsa, sistemin iki farklı gerçeği vardır. Bu fark yeni ekip üyesinin yanlış anlamasına, kuralın farklı servislerde tekrarlanmasına ve toplantıların sürekli açıklama seansına dönüşmesine neden olur.

❌ InsertNewSchoolYear()
✓ OpenNewSchoolYear()

❌ UserStatus = 1
✓ customer.MarkAsPreferred()

❌ OrderRow
✓ LoanApplication / Order / Subscription

Ortak dil, her teknik ismi iş terimiyle değiştirmek değildir. Model, o bağlamdaki kararları açıklayacak kadar doğru olmalıdır. Harita nasıl tüm dünyayı değil, yolculuk için gerekli gerçekliği gösteriyorsa; domain modeli de her veriyi değil, ilgili iş kararını temsil eder.

Anemic model: veriyi nesne, davranışı prosedür yapmak

Kansız domain modeli, public setter'larla dolu entity'leri servis sınıflarının yönettiği yapıdır. OrderService, PricingService, DiscountService ve ShipmentService zamanla aynı kuralları farklı yerlerde taşımaya başlar. Nesne yalnızca veri taşır; davranış dışarıda kalır.

❌ order.Status = Paid
❌ order.Total = -10

✓ order.ConfirmPayment(payment)
✓ order.ApplyDiscount(discount)

Zengin modelin amacı her şeyi bir entity'ye koymak değildir. Ama sistemin asla bozulmaması gereken kurallarını davranışın yanında tutmaktır. Örneğin bir sipariş ödemesi doğrulanmadan kargoya verilemez. Bu kuralın tek sahibi olmalıdır.

DDD'nin bedeli ve doğru bağlamı

DDD; analiz, ortak dil oturumları, daha dikkatli isimlendirme ve ekip disiplini ister. Bu maliyet, basit veri girişinde geri dönmez. Karar, teknik heyecanla değil; domain karmaşıklığı ve değişim oranıyla alınmalıdır.

Sinyal CRUD daha uygundur DDD yatırımı anlamlıdır
İş kuralı Az ve stabil Katmanlı, kritik, sürekli değişen
Ürün ömrü Kısa prototip Uzun ömürlü ürün
Hata maliyeti Düşük Finansal veya operasyonel olarak yüksek
Ekip konuşması Tek anlamlı Aynı kavram farklı anlamlara geliyor

Kural sayısı arttıkça çözümün çalışma maliyeti çoğu zaman doğrusal değildir. Bir kural k farklı serviste tekrarlandığında değişiklik maliyeti en az O(k)'dir; kurallar birbirini etkiliyorsa test senaryoları daha hızlı büyür. DDD bu maliyeti sihirli biçimde sıfırlamaz; sahipliği ve sınırı görünür kılar.

İlk adım: kodu yeniden yazmak değil, dili gözlemlemek

  1. En pahalı kararların geçtiği iş akışını seçin.
  2. İş uzmanının kullandığı fiilleri ve isimleri kaydedin.
  3. Çelişen terimleri tek bir bağlam içinde netleştirin.
  4. Yeni davranışı, veri alanı güncellemesi yerine iş niyeti olarak modelleyin.
  5. Sadece bu sınırda geçersiz durumu engelleyen davranışları bir araya getirin.

Bu süreçte veritabanı, framework ve API adaptördür; domain kararının sahibi değildir.

Yanlış güven duygusu oluşturan eşleştirmeler

❌ DDD = katmanlı mimari
✓ DDD = karmaşık iş alanını modelleme disiplini

❌ DDD = çok fazla interface
✓ DDD = kararların ve kuralların doğru sahibini bulmak

❌ Her projede DDD gerekir
✓ Yatırım, karmaşık ve değişen domain'de geri döner

❌ Aggregate = entity grubu
✓ Aggregate = tutarlılığın korunacağı transaction sınırı

❌ Repository = her tablo için vardır
✓ Repository, domain'de anlamlı aggregate root'lar içindir

Karar kontrol listesi

  • En pahalı iş hatası hangi kural ihlal edildiğinde oluşuyor?
  • İş uzmanı ve kod aynı kavramı aynı kelimeyle mi anıyor?
  • Bir durum değişikliği status = 2 mi, yoksa anlamlı bir iş davranışı mı?
  • Kuralın tek sahibi var mı; yoksa farklı servislerde mi tekrar ediliyor?
  • Bu domain yeterince karmaşık mı ki analiz maliyeti uzun vadede geri dönsün?

Bu sorulara net yanıt yoksa önce entity veya framework seçmeyin. Önce problemi, dili ve sınırı netleştirin.

Bu yazıdan aklında ne kalmalı

  1. DDD, veritabanına karşı değil; iş kuralının veriden daha değerli olduğunu kabul eden bir tasarım yaklaşımıdır.
  2. Ortak dil, toplantı notu değil; kodun, API'nin ve kararların sözleşmesidir.
  3. Kansız model, davranışı servis katmanına dağıtarak geçersiz durum riskini büyütür.
  4. DDD her projede değil; karmaşıklığın ve değişimin maliyet ürettiği yerde yatırım geri döner.

Yazılımın değeri, veriyi saklamasında değil; işin doğru kararlarını uzun süre koruyabilmesindedir.

Bir sonraki bölümde bu zihniyeti kod seviyesine indireceğiz: Value Object, Entity ve Aggregate sınırları.

Taktiksel desene geçmeden önce

Peki bu iş kararlarını kodun içinde nerede tutacağız? Value Object, Entity ve Aggregate gibi taktiksel DDD desenleri bu soruya cevap verir. Ancak bunlar başlangıç noktası değil; burada netleştirdiğimiz dili, kuralları ve sınırları koruyan araçlardır.

SSS

Sık sorulan sorular

Domain nedir?

Sistemin çözmeye çalıştığı iş alanı: örneğin sipariş, kredi veya sigorta.

Domain modeli nedir?

İşin kurallarını, kavramlarını ve geçişlerini kodda temsil eden model.

"DDD = katmanlı mimari" doğru mu?

DDD = karmaşık iş alanını modelleme disiplini

Ogrenilen Muhendislik Prensipleri

  • Tasarımın başlangıç noktası tablo değil, işin kararları ve ortak dili olmalıdır.
  • Davranış, geçersiz durumu engelleyebildiği domain sınırında yaşamalıdır.
  • DDD yatırımı; değişim oranı, hata maliyeti ve domain karmaşıklığıyla gerekçelendirilmelidir.

Okumaya devam et

Okumaya devam et

Ilgili yazilar

Ilgili yazilar

Ilgili yazilar

Paylaş