Ostatnio zastanawiałem się praktycznie nad tym samym, cała koncepcja z architekturą heksagonalną brzmi świetnie, tylko ciągle mam wrażenie, że jest łatwa do zastosowania tylko przy projektach, które nie mają zbyt wielu zależności między obiektami. Z mojej strony zaproponowałbym bardziej coś w takim kierunku.
Dla przykładu załóżmy, że pracujemy z dokumentami. Każdy dokument posiada:
- **DocumentHeader **- nagłówek dokumentu, każdy dokument zawiera jeden.
- **DocumentBody **- pozycja dokumentu, każdy dokument zawiera przynajmniej jedną.
- **DocumentSummary **- podsumowanie dokumentu w danej stawce vat - przynajmniej jedno.
Do każdego z tych elementów masz jakiś tam serwis, w którym znajduje się logika do zapisu, walidacja, pobieranie danych. Później jest to udostępniane na światło dzienne przy pomocy fasady. Te fasady powinny zostać przetestowane szybkimi testami jednostkowymi - to tylko drobny element, odnosi się do jednej encji, tutaj nie potrzebujesz robić żadnych testów integracyjnych. (To miejsce tak jak wspomniałeś na skorzystanie z InMemoryDbRepository)
Wszystko fajnie, ale teraz chcemy zrobić korektę dokumentu - trzeba pobrać dane ze wszystkich serwisów, przetworzyć i zmodyfikować na podstawie danych wprowadzonych przez użytkownika. Tworzymy sobie teraz serwis w głównym pakiecie dla dokumentów - DocumentCorrectionService, w nim wołamy wszystkie potrzebne fasady oraz przetwarzamy otrzymane dane. Możemy dalej sobie rozbijać to na klocki, realizujące już jakąś konkretną funkcję, np. przeliczenie pozycji, czy co tam sobie wymyślimy. Kiedy już mamy napisane to co chcieliśmy, to udostępniamy to przez publiczną fasadę. Tego elementu już nie musimy testować jednostkowo, ponieważ wszystkie składowe mamy przetestowane na niższym poziome. Tutaj możemy śmiało napisać sobie do tej fasady test integracyjny, postawić sobie bazę danych w pamięci, dzięki temu sprawdzimy sobie spójność komponentów, sprawdzimy jak się zachowa system dla danej funkcji.
-
Documents - DocumentHeader - DocumentHeaderFacade
-
Documents - DocumentHeader - DocumentHeaderService
-
Documents - DocumentBody - DocumentBodyFacade
-
Documents - DocumentBody - DocumentBodyService
-
Documents - DocumentSummary - DocumentBodyFacade
-
Documents - DocumentSummary - DocumentBodyService
-
Documents - DocumentsFacade
-
Documents - DocumentCorrectionService
Co do jeszcze zależności pomiędzy obiektami, czyli np. relacja jeden do wiele - DocumentHeader z DocumentBody, to bardziej bym poszedł w rozszerzenie klasy bazowej DocumentHeader, która nie posiadałaby żadnych relacji, w kolejnej klasie. O ile musisz mieć taką relację, to wydaje się to jedyne sensowne rozwiązanie, bo nie spowoduje Ci dodatkowego narzutu na encje, kiedy nie będziesz tego potrzebował. (z lazy bywa różnie ;p) Chociaż może się okazać, że nawet do końca nie potrzebujesz tej relacji na obiekcie, bo przeliczyć jakieś pola możesz na etapie tworzenia samego zapytania w jpql i zwrócić sobie bezpośrednio DTO z obliczonymi polami. No chyba, że chcesz się bawić w kaskadowe zapisywanie, usuwanie etc., ale moim zdaniem funkcja nie warta zachodu. Powiązanie jeden do jeden, będzie jeszcze prostsze, bo tutaj wszystko możesz sobie zwrócić bezpośrednio w DTO, ewentualnie możesz zrobić to samo co pisałem wcześniej + ew. dochodzi jeszcze opcja z wykorzystaniem @Formula.