DDD ma sens tam, gdzie sam model danych przestaje wystarczać, a zaczyna liczyć się sposób myślenia o biznesie. W tym artykule pokazuję, czym jest projektowanie sterowane domeną, jak odróżnić jego część strategiczną od taktycznej i kiedy naprawdę pomaga w projektach webowych.
Nie będę robił z tego akademickiego wykładu. Zależy mi na praktycznej odpowiedzi: co wdrażać, w jakiej kolejności i jak nie pomylić dobrego modelu domeny z przerostem architektury.
Najważniejsze rzeczy o DDD widać dopiero wtedy, gdy system ma realne reguły biznesowe
- DDD nie jest frameworkiem, tylko sposobem projektowania oprogramowania wokół domeny biznesowej.
- Największą wartość daje tam, gdzie reguły są złożone, a pojęcia biznesowe łatwo się rozjeżdżają między zespołem i kodem.
- Strategiczne DDD porządkuje granice i język, zanim powstanie implementacja.
- Taktyczne wzorce pomagają modelować encje, obiekty wartości, agregaty, repozytoria i zdarzenia domenowe.
- W prostych CRUD-ach DDD zwykle dokłada więcej kosztu niż korzyści.
- Najlepiej zaczynać od jednego ważnego procesu, a nie od przebudowy całej aplikacji naraz.
Na czym polega projektowanie sterowane domeną
DDD, czyli projektowanie sterowane domeną, to podejście, w którym najpierw modeluję rzeczywisty problem biznesowy, a dopiero potem dobieram technologię, strukturę klas i sposób persystencji. W praktyce chodzi o to, żeby kod odzwierciedlał pojęcia ważne dla biznesu, a nie tylko wygodę bazy danych albo ORM-u.
To podejście szczególnie dobrze działa wtedy, gdy system ma więcej niż kilka prostych formularzy. Jeśli w aplikacji pojawiają się reguły typu „zamówienie można anulować tylko do określonego momentu”, „rabat zależy od segmentu klienta” albo „jedna zmiana wpływa na kilka obszarów”, zwykły model CRUD szybko robi się chaotyczny. DDD porządkuje ten chaos, bo zmusza do nazwania pojęć, granic i odpowiedzialności.
Najkrócej mówiąc: DDD pomaga budować software, który rozumie domenę, zamiast tylko przechowywać dane. I właśnie dlatego tak dobrze pasuje do systemów webowych, które z czasem rosną i zaczynają żyć własnym życiem. Żeby to jednak zadziałało, trzeba najpierw dobrze ustawić granice pojęć i odpowiedzialności, a do tego służy część strategiczna.

Strategiczne DDD porządkuje system zanim napiszesz kod
Strategiczne DDD odpowiada na pytanie: gdzie w ogóle przebiega logika biznesowa i jak ją podzielić, żeby nie zrobić jednego wielkiego modelu do wszystkiego. To jest warstwa, którą zbyt łatwo się pomija, a potem zespół przez lata walczy z jednym „uniwersalnym” modelem, który nikomu już nie pasuje.
Ujednolicony język zmniejsza liczbę nieporozumień
Ubiquitous language, czyli wspólny język domeny, oznacza, że biznes i zespół techniczny używają tych samych nazw dla tych samych pojęć. Jeśli ktoś mówi „abonament”, a ktoś inny ma na myśli „subskrypcję próbną”, „plan taryfowy” albo „umowę”, to nie jest detal. To sygnał, że model nie jest jeszcze dopracowany.
Ja zwykle sprawdzam to bardzo prosto: jeśli dwa działy używają tego samego słowa, ale znaczą ono coś innego, model trzeba rozdzielić albo doprecyzować. Właśnie wtedy zaczyna się prawdziwe projektowanie domeny, a nie tylko rysowanie diagramów.
Bounded context wyznacza granice znaczeń
Bounded context to wyraźna granica, w której dany model i jego język mają sens. To ważne, bo to samo słowo może znaczyć coś innego w różnych częściach systemu. „Klient” w sprzedaży może oznaczać nabywcę, a w supportcie osobę zgłaszającą problem. Próba pogodzenia tego w jednym modelu kończy się zwykle niepotrzebnym komplikowaniem klas i warstw.W praktyce bounded context pozwala powiedzieć: tutaj obowiązuje ten model, a tamten obszar ma własne reguły. Dzięki temu system przestaje udawać, że całe przedsiębiorstwo da się zamknąć w jednej strukturze obiektów.
Przeczytaj również: Wzorce projektowe - Czy na pewno ich potrzebujesz?
Context map pokazuje, jak konteksty współpracują
Kiedy granice są już nazwane, trzeba jeszcze ustalić, jak te części systemu ze sobą rozmawiają. Tu przydaje się context map, czyli mapa zależności między kontekstami. W prostych projektach wystarczy kilka jasnych relacji, ale w większych systemach to robi ogromną różnicę, bo ogranicza przypadkowe sprzężenia.
Najczęściej chodzi o to, żeby jeden kontekst nie „wciągał” modelu drugiego bezpośrednio. Zamiast tego stosuje się jawne kontrakty, tłumaczenie pojęć albo warstwę antykorupcyjną, jeśli integrujesz się z legacy lub zewnętrznym systemem. To właśnie na tym etapie architektura zaczyna wspierać biznes, a nie odwrotnie.
Gdy granice są jasne, można zejść poziom niżej i zdecydować, jak ten model ma wyglądać w kodzie.
Taktyczne wzorce pokazują, jak modelować kod
Taktyczne DDD daje zestaw pojęć, które pomagają przełożyć model domeny na kod. To tutaj pojawiają się encje, obiekty wartości, agregaty, repozytoria i zdarzenia domenowe. Bez tej warstwy DDD zostaje piękną ideą bez implementacji, ale bez strategicznej warstwy szybko zamienia się w zbiór modnych klas bez sensu.
| Pojęcie | Rola | Jak je rozpoznać | Przykład |
|---|---|---|---|
| Encja | Ma tożsamość i może zmieniać stan w czasie | Ważne jest „który obiekt”, a nie tylko „jaki ma zestaw danych” | Order, User, Invoice |
| Obiekt wartości | Opisuje cechę lub stan, bez własnej tożsamości | Dwa obiekty są równe, jeśli mają te same wartości | Money, Address, DateRange |
| Agregat | Grupuje obiekty i pilnuje niezmienników | Jest granicą spójności dla ważnej reguły biznesowej | Zamówienie z pozycjami |
| Repozytorium | Ukrywa szczegóły persystencji | Chcesz pobierać i zapisywać agregaty bez znajomości bazy | OrderRepository |
| Usługa domenowa | Obsługuje logikę, która nie pasuje do jednej encji | Operacja jest biznesowa, ale nie należy do konkretnego obiektu | Obliczanie ceny złożonej |
| Zdarzenie domenowe | Informuje, że coś istotnego zaszło w domenie | „Co się stało?” jest ważniejsze niż „kto to wywołał?” | OrderPaid, SubscriptionCancelled |
Warto też odróżnić repozytorium od samego ORM-u. Repozytorium to abstrakcja z perspektywy domeny, a nie „wygodny wrapper na Entity Framework”. Jeśli kod domeny zaczyna zależeć od detali technicznych, model traci autonomię i z czasem trudno go testować oraz rozwijać. Dopiero po takim uporządkowaniu łatwiej przejść do praktycznego wdrożenia w projekcie.
Jak wdrożyć DDD w projekcie webowym bez przeciążania zespołu
Najlepszy start nie polega na przepisywaniu całej aplikacji. Ja zaczynam od jednego procesu biznesowego, który naprawdę boli: na przykład składania zamówienia, obsługi płatności, rezerwacji terminu albo naliczania uprawnień abonamentowych. Jeśli ten fragment zaczyna działać czytelniej, dopiero wtedy warto rozciągać podejście na kolejne obszary.
- Spisz pojęcia używane przez biznes i sprawdź, gdzie znaczą to samo, a gdzie coś innego.
- Wybierz jeden proces, który ma najwięcej reguł albo najwięcej zmian.
- Odszukaj granicę kontekstu i zdecyduj, co naprawdę należy do jednego modelu.
- Ustal agregat i jego niezmienniki, czyli zasady, których model nie może łamać.
- Oddziel logikę aplikacyjną od domenowej, a persystencję trzymaj poza modelem.
- Dodaj testy reguł biznesowych, nie tylko testy kontrolerów i endpointów.
W projektach webowych dobrze sprawdza się też prosty podział: warstwa aplikacji orkiestruje przypadki użycia, domena podejmuje decyzje biznesowe, a infrastruktura zajmuje się bazą, kolejkami i integracjami. Taki układ nie jest ozdobą architektoniczną. On naprawdę ogranicza liczbę miejsc, w których reguła może się rozjechać. I co ważne, nie wymaga od razu mikrousług.
Jeśli budujesz system zamówień w e-commerce, dobrym pierwszym krokiem będzie wydzielenie osobnych kontekstów dla katalogu, koszyka, płatności i wysyłki. W każdym z nich pojęcie „zamówienie” albo „status” może znaczyć coś innego, więc wspólny model szybko przestaje być wspólny w praktyce. To właśnie jest jedna z najcenniejszych lekcji DDD: rozdzielaj to, co ma różne znaczenie biznesowe, nawet jeśli na pierwszy rzut oka wygląda podobnie. Z drugiej strony trzeba też uczciwie powiedzieć, że nie każdy projekt tego potrzebuje.
Kiedy DDD pomaga, a kiedy lepiej zostać przy prostszym modelu
DDD daje największy zwrot wtedy, gdy domena jest złożona, reguły często się zmieniają, a zespół musi rozumieć biznes naprawdę dobrze. Jeżeli aplikacja rośnie, dochodzą nowe kanały sprzedaży, integracje albo różne zespoły dotykają tych samych pojęć, dobrze opisany model domeny oszczędza mnóstwo chaosu. Gdy jednak system to głównie formularze, listy i proste operacje na rekordach, pełne DDD zwykle jest za ciężkie.
| Sytuacja | DDD ma sens | Dlaczego |
|---|---|---|
| System z wieloma regułami biznesowymi | Tak | Model pomaga utrzymać niezmienniki i porządek pojęć |
| Wiele zespołów rozwija różne części produktu | Tak | Bounded context ogranicza konflikty i przypadkowe zależności |
| Prosty panel administracyjny | Raczej nie | CRUDE bez złożonych reguł nie potrzebuje ciężkiego modelu |
| Krótko żyjący projekt lub MVP z niewielką logiką | Zwykle nie | Lepsza jest prostota i szybkość dostarczenia niż rozbudowana architektura |
| Legacy z wieloma zależnościami | Tak, ale ostrożnie | Najpierw trzeba wydzielić granice, potem dopiero zmieniać model |
Najczęstsze błędy? Widzę trzy powtarzające się schematy. Po pierwsze, modelowanie tabel zamiast decyzji biznesowych. Po drugie, traktowanie każdego rzeczownika jako osobnej encji. Po trzecie, mylenie DDD z mikrousługami, jakby jedno automatycznie wymuszało drugie. To nie jest prawda. DDD może działać w monolicie, modularnym monolicie i w architekturze usługowej, ale samo w sobie nie rozwiązuje problemu złego podziału odpowiedzialności.
Jeśli miałbym zostawić jedną praktyczną wskazówkę, powiedziałbym tak: nie zaczynaj od wzorców, tylko od decyzji biznesowych, które system musi chronić. Kiedy potrafisz nazwać te decyzje, reszta architektury staje się dużo prostsza. I właśnie to prowadzi do ostatniej rzeczy, o której warto pamiętać, zanim uznasz DDD za zakończone zadanie.
Co sprawdzać, żeby model domeny naprawdę pracował na biznes
Najlepszy sygnał, że idziesz dobrą drogą, jest bardzo przyziemny: gdy zmienia się reguła biznesowa, nie musisz rozbijać pół aplikacji. Kod staje się przewidywalny, testy opisują sens reguł, a rozmowa z biznesem jest prostsza, bo nazwy w systemie zaczynają odpowiadać temu, jak firma naprawdę mówi o swoim procesie.
- Jeśli pojęcia w kodzie i na spotkaniach brzmią podobnie, model jest na dobrej drodze.
- Jeśli reguły są zamknięte w jednym miejscu, łatwiej je testować i rozwijać.
- Jeśli konteksty nie mieszają znaczeń, system mniej cierpi przy kolejnych zmianach.
- Jeśli prosty CRUD wystarcza, nie ma sensu dokładać ciężkiej architektury „na zapas”.
W praktyce DDD nie wygrywa tym, że wygląda elegancko na diagramie. Wygrywa wtedy, gdy skraca drogę między rozmową o biznesie a działającym kodem. Jeżeli po kilku iteracjach nadal potrafisz opisać system językiem domeny, a nie tylko nazwami tabel i kontrolerów, to znaczy, że model robi dokładnie to, do czego został stworzony.