DDD (Domain-Driven Design) w C# — building blocks na przykładach
Domain-Driven Design (Eric Evans, 2003) to podejście, w którym kod modeluje realny język i reguły biznesu, nie tylko tabele w bazie danych. Zamiast zaczynać projektowanie od schematu SQL, zaczynasz od pytania: jak eksperci biznesowi nazywają te pojęcia i jakie mają reguły? Poniżej — pięć podstawowych “klocków” DDD, każdy na realnym kodzie C#.
Ubiquitous Language — wspólny język w kodzie
Nazwy klas i metod powinny brzmieć dokładnie tak, jak mówi o nich ekspert biznesowy — nie jak brzmiałoby to wygodniej dla programisty.
// ❌ Nazwy techniczne, oderwane od języka biznesu
public class OrderProcessor { public void Process(OrderDto dto) { } }
// ✅ Nazwy, których użyłby ekspert od sprzedaży
public class Zamowienie
{
public void ZlozZamowienie() { }
public void Anuluj() { }
public void OznaczJakoWyslane() { }
}Gdy kod i rozmowa z biznesem używają tych samych słów, tłumaczenie między “tym, co chce biznes” a “tym, co robi kod” znika — to jeden z głównych powodów, dla których DDD w ogóle istnieje.
Entity — tożsamość ważniejsza niż wartości pól
public class Zamowienie // Entity — ma tożsamość (Id), która nie zmienia się przez cały cykl życia
{
public int Id { get; }
public string Status { get; private set; } = "Nowe";
public Zamowienie(int id) => Id = id;
public void OznaczJakoWyslane() => Status = "Wysłane";
}
var a = new Zamowienie(5);
var b = new Zamowienie(5);
// a i b reprezentują TO SAMO zamówienie (ta sama tożsamość Id), nawet jeśli stan się różniEntity to obiekt, którego tożsamość (zwykle Id) definiuje go bardziej niż aktualne wartości jego pól — zamówienie #5 pozostaje “tym samym” zamówieniem, niezależnie od tego, ile razy zmieni się jego status.
Value Object — wartość ważniejsza niż tożsamość
public record Adres(string Ulica, string Miasto, string KodPocztowy); // Value Object — bez Id
var a1 = new Adres("Długa 5", "Warszawa", "00-001");
var a2 = new Adres("Długa 5", "Warszawa", "00-001");
Console.WriteLine(a1 == a2); // True — te same wartości = ten sam obiekt logicznieOdwrotnie niż Entity: Adres nie ma tożsamości — dwa adresy o tych samych wartościach są równoważne, kropka. Value Objects zasługują na osobny, dogłębny artykuł — sprawdź Value Object w DDD — implementacja w C# z rekordem, gdzie rozkładamy je znacznie szerzej.
Aggregate — granica spójności
public class Zamowienie // Aggregate Root — jedyny punkt wejścia do modyfikacji całego agregatu
{
private readonly List<PozycjaZamowienia> _pozycje = new();
public IReadOnlyList<PozycjaZamowienia> Pozycje => _pozycje;
public void DodajPozycje(Produkt produkt, int ilosc)
{
if (ilosc <= 0) throw new ArgumentException("Ilość musi być dodatnia");
_pozycje.Add(new PozycjaZamowienia(produkt, ilosc));
}
}Zamowienie to Aggregate Root — kod z zewnątrz nigdy nie modyfikuje _pozycje bezpośrednio, tylko przez metody Zamowienie (DodajPozycje), które pilnują reguł spójności (np. dodatnia ilość). Agregat to granica, w obrębie której wszystkie reguły biznesowe są zawsze spełnione.
Repository — dostęp do agregatów bez ujawniania szczegółów bazy
public interface IZamowieniaRepository
{
Zamowienie? ZnajdzPoId(int id);
void Zapisz(Zamowienie zamowienie);
}Repository udostępnia agregaty tak, jakby żyły w pamięci — kod domenowy nie wie, czy ZnajdzPoId odpytuje SQL Server, czy plik JSON. To ten sam mechanizm, który napędza regułę zależności w Clean Architecture — DDD i Clean Architecture naturalnie się uzupełniają.
Kiedy DDD to za dużo
Pełne DDD (bounded context, agregaty, event storming) ma sens dla złożonych domen biznesowych z realnymi regułami do wymodelowania. Dla prostego CRUD-a (lista zadań, blog) to narzut bez korzyści — KISS i YAGNI dotyczą też wyboru, ile DDD faktycznie potrzebujesz.
Podsumowanie
Pięć building blocków DDD, które zobaczysz w niemal każdym poważniejszym projekcie .NET: Ubiquitous Language (nazwy z języka biznesu), Entity (tożsamość ważniejsza niż wartości), Value Object (odwrotnie — wartość, nie tożsamość), Aggregate (granica spójności z jednym punktem wejścia) i Repository (dostęp do agregatów bez ujawniania bazy danych). Każdy z nich rozwiązuje inny, konkretny problem modelowania — DDD to nie jeden wzorzec, tylko zestaw narzędzi do wyboru zależnie od złożoności domeny, którą modelujesz.
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
1 comment
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →
Keep up the good work!