W poprzednim wpisie skupiłem się na architekturze warstwowej, która wydaje się najprostszą możliwą opcją tworzenia oprogramowania. Dzisiaj chciałbym przedstawić bardzo popularną ówcześnie technikę Domain-Driven Design. Nie jest ona co prawda architekturą, ale z racji dużej ilości wytycznych w niej zawartych zdecydowałem postawić ją na równi z innymi dostępnymi opcjami.

Głównym filarem DDD jest myślenie biznesowe. W tym podejściu struktura aplikacji powinna opierać się na wiedzy eksperta domenowego oraz używanym przez niego słownictwie. Ważne jest, aby w systemie zostały wydzielone tzw. Bounded Context’y, czyli obszary funkcjonalne podzielone według kategorii biznesowych. Co to oznacza? Przykładem może być sytuacja, gdy w naszej aplikacji istnieje moduł sprzedaży oraz moduł logistyki. Są to dwie oddzielne działy, które mogłyby istnieć jako osobne aplikacje. Mają jasno postawioną granicę wyznaczającą właśnie Bounded Context’y. Oczywiście moduły komunikują się ze sobą, aby uzyskać niezbędne dane do wykonania swoich operacji. Jednak posługują się przy tym innymi pojęciami. Co innego dla modułu sprzedaży może oznaczać produkt, a co innego dla modułu logistycznego. I tutaj wkracza do akcji Ubiqutuos Language.

Koncepty stojące za DDD

Jeżeli potocznie mówimy o produkcie to nie robi dla nas różnicy czy jest to towar w sklepie czy rzecz w kontenerze na statku. Jednak dla specjalistycznych branż są to w ogóle dwa różne byty. W przypadku produktu do kupienia na stronie internetowej istotna jest jego cena, ilość sztuk, kolor czy opcje dodatkowe. Dla logistyki natomiast ważne są jego wymiary, masa, wrażliwość na uderzenia itp. W każdym z tych obszarów posługujemy się innym, dedykowanym językiem, czyli właśnie Ubiqutous Language.

Schemat architektury DDD

Nasuwa się następujące pytanie, jak tworzyć aplikację w stylu DDD? Do tego służą małe klocki, które zaraz pokrótce przedstawię. Nie są to wszystkie możliwe koncepty, ale według mnie najbardziej niezbędne.

  • Entity – klasa zawierająca odpowiedzialność biznesową.
  • Value Object – klasa przedstawiająca proste koncepty, które są szeroko wykorzystywane jako niezmienniki np. pieniądze, wymiar, numer dokumentu.
  • Aggregate – zenkapsulowany zbiór obiektów (Encji i Value Objects) z jedną encją będącą API - “korzeniem” - całości.
  • Repository – zarządza pracą danymi Agregatu czy Encji.
  • Service – gromadzi operacje, które nie pasują do żadnego kontekstu i wykonywane są na wielu agregatach.
  • Policy – algorytm operacji biznesowej, który implementowany jest jako wzorzec Strategii.
  • Event – wydarzenie biznesowe, które może służyć do równoległych operacji lub przekazywania informacji pomiędzy Bounded Context’ami.

Ważne jest, żeby dwa niezależne od siebie konteksty komunikowały się ze sobą tylko za pośrednictwem identyfikatorów obiektów. Jeżeli towar znajdujący się na półce ma id 231 to przez niego trzeba odwoływać się do modułu logistycznego. To jest fizycznie ta sama rzecz, np. laptop, który po prostu ma inne znaczenie w tych dwóch kontekstach. Opisuje ją cena czy masa, ale jej stan się nie zmienia. Z tego powodu warto używać wobec tej rzeczy ten sam identyfikator.

Za i przeciw

Technika Domain-Driven Design zmienia sposób postrzegania systemu. Nie jest już on jednym, wielkim monolitem, gdzie wszystkie funkcjonalności są ze sobą powiązane. Każdy kontekst jest wyodrębniony i logicznie uporządkowany. Dzięki takiemu podziałowi bez problemu można tworzyć większą całość jaką jest działająca aplikacja. Na pewno ma to wpływ na łatwiejszą implementację dodatkowych funkcjonalności oraz praca pomiędzy zespołami staje się prostsza. Każdy Bounded Context ma swojego właściciela, który dba o jego rozwój.

Na pewno trzeba zwrócić uwagę na wysoki próg wejścia. Zespół o niskich kompetencjach będzie miał naprawdę sporo trudności w zachowaniu porządku. DDD stawia na programowanie obiektowe, ale nie w teorii jak to ma miejsce na rozmowach kwalifikacyjnych, tylko w praktyce. Na pewno tworząc elastyczne konteksty należy też włożyć spory wysiłek w synchronizację danych pomiędzy nimi. Cały czas trzeba mieć na uwadze, aby przypadkiem nie zacząć mieszać ze sobą odpowiedzialności poszczególnych modułów.

Podsumowanie

Dzisiejszy artykuł jest tylko ogólnym liźnięciem tematu DDD. Mi osobiście nauka tej techniki sprawia ogromną satysfakcję, więc pewnie będę chciał jeszcze rozwinąć tą koncepcję na blogu. Na prawdę kusząca jest wizja tworzenia obiektów, które nie służą tylko i wyłącznie jako struktury danych. Dodaje smaczku też fakt, że wiedza biznesowa jest odzwierciedlona jeden do jednego w kodzie. Nie trzeba marnować sporej ilości czasu, aby odkryć na nowo o co chodziło dokładnie w danej funkcjonalności.

Mam nadzieję, że układanie w głowie zdobytej już wiedzy sprawia Tobie taką samą frajdę jak i mi. W następnym wpisie krótko przedstawię architekturę Ports & Adapters. Nie mogę się już doczekać!

A tym czasem, na razie i cześć!