Jak w większości systemów budowanych w oparciu o DDD, tak i w naszym natrafiliśmy w końcu na problem poprawności obiektów modelu domeny. Na samym początku ograniczyłem się do przekazania programistom informacji, że dobry obiekt modelu powinien być
zawsze poprawny.
Pomyślałem, że jest to dobre pierwsze przybliżenie. Szczegółami zajmiemy się później. Szczegóły te miały, według moich przewidywań, dotyczyć walidacji
zależnej od kontekstu, która sprawia, że Jeffrey
Palermo nie wierzy w zasadę "always valid".
Okazało się jednak, że atak nastąpił z zupełnie innej strony. Problem, który się pojawił dotyczył walidacji unikalności pewnego atrybutu obiektu domeny w obrębie przechowywanego zbioru obiektów. Chodziło konkretnie o
login konta użytkownika.
W jaki sposób zaimplementować regułę biznesową: konto użytkownika ma przypisany unikatowy login?
Pierwszym rozwiązaniem, jakie nam się nasunęło na myśl, była
Prewencja w warstwie usług.
Usługa "Utwórz konto" po rozpoczęciu transakcji na bazie danych wykorzystuje dedykowaną metodę z Repozytorium Kont, aby sprawdzić, czy istnieje konto o podanym loginie. Jeśli tak, usługa kończy działanie zwracając false. Jeśli konta nie ma, usługa tworzy nowy obiekt Konta i zapisuje go do bazy danych.
Problem z tym podejściem jest jeden:
nie działa. Prześledźmy następujący scenariusz:
- wątek naszej usługi "Utwórz konto" rozpoczyna transakcję
- inny zły wątek rozpoczyna swoją transakcję
- nasz wątek sprawdza, czy w bazie są konta o loginie "XXX": nie ma, można kontynuować
- zły wątek zapisuje do bazy konto "XXX"
- zły wątek zatwierdza swoją transakcję
- nasz wątek zapisuje do bazy konto o loginie "XXX" i otrzymuje wyjątek naruszenia constraint-a
Wniosek z tego podejścia: problemu nie da się rozwiązać metodą prewencyjną - musimy liczyć się z wyjątkiem. Ale właściwie to chyba nic strasznego: w końcu sytuacja jest przecież wyjątkowa.
Wydaje nam się, że problem załatwimy przez złapanie wyjątku na poziomie usługi i zwrócenie false do warstwy prezentacji? A co jeśli podjęliśmy wcześniej decyzję o wykorzystaniu
zdarzeń domenowych Udiego do komunikacji sytuacji wyjątkwych do GUI? Czy może warstwa usług ma inicjować zdarzenie domenowe? Trochę to nie tak jakbyśmy chcieli:\
A może ktoś ma pomysł, jak regułę unikalności loginu zaimplementować w sposób zgodny z filozofią DDD?