Zacznijmy od krótkiego przeglądu przestrzeni problemowej: jednym z podstawowych zasad DDD jest umieszczenie reguł biznesowych jak najbliżej miejsc, w których należy je egzekwować. Jest to niezwykle ważna koncepcja, ponieważ sprawia, że twój system jest bardziej „spójny”. Przesunięcie reguł „w górę” jest zazwyczaj oznaką modelu anemicznego; gdzie obiekty są tylko workami danych, a reguły są wprowadzane z tymi danymi, które mają być egzekwowane.
Anemiczny model może mieć wiele sensu dla programistów rozpoczynających pracę z DDD. Tworzysz User
model i EmailMustBeUnqiueRule
dostaje się do niego niezbędne informacje, aby sprawdzić poprawność wiadomości e-mail. Prosty. Elegancki. Problem polega na tym, że ten „sposób myślenia” ma zasadniczo charakter proceduralny. Nie DDD. Ostatecznie dzieje się tak, że masz moduł z dziesiątkami Rules
starannie zapakowanych i zamkniętych, ale są one całkowicie pozbawione kontekstu do tego stopnia, że nie można ich już zmienić, ponieważ nie jest jasne, kiedy / gdzie są egzekwowane. Czy to ma sens? To może być oczywiste, że EmailMustBeUnqiueRule
zostaną zastosowane na utworzenie grupy roboczej User
, ale co UserIsInGoodStandingRule
?. Powoli, ale pewnie ziarnistość ekstrakcjiRules
z ich kontekstu pozostawia cię system, który jest trudny do zrozumienia (i dlatego nie można go zmienić). Reguły powinny być enkapsulowane tylko wtedy, gdy faktyczne chrupanie / wykonywanie jest tak szczegółowe, że Twój model zaczyna tracić koncentrację.
Teraz do konkretnego pytania: Problem z posiadające Service
/ CommandHandler
rzucić Exception
to, że logika biznesowa zaczyna przeciekać ( „w górę”) z danej domeny. Dlaczego Twój Service
/ CommandHandler
musisz znać adres e-mail musi być unikalny? Warstwa usługi aplikacji jest zwykle używana raczej do koordynacji niż do implementacji. Przyczynę tego można zilustrować po prostu, jeśli dodamy ChangeEmail
metodę / polecenie do twojego systemu. ZARÓWNO metody / moduły obsługi poleceń będą musiały zawierać unikatowy test. To tutaj deweloper może ulec pokusie „wyodrębnienia” an EmailMustBeUniqueRule
. Jak wyjaśniono powyżej, nie chcemy iść tą drogą.
Pewne dodatkowe trudności w zdobywaniu wiedzy mogą prowadzić do odpowiedzi na więcej DDD. Wyjątkowość wiadomości e-mail jest niezmiennikiem, który należy wymusić w całej kolekcji User
obiektów. Czy w Twojej domenie istnieje koncepcja reprezentująca „kolekcję User
obiektów”? Myślę, że prawdopodobnie widzisz, dokąd idę.
W tym konkretnym przypadku (i wielu innych, obejmujących egzekwowanie niezmienników w różnych kolekcjach), najlepsze miejsce na wdrożenie tej logiki będzie w twoim Repository
. Jest to szczególnie wygodne, ponieważ Repository
„wiesz” dodatkową infrastrukturę niezbędną do przeprowadzenia tego rodzaju weryfikacji (magazyn danych). W twoim przypadku umieszczę to sprawdzenie w add
metodzie. To ma sens, prawda? Koncepcyjnie jest to ta metoda, która naprawdę dodaje User
do twojego systemu. Magazyn danych jest szczegółem implementacji.