Skip to main content
Yazılım Geliştirme

Domain-Driven Design (DDD): Türkçe Kapsamlı Rehber

Mart 06, 2026 7 dk okuma 24 views Raw
Ayrıca mevcut: en
Domain-Driven Design yazılım modelleme konsept görseli
İçindekiler

Domain-Driven Design Nedir?

Domain-Driven Design (DDD), karmaşık yazılım projelerinde iş alanını (domain) merkeze alan bir yazılım geliştirme yaklaşımıdır. 2003 yılında Eric Evans tarafından yayımlanan "Domain-Driven Design: Tackling Complexity in the Heart of Software" kitabıyla yazılım dünyasına kazandırılmıştır. DDD'nin temel felsefesi, yazılımın teknik detaylarından önce iş alanının derinlemesine anlaşılması ve bu anlayışın doğrudan koda yansıtılmasıdır.

Geleneksel yazılım geliştirme yaklaşımlarında teknik altyapı ve veritabanı şeması öncelikli olarak tasarlanır. DDD ise bunun tam tersini savunur: önce iş alanını anlayın, ardından bu anlayışı kodda modelleyin. Bu yaklaşım özellikle büyük, karmaşık ve sürekli değişen iş kurallarına sahip projelerde muazzam bir fark yaratır.

Ubiquitous Language: Ortak Dil

DDD'nin en temel kavramlarından biri Ubiquitous Language, yani ortak dildir. Bu kavram, yazılım ekibi ile iş uzmanlarının aynı terminolojiyi kullanmasını ifade eder. Kodda kullanılan sınıf isimleri, metot adları ve değişkenler, iş uzmanlarının günlük konuşmalarında kullandığı terimlerle birebir örtüşmelidir.

Örneğin bir e-ticaret projesinde iş uzmanları "sipariş", "sepet", "iade" gibi terimler kullanıyorsa, kodda da Order, Cart, Return gibi isimler kullanılmalıdır. Bu ortak dil sayesinde iş uzmanları kodu okuyabilir, geliştiriciler ise iş kurallarını doğru şekilde anlayabilir.

Ortak dil yalnızca bir isimlendirme kuralı değildir; ekip içindeki iletişim kopukluğunu ortadan kaldıran stratejik bir araçtır.

Stratejik DDD Kavramları

Stratejik DDD, sistemin büyük resmine odaklanır. Büyük ve karmaşık sistemleri yönetilebilir parçalara bölmek için kullanılan üst düzey kavramları içerir.

Bounded Context (Sınırlı Bağlam)

Bounded Context, DDD'nin belki de en önemli stratejik kavramıdır. Bir bounded context, belirli bir modelin geçerli olduğu sınırları tanımlar. Aynı terim farklı bağlamlarda farklı anlamlara gelebilir. Örneğin "müşteri" kavramı satış bağlamında farklı, destek bağlamında farklı niteliklere sahiptir.

Her bounded context kendi modelini, kendi veritabanını ve kendi iş kurallarını barındırır. Bu sayede ekipler birbirinden bağımsız çalışabilir ve bir bağlamdaki değişiklik diğerlerini etkilemez.

Context Mapping (Bağlam Haritası)

Bounded context'ler birbirinden tamamen izole değildir; aralarında iletişim gerekir. Context mapping, bu bağlamlar arasındaki ilişkileri ve entegrasyon desenlerini tanımlar. Başlıca context mapping desenleri şunlardır:

  • Shared Kernel: İki bağlamın ortak bir model parçasını paylaşması
  • Customer-Supplier: Bir bağlamın diğerine hizmet sağlaması
  • Conformist: Bir bağlamın diğerinin modeline uyum sağlaması
  • Anti-Corruption Layer: Dış sistemlerden gelen verilerin kendi modeline dönüştürülmesi
  • Open Host Service: Bir bağlamın genel bir protokol üzerinden hizmet sunması
  • Published Language: Bağlamlar arası iletişim için standart bir dil tanımlanması

Subdomain (Alt Alan)

Her iş alanı birden fazla alt alana ayrılabilir. DDD, alt alanları üç kategoride sınıflandırır:

  1. Core Domain: İşletmenin rekabet avantajı sağladığı, en kritik alt alan. En yetenekli geliştiriciler burada çalışmalıdır.
  2. Supporting Domain: Core domain'i destekleyen ancak rekabet avantajı sağlamayan alanlar.
  3. Generic Domain: Her işletmede benzer şekilde bulunan genel alanlar. Kimlik doğrulama, e-posta gönderimi gibi.

Taktik DDD Kavramları

Taktik DDD, bounded context içindeki yapı taşlarını tanımlar. Bu kavramlar doğrudan kodla ilişkilidir ve modelin nasıl uygulanacağını belirler.

Entity (Varlık)

Entity, benzersiz bir kimliğe sahip olan ve yaşam döngüsü boyunca bu kimlikle takip edilen nesnedir. İki entity'nin tüm özellikleri aynı olsa bile kimlikleri farklıysa farklı nesnelerdir. Örneğin iki müşterinin adı ve adresi aynı olsa bile müşteri numaraları farklıysa bunlar farklı müşterilerdir.

Entity'ler değişebilir (mutable) nesnelerdir. Durumları zamanla değişir ancak kimlikleri sabit kalır. Bir siparişin durumu "hazırlanıyor"dan "kargoya verildi"ye değişebilir ama sipariş numarası aynı kalır.

Value Object (Değer Nesnesi)

Value Object, kimliği olmayan ve yalnızca değerleriyle tanımlanan nesnedir. İki value object'in tüm özellikleri aynıysa eşittirler. Adres, para birimi, tarih aralığı gibi kavramlar value object olarak modellenir.

Value object'ler değişmez (immutable) olmalıdır. Bir değişiklik gerektiğinde mevcut nesne değiştirilmez, yeni bir nesne oluşturulur. Bu özellik thread safety ve önbellek tutarlılığı açısından büyük avantaj sağlar.

Aggregate ve Aggregate Root

Aggregate, birbiriyle yakından ilişkili entity ve value object'lerden oluşan bir kümedir. Her aggregate'in bir kök entity'si (aggregate root) vardır ve dış dünya yalnızca bu kök üzerinden aggregate ile etkileşime girer.

Aggregate'ler tutarlılık sınırlarını belirler. Bir aggregate içindeki tüm değişiklikler tek bir işlemde (transaction) gerçekleştirilir. Sipariş aggregate'ini düşünün: sipariş (root), sipariş kalemleri ve teslimat adresi tek bir birim olarak yönetilir.

Aggregate tasarımında dikkat edilmesi gereken kurallar:

  • Aggregate'leri mümkün olduğunca küçük tutun
  • Aggregate'ler arası referanslar yalnızca kimlik (ID) üzerinden olmalıdır
  • Bir işlemde yalnızca bir aggregate güncellenmelidir
  • Aggregate sınırları iş kurallarına göre belirlenmelidir

Domain Event (Alan Olayı)

Domain event, iş alanında gerçekleşen önemli bir olayı temsil eder. "SiparişOluşturuldu", "ÖdemeAlındı", "ÜrünStoktanDüşürüldü" gibi olaylar domain event örnekleridir. Bu olaylar geçmişte gerçekleşmiş durumları ifade eder ve değiştirilemezdir.

Domain event'ler aggregate'ler arası iletişimi sağlamanın en etkili yoludur. Bir aggregate değiştiğinde olay yayımlar, ilgili diğer aggregate'ler bu olaya tepki verir. Bu yaklaşım loose coupling sağlar ve sistemi daha esnek hale getirir.

Repository (Depo)

Repository, aggregate'lerin kalıcı depodan (veritabanı) alınması ve kaydedilmesi için bir soyutlama katmanıdır. Domain katmanı, verinin nasıl saklandığını bilmez; yalnızca repository arayüzüyle çalışır.

Her aggregate root için bir repository tanımlanır. Repository, koleksiyon benzeri bir arayüz sunar: ekleme, silme, kimliğe göre bulma gibi temel işlemler içerir.

Domain Service (Alan Hizmeti)

Bazı iş kuralları tek bir entity veya value object'e doğal olarak ait değildir. Bu tür kurallar domain service olarak modellenir. Örneğin iki hesap arasında para transferi işlemi ne gönderen ne de alıcı hesaba aittir; bu bir domain service'dir.

Domain service'ler durumsuz (stateless) olmalıdır ve yalnızca iş mantığı içermelidir. Altyapısal kaygılar (veritabanı erişimi, dış servis çağrıları) domain service'lerde bulunmamalıdır.

DDD ve .NET Ekosistemi

.NET ekosistemi DDD uygulamak için son derece uygun bir platform sunar. C# dilinin zengin tip sistemi, entity ve value object modellemeyi kolaylaştırır. Record türleri value object'ler için mükemmel bir yapıdır.

ABP Framework, .NET dünyasında DDD prensiplerini doğrudan destekleyen güçlü bir altyapıdır. Entity, AggregateRoot, ValueObject temel sınıfları, repository arayüzleri ve domain event mekanizması hazır olarak sunulur. Entity Framework Core ile aggregate persistence sorunsuz şekilde yönetilir.

MediatR kütüphanesi domain event'lerin yayımlanması ve işlenmesi için yaygın olarak kullanılır. CQRS (Command Query Responsibility Segregation) deseni ile birleştirildiğinde okuma ve yazma işlemleri ayrıştırılarak performans ve ölçeklenebilirlik artırılır.

DDD Uygulama Katmanları

DDD tabanlı bir uygulama tipik olarak dört katmandan oluşur:

  1. Domain Layer: Entity, value object, aggregate, domain event ve repository arayüzlerini içerir. Hiçbir dış bağımlılığı yoktur.
  2. Application Layer: Use case'leri koordine eder. Domain nesnelerini kullanarak iş akışlarını yönetir. DTO dönüşümleri burada yapılır.
  3. Infrastructure Layer: Repository uygulamaları, veritabanı erişimi, dış servis entegrasyonları burada bulunur.
  4. Presentation Layer: API controller'lar, UI bileşenleri ve kullanıcı etkileşimi burada yönetilir.

Bu katmanlı yapıda bağımlılık yönü her zaman dıştan içe doğrudur. Domain katmanı hiçbir şeye bağımlı değildir; diğer tüm katmanlar domain katmanına bağımlıdır.

DDD Ne Zaman Kullanılmalı?

DDD her proje için uygun değildir. Basit CRUD uygulamalarında DDD gereksiz karmaşıklık ekler. DDD'nin gerçek değer kattığı senaryolar şunlardır:

  • Karmaşık ve sürekli değişen iş kurallarına sahip projeler
  • İş uzmanlarıyla yakın işbirliği gerektiren projeler
  • Uzun ömürlü ve sürekli gelişen sistemler
  • Birden fazla ekibin aynı sistem üzerinde çalıştığı projeler
  • Mikroservis mimarisine geçiş planlanan monolitik sistemler
DDD bir çerçeve veya teknoloji değil, bir düşünce biçimidir. Önemli olan araçları körü körüne uygulamak değil, iş alanını derinlemesine anlamak ve bu anlayışı koda yansıtmaktır.

Sık Yapılan Hatalar

DDD uygularken dikkat edilmesi gereken yaygın hatalar vardır:

  • Anemic Domain Model: Entity'lerin yalnızca veri taşıdığı, iş mantığının service'lere taşındığı model. DDD'nin tam tersidir.
  • Büyük Aggregate'ler: Çok fazla entity'yi tek bir aggregate'e dahil etmek performans ve eşzamanlılık sorunlarına yol açar.
  • Teknik Odaklı Modelleme: Modeli veritabanı şemasına göre tasarlamak yerine iş alanına göre tasarlamak gerekir.
  • Ortak Dili İhmal Etmek: Kodda teknik jargon kullanıp iş terimlerini göz ardı etmek DDD'nin temel ilkesine aykırıdır.
  • Her Yerde DDD Uygulamak: Generic domain'lerde DDD uygulamak zaman kaybıdır; odak core domain'de olmalıdır.

Sonuç

Domain-Driven Design, karmaşık yazılım projelerinde sürdürülebilir ve anlaşılır bir mimari oluşturmanın en etkili yollarından biridir. Stratejik DDD ile sistemi anlamlı parçalara böler, taktik DDD ile bu parçaları doğru şekilde modeller ve kodlarsınız. Ortak dil sayesinde ekip içi iletişimi güçlendirir, bounded context'ler sayesinde bağımsız geliştirme yapabilirsiniz.

DDD öğrenme eğrisi yüksek bir yaklaşımdır ancak doğru projelerde uygulandığında getirisi çok büyüktür. Önemli olan küçük adımlarla başlamak, ortak dili benimsemek ve aggregate sınırlarını doğru çizmektir. .NET ekosistemi ve ABP Framework gibi araçlar bu yolculukta size güçlü bir altyapı sunar.

Bu yazıyı paylaş