Oyun Kitabı
Production'da DDD: Dağıtık Sistemler ve Modernizasyon Stratejileri (Productionda Ddd Dagitik Sistemler Ve Modernizasyon)
DDD production ortamında nasıl yaşatılır? Event Storming, Saga, Transactional Outbox, Anti-Corruption Layer ve Strangler Fig ile legacy dönüşüm rehberi.
Bu bölümün haritası
Bu bölümde tek tek desen ezberlemiyoruz. Monolith içindeki iş gerçeğini, değişim sırasında nasıl güvenle taşıyacağımızı izliyoruz.
Monolith
↓
Event Storming
↓
Bounded Context
↓
Saga
↓
Outbox
↓
Strangler Fig
↓
Production
Production'da asıl soru
DDD ile sınırları çizmek başlangıçtır. Production'da asıl sınav, bu sınırlar değişirken sistemi ve kullanıcı güvenini korumaktır. Eski monolith içindeki bir sipariş akışını bir gecede yeniden yazmak cazip görünebilir; ama en riskli seçenek genellikle budur.
Monolith → mevcut iş gerçeği
Yeni bağlam → daha temiz model
Kademeli geçiş → ölçülebilir güven
Amaç daha fazla servis üretmek değildir. Amaç, işin dili değiştiğinde sistemin de güvenle değişebilmesidir.
Kavramlar ilk geçtiği yerde
📦 Event Storming
İş olaylarını, komutları ve riskleri birlikte görünür kılan keşif atölyesi.
📦 Saga
Dağıtık bir iş akışındaki yerel işlemleri ve başarısızlıktaki iş telafisini yöneten model.
📦 Transactional Outbox
Veri değişikliği ile yayınlanacak event'i aynı yerel transaction içinde kaydeden desen.
📦 Strangler Fig
Legacy sistemi tek seferde değiştirmek yerine yeni sınırlarla adım adım saran dönüşüm stratejisi.
Bir domain event geçmiş zamanda yazılmış iş gerçeğidir: SiparişOnaylandı. Command ise niyettir: SiparişiOnayla. Bu ayrım gerekir; çünkü niyet reddedilebilir, olmuş bir gerçek ise diğer bağlamların güvenle tepki verebileceği kayıttır.
Event Storming ile önce görünmeyen akışı bulun
Production dönüşümü kod envanteriyle değil, iş akışıyla başlar. Ürün, operasyon ve mühendislik aynı duvarda olayları geçmiş zamanda sıralar; komutları, aktörleri, dış sistemleri ve kırmızı hot spot'ları ekler.
SiparişOnaylandı ← SiparişiOnayla ← Customer
↓
StokRezerveEdildi ← StokRezerveEt
↓
ÖdemeAlındı ← ÖdemeyiAl ← Payment Gateway
Akışı sondan başa da okuyun. Ters anlatı; iade, kısmi ödeme, zaman aşımı ve manuel müdahale gibi mutlu yolun sakladığı kararları görünür kılar. Bir Bounded Context, tablo adıyla değil; karar, dil ve sahiplik değiştiği yerde bulunur.
🎯 Bu bölümün amacı
Transaction sınırları dağıldığında iş tutarlılığını nasıl koruduğumuzu anlamak.
Bankadan para çekildiyse bir SQL rollback bunu geri alamaz. Stok başka bir bağlamda rezerve edildiyse, tek veritabanındaki geri alma da onu düzeltmez. Bu yüzden dağıtık sistemlerde geri alma yerine, iş etkisini telafi ederiz.
Saga: rollback değil, iş telafisi
Ödeme, stok ve teslimat farklı bağlamlarda yaşadığında tek ACID transaction yoktur. 2PC güçlü tutarlılık vaat edebilir; fakat koordinatör veya katılımcı arızasında kilit tutma ve erişilebilirlik bedeli taşır. Saga bunun yerine her yerel adım için bir telafi tanımlar.
Reserve inventory → Capture payment → Create shipment
payment fails → Release inventory
ReleaseInventory de idempotent olmalıdır; aynı event iki kez gelirse stok iki kez artmamalıdır. Kısa ve yerel akışlarda choreography yeterli olabilir. Çok adımlı, görünürlüğü kritik süreçlerde orchestration; durum makinesi ve tek gözlem noktası sağlar.
🎯 Bu bölümün amacı
Veritabanı kaydı ile event yayınlama arasındaki boşluğu kapatmak.
Sipariş başarıyla kaydedildi. Tam o anda broker çöktü. Sipariş vardır ama OrderConfirmed event'i yoktur; kargo ve bildirim akışı sessizce geride kalır. Outbox bu boşluğu, kaydı ve yayınlanacak event'i aynı yerel transaction içinde tutarak kapatır.
Outbox ve izlenebilirlik: geçişi kanıtlanabilir yapın
Bir sipariş commit olurken broker ulaşılamazsa, veritabanı ile mesaj yayınlama arasındaki dual-write boşluğu oluşur. Outbox bu yüzden vardır.
Local transaction
→ Order'ı kaydet
→ OrderConfirmed'i Outbox'a yaz
→ Commit
Relay → Broker → Consumer → Projection
Consumer'lar at-least-once teslimatta duplicate mesaj beklemelidir. Event ID, aggregate version ve iş etkisi kontrol edilmelidir. Correlation ID bir uçtan uca akışın parçasını, causation ID ise event'i hangi kararın ürettiğini gösterir. Bunlar log alanı değil; incident anında “ne oldu?” ve “neden oldu?” sorularının cevabıdır.
🎯 Bu bölümün amacı
Legacy davranışı kaybetmeden yeni bir domain sınırına geçmek.
On yıldır çalışan bir ERP sistemini bir hafta sonunda yeniden yazamazsınız. Önce yeni modelin eski davranışla nerede ayrıştığını canlı trafik altında ölçer, sonra küçük ve geri alınabilir adımlarla yönlendirme yaparsınız.
Strangler Fig ile legacy dönüşümü
Big-bang dönüşüm, iş kuralları keşfedilmeden eski davranışı kaybetme riskidir. Yeni bağlamı legacy'nin yanına alın; önce veri ve davranış farkını ölçün, sonra trafik yönlendirin.
1. Replication only → yeni modele veri akıt
2. Shadow reads → eski ve yeni cevabı karşılaştır
3. Partial reads → küçük trafik yüzdesini yönlendir
4. Write migration → yeni sınırda yaz, geri uyumu koru
5. Full cutover → metriklerle doğrulanmış geçiş
6. Decommission → köprüleri ve eski kodu kaldır
Anti-Corruption Layer burada yeni modelin kalkanıdır. Legacy'nin belirsiz alanlarını doğrudan domain'e taşımak yerine çevirir: LEGACY_ORDER_STATE=7 yeni bağlamda anlamlı bir FulfilmentStatus olur. Böylece kirli modelin etkisi tek adaptörde kalır.
Kabul kriteri: sadece deploy değil, geri dönüş kabiliyeti
Geçişin başarısı yalnızca yeni endpoint'in cevap vermesi değildir. Shadow read fark oranı, P95 gecikme farkı, consumer lag, DLQ derinliği ve rollback planı görünür olmalıdır. Replay maliyeti event sayısına göre O(n)'dir; snapshot veya segmentli replay bu maliyeti azaltabilir, fakat doğrulanmış geçmişin yerini tutmaz.
Gözlemlenemeyen sistem yönetilemez. Her event sözleşmesinin sahibi, sürüm stratejisi, alarmı ve tekrar oynatma runbook'u olmalıdır.
Yanlış güven duygusu oluşturan eşleştirmeler
❌ DDD = mikroservis dönüşümü
✓ DDD önce iş dilini ve karar sınırını korur; mikroservis bazen sonuçtur.
❌ Saga = teknik rollback
✓ Saga, geri alınamayan iş etkisini telafi eden iş akışıdır.
❌ Outbox = exactly-once teslimat
✓ Outbox event kaybını önler; consumer yine duplicate için idempotent olmalıdır.
❌ Shadow read = test tamamlandı
✓ Karşılaştırma, canlı trafikte davranış farkını ölçen uzun süreli kanıttır.
❌ ACL = gereksiz katman
✓ ACL, legacy dilinin yeni domain'i kirletmesini engeller.
Production hazırlık kontrol listesi
- Event Storming'de mutlu yol dışındaki hot spot'lar ve dış sistemler görünür mü?
- Her Saga adımının idempotent telafisi tanımlı mı?
- Outbox, broker arızasında veritabanı kaydı ile event arasındaki boşluğu kapatıyor mu?
- Correlation ID, causation ID, consumer lag ve DLQ için gözlemlenebilirlik var mı?
- Yeni bağlam legacy modelini ACL ile koruyor mu?
- Shadow read, kademeli trafik ve rollback için ölçülebilir eşikler belirlendi mi?
- Eski köprülerin kaldırılacağı tarih ve sahibi açık mı?
Bir dönüşümün karmaşıklığı servis sayısıyla ölçülmez. Bağımsız değişim, hata izolasyonu ve geri dönüş kanıtı ile ölçülür.
Bu yazıdan aklında ne kalmalı
- Production'da DDD, modelin değişim altında da iş diline sadık kalmasıdır.
- Event Storming koddan önce görünmeyen kararları ve riskleri keşfeder.
- Saga, Outbox ve idempotency dağıtık başarısızlıkları tasarım girdisi kabul eder.
- Strangler Fig ve ACL, legacy dönüşümünü bir sıçrama yerine doğrulanabilir adımlara böler.
Modernizasyon, eski sistemi yok etmek değil; işin değerini kaybetmeden daha güvenli bir değişim ritmi kurmaktır.
SSS
Sık sorulan sorular
Event Storming nedir?
İş olaylarını, komutları ve riskleri birlikte görünür kılan keşif atölyesi.
Saga nedir?
Dağıtık bir iş akışındaki yerel işlemleri ve başarısızlıktaki iş telafisini yöneten model.
"DDD = mikroservis dönüşümü" doğru mu?
DDD önce iş dilini ve karar sınırını korur; mikroservis bazen sonuçtur.
Bu bölüm neyi sabitler?
Amaç daha fazla servis üretmek değildir. Amaç, işin dili değiştiğinde sistemin de güvenle değişebilmesidir. Production'da DDD, modelin değişim altında da iş diline sadık kalmasıdır. DDD ile sınırları çizmek başlangıçtır. Production'da asıl sınav, bu sınırlar değişirken sistemi ve kullanıcı güvenini korumaktır. Eski monolith içindeki bir sipariş akışını bir gecede yeniden yazmak cazip görünebilir; ama en riskli seçenek genellikle budur.
Ogrenilen Muhendislik Prensipleri
- Production DDD, event'lerin ve sınırların hata altında da iş anlamını korumasını gerektirir.
- Saga, Outbox ve idempotency; dağıtık teslimatın istisna değil normal olduğunu kabul eder.
- Strangler Fig ile ACL, legacy dönüşümünde değişimi küçük, ölçülebilir ve geri alınabilir tutar.
Okumaya devam et
Okumaya devam et
Ilgili yazilar
DDD Büyük Sistemlerde Nasıl Çalışır?
DDD büyük sistemlerde nasıl ölçeklenir? Bounded Context, Context Mapping, Conway Yasası, modüler monolith, mikroservis sınırları ve Transactional Outbox…
Ilgili yazilar
Production'da CQRS (Command Query Responsibility Segregation): Tutarlılık, Hatalar ve Kurtarma Stratejileri
CQRS production ortamında nasıl güvenli çalışır? Consistency lag, duplicate event, sıra bozulması, projection recovery, retry, DLQ ve Saga stratejileri.
Ilgili yazilar
Bir Vertical Slice İçeriden Nasıl Çalışır?
Bir Vertical Slice request'ten doğrulamaya, handler'dan aggregate'e, outbox event'inden read model'e ve bulut maliyetine kadar içeriden nasıl akar? CQRS…