Domain-Driven Design (DDD)

DDD to podejście do projektowania złożonych systemów, szczególnie biznesowych, skupionych na modelu domeny, czyli odwzorowaniu zasad i procesów, według których działa organizacja. Model domenowy stanowi centrum systemu i opisuje logikę biznesową w sposób wierny rzeczywistości. DDD zakłada ścisłą współpracę zespołów technicznych i biznesowych poprzez wspólny język (Ubiquitous Language), który eliminuje nieporozumienia i odzwierciedla pojęcia domenowe w kodzie. DDD dzieli się na dwa poziomy:

  • Strategiczne DDD – skupia się na kontekście i relacjach między częściami systemu:
    • Bounded Context – jasno określony obszar, w którym obowiązuje dany model.
    • Context Map – mapa relacji między kontekstami.
  • Taktyczne DDD – konkretne wzorce projektowe, jak:
    • Encje (Entities) — obiekty z tożsamością,
    • Agregaty (Aggregates) — grupy powiązanych obiektów,
    • Wartości (Value Objects) — opisują atrybuty bez tożsamości,
    • Repozytoria — pośredniczą w dostępie do danych,
    • Serwisy domenowe — zawierają logikę niezwiązaną z konkretną encją.

DDD promuje czystą architekturę. Kod jest dzielony tak, aby logika domeny była niezależna od infrastruktury. To sprzyja testowalności. Reguły biznesowe można testować jednostkowo, bez zależności od bazy czy UI.


Model żyje i ewoluuje. To również proces odkrywania domeny. Model zmienia się wraz z lepszym zrozumieniem biznesu. Testerzy powinni śledzić te zmiany, bo wpływają one na reguły walidacji, ścieżki testowe i przypadki brzegowe.

DDD w kontekście testera

  • Tester musi znać i rozumieć ubiquitous language.
  • Testy, szczególnie scenariusze funkcjonalne i akceptacyjne, powinny być pisane w tym języku.
  • Tester uczestniczy w tworzeniu przykładów biznesowych (example mapping, specification by example).
  • W DDD, logika aplikacyjna (np. przypadki użycia) jest osobno od logiki domenowej. Tester powinien:
    • Tworzyć testy akceptacyjne dla przypadków użycia (np. „użytkownik może zarejestrować się, jeśli spełnia warunki”).
    • Weryfikować logikę aplikacyjną niezależnie od interfejsu użytkownika.
  • Tutaj testujemy jednostkowo Entity, Value Objects, Aggregates. Przykład testu: „Zamówienie nie może być opłacone dwa razy”.
  • Tester techniczny (lub deweloper-testujący) powinien pisać precyzyjne testy jednostkowe logiki domenowej.
  • Testowanie zachowań, nie struktur.
  • W DDD komunikacja między kontekstami może przebiegać przez:
    • Zdarzenia domenowe.
    • API (np. REST, gRPC).
  • Rolą testera może być:
    • Testowanie zgodności kontraktów (Contract Testing) – np. czy wiadomość JSON spełnia oczekiwany schemat.
    • Testy integracyjne międzykontekstowe, np. czy Bounded Context A prawidłowo reaguje na zdarzenie wysłane przez kontekst B.
  • W DDD nie testujemy „wszystkiego ze wszystkim” – testujemy w kontekście konkretnej odpowiedzialności (bounded context).
  • Tester musi być świadomy granic odpowiedzialności i punktów integracji, by:
    • Unikać testów, które są zbyt szerokie lub nieskuteczne.
    • Zapewniać lepsze pokrycie przez testy funkcjonalne, kontraktowe, integracyjne, zamiast tylko end-to-end.
  • Tester może być pomostem między biznesem a zespołem technicznym.
  • Testy akceptacyjne mogą być pisane z użyciem narzędzi typu Gherkin (Given/When/Then).
  • Hexagonal Architecture (Ports & Adapters) dobrze uzupełnia DDD. Tester może:
    • Testować adaptery zewnętrzne (np. REST API, baza danych).
    • Testować porty aplikacyjne – jako punkt wejścia do logiki aplikacyjnej.
  • Porty są dobrym miejscem do testów funkcjonalnych i integracyjnych.

Checklist dla testera w DDD

Co testować?Gdzie?Narzędzie/test
Reguły biznesoweDomain LayerTesty jednostkowe
Przypadki użyciaApplication LayerTesty akceptacyjne, funkcjonalne
Interakcje z zewnętrzemAdaptersTesty integracyjne
Komunikacja między kontekstamiContext MapContract Tests, Event Testing
Zgodność z biznesemCałośćSpecification by Example, Gherkin


References

  • Vaughn Vernon, DDD dla architektów oprogramowania.