Kontynuujemy poznawanie rozwiązań architektonicznych w oprogramowaniu. Wcześniej omówiliśmy meandry struktury heksagonalnej, dziś przyszedł czas na coś jeszcze bardziej zawiłego: Domain Driven Design.
Uwaga! W tej serii zajmuję się opisowym przedstawieniem tematu, a celem jest zapoznanie z zagadnieniem w sposób luźny i zrozumiały dla nowicjusza. W związku z tym wiele elementów siłą rzeczy musi zostać pominiętych. Tych z was, którzy chcieliby się dowiedzieć więcej, zapraszam do źródeł na końcu artykułu.
Poprzedni wpis zakończył się wypaleniem zawodowym człowieka, którego sieżkę kariery obserwowaliśmy. W sytuacji kiedy obecne zajęcie nie daje mu już spełnienia i poczucia satysfakcji, nasz bohater decyduje się przejść na swoje.
Jeśli nie możesz zmienić swojej pracy to zmień pracę.
Otwiera mały software house, zbiera dream team i zaczyna szukać klientów. Teraz to on jest szefem, zmieniły się jego obowiązki. Zamiast siedzieć i klepać w klawiaturę chodzi na spotkania, business-lunche, konferencje. Poznaje ludzi i „networkinguje” budując markę osobistą oraz swojej firmy, tak aby klienci mający problem który on może rozwiązać, z miejsca wiedzieli gdzie dzwonić.
Poznaje tzw. język biznesu i umiejętnie łączy go ze swoim doświadczeniem w technologii. Potrafi znaleźć poważny problem tam gdzie jego klient uważa, że wszystko działa wyśmienicie. I na odwrót – w sytuacji kompletnego chaosu szybki audyt i mała korekta pozwalają firmie wrócić do gry. Z małpki produkującej kod ewoluuje w tzw. inżyniera rozwiązań, którego mottem jest:
„Kod, który nie powstał jest najłatwiejszy w utrzymaniu.”

Zaczynając omawianie zagadnienia Domain-Driven Design, czyli po naszemu „Projektowanie zorientowane domenowo” najlepiej jest podejść do tego od tzw. du*y strony i zastanowić się wpierw czym jest:
Design-Driven Domain
Domena to inaczej temat naszego biznesu: jego całość albo integralna część. W poprzedniej części pokazałem przykład pakietowania projektu prostej listy zadań do zrobienia – tam domeną było zadanie i to co użytkownik może z nim zrobić: stworzyć, zmienić, usunąć, ukończyć. Usera nie interesuje jak to wygląda w IntelliJ’u, że są tam jakieś kontrolery, filtry, „łapacze wyjątków” itd. Te elementy są ważne dla deva, ale nie są częścią domeny.
Mamy domenę czyli to co chcemy osiągnąć oraz całą resztę
– to co nam (jako programistom) w tym pomaga.
Ta cała reszta to szablon w który chcemy włożyć naszą domenę – a jeśli ta nie pasuje, to ją modelujemy tak, aby zaczęła pasować. Domena jest dostosowywana do projektu – czyli ang. „Design-Driven Domain„.

Nie jest do najlepsze podejście dla biznesu. Z co najmniej dwóch powodów.
Po pierwsze biznes to klient, a ten chce działać na zasadzie „płacę i wymagam” przez co nie w smak mu są wyrażenia takie jak: „nie można tego zrobić”, „nie da się”, „architektura na to nie pozwala”.
Po drugie klient stosunkowo rzadko zna się na technologii, a mimo to chce w sposób techniczny przekazać na czym mu zależy: „to napiszcie w tym języku”, „tutaj koniecznie użyjcie tego frameworka”, „skorzystajcie z takiej, a takiej bazy danych”. Programista typu „coding ape” zrobi wszystko dokładnie tak jak zażyczył tego sobie klient. A to czy to razem fajnie zabangla to już nie jest jego brocha. Natomiast inżynier rozwiązań będzie dociekał powodów i sugerował inne rozwiązania, lepiej pasujące do domeny biznesowej. I to jest właśnie clou (fr. „sedno”) tego mitycznego
Domain-Driven Design
Mówiąc o DDD musimy to rozgraniczyć na dwa podejścia: strategiczne i taktyczne. O tym pierwszym napisałem powyżej: spojrzenie na problem z oddali i opracowanie strategii zmierzenia się z nim w jak najbardziej efektywny sposób.
DDD taktyczne oznacza z kolei projekcję tej idei w kodzie programu. W poprzednim wpisie pokazałem jak wygląda pakietowanie w architekturze heksagonalnej w porównaniu do trójwarstwowej. Teraz pewnie oczekujecie, że zrobię to samo z kodem napisanym zgodnie z zasadami DDD.

Powyższy obrazek nie jest tym którego pragniecie, ale tym jakiego potrzebujecie.
Można powiedzieć, że DDD i czysta architektura (opierająca się właśnie na modelu heksagonalnym i CQRS) idą ze sobą w parze. Jeśli pokazałbym wam obie wersje: z i bez DDD to różnice w strukturze byłyby raczej kosmetyczne.
Bo nie chodzi o to jak to jest ułożone, ale co jest wewnątrz.
Śmiało mogę powiedzieć, że sercem taktycznego DDD jest coś takiego jak
Agregat
Najkrócej rzecz ujmując: agregat to encja* bez getterów i setterów, ale za to z konkretnymi metodami logiki biznesowej.
(*) O encjach jeszcze nic nie było, więc macie prawo czuć się zagubieni. Encja to obiekt, który jest jednocześnie tabelą w bazie danych – jego argumenty są mapowane na konkretne kolumny. Będziemy o tym mówić za kilka odcinków, kiedy pojawi się temat Hibernate/ORM.
W wyżej pokazanym obrazku, zwykła struktura (po lewej) opiera się na encjach i ich wzajemnych relacjach. Wszystko jest ze sobą połączone.
Po prawej zaś widzimy jak to jest z użyciem DDD: tam jedna encja (choć może być więcej) tworzy agregat i łączy się tylko z tym co jest w tym agregacie. Dzięki tej sztuczce poszczególne agregaty stanowią osobne moduły i mogą szybko być przeniesione do niezależnych mikroserwisów.

Odgórną zasadą agregatu (choć często dla wygody łamaną) jest to, że z niczym nie może się integrować bezpośrednio – ani ze Springiem, ani z ORM*. Jest tam sama Java (lub inny język, bo to dość uniwersalny model) i dopiero dookoła tego agregatu zaczyna się tworzyć niezbędną infrastrukturę.
Taki styl stoi w wyraźnej opozycji do podejścia klasycznego nazywanego żartobliwie „encja na twarz i pchasz”, gdzie po prostu załączamy nad klasą adnotację @Entity i reszta już nas nie interesuje.
Agregat jest początkiem opowieści – jej motywem i sensem istnienia.
Ziarnem z którego wyrasta oprogramowanie.
Można sobie to fajnie zwizualizować na przykładzie ulubionego serialu – zastanówcie się nad pytaniem: „Wycięcie jakiego elementu zabrałoby duszę przedstawieniu?”.
Czasami odpowiedź jest banalnie prosta:
- Herkules -> bez gościa, który urokiem osobistym i przemocą rozwiązuje wszystkie problemy, opowieść byłaby bez sensu
- Przyjaciele -> tutaj nie mamy jednej konkretnej postaci, nawet główny romans stanowi jedynie dodatek, agregatem mógłby zatem być wiek bohaterów – wszyscy mają około 30 lat, historia toczy się wokół problemów z tym związanych: związki, praca, dzieci
- Scrubs -> szpital jest miejscem, które spaja perypetie bohaterów w jedną opowieść

Nie zawsze jest to takie oczywiste, np. w „Grze o tron” moglibyśmy się zastanawiać czy historia toczy się wokół samego tronu, albo smoków, a może któregoś z nielicznych bohaterów którzy dotrwali do końca serialu.
Praca nad projektem z użyciem DDD zawsze rozpoczyna się od wspólnego poszukiwania agregatów. Takie spotkanie nosi nazwę „event storming” i polega na wyszukiwaniu czasowników – czynności, które mogą się zadziać w aplikacji. Potem wynajdywane są wspólne podmioty i na tej bazie wyłuskiwane są agregaty. Efekty takiego event stormingu nie zawsze są oczywiste od samego początku – polecam obejrzenie załączonego przykładu z bajką o 3 świnkach.
Na koniec
Ok, myślę, że temat architektury oprogramowania został właściwie nakreślony i możemy przejść dalej. Zanim to jednak zrobimy, chciałbym podsumować ten i poprzedni wpis kilkoma zdaniami.
Mam wrażenie, że po lekturze obu artykułów zostajecie z myślą w stylu: MVC – złe, Hex – dobre, DDD – świetne. Sęk w tym, że to nie do końca prawda. Po pierwsze musimy pamiętać, że architektura to narzędzie, zupełnie jak młotek, który możemy użyć do wbicia gwoździa, ale i żeby przypadkowo sobie przypieprzyć w palec.

Nie patrzcie na temat w stylu: dobra/zła architektura, a zamiast tego zastanówcie się czy jest adekwatna do sytuacji. Pamiętajcie, że nadrzędną zasadą w programowaniu wciąż pozostaje
K I S S
Keep It Simple Stupid
Nie próbujmy „przeinżynierować”, bo nie tylko utrudnimy życie sobie, ale także i innym programistom próbującym ogarnąć nasze dzieło. Jeśli miałbym wam dać prostą wskazówkę: „co do czego” to zapamiętajcie:
- DDD do wieloletnich projektów ze skomplikowaną logiką
- Porty/adaptery tam gdzie bardzo zależy nam na testach
- MVC do aplikacji typu CRUD gdzie logika jest szczątkowa
Uff. Powiem szczerze, że temat architektury (a DDD w szczególności!) okrutnie mnie sponiewierał i zajął znacznie więcej czasu niż zakładałem. Nie jest to łatwa ścieżka, ale pełna wyzwań i satysfakcji – szczególnie w sytuacji, kiedy zwykłe klepanie kodu stanie się nużące i będziecie potrzebować zmiany.
Zostanie architektem (tudzież inżynierem rozwiązań)
jest ostatnim szczeblem kariery każdego programisty.
Na dzisiaj tyle i tradycyjnie dziękuję za uwagę. Widzimy się już niedługo we wpisie pod tytułem: „Czym są mikroserwisy?”.
Źródła:
Model anemiczny i bogaty (DDD) – blog/POL
Trzy świnki – bajka o DDD – YT/POL
DDD – Porozmawiajmy o IT – podcast/POL
Inżynier rozwiązań – Porozmawiajmy o IT – podcast/POL
Modelowanie agregatu – Better Software Design – podcast/POL
Domain Drivers – kurs DDD dla profesjonalistów POL