Problem przy projektowaniu obiektów domenowych

0

Cześć, mam pytanie związane z projektowaniem agregatów lub generalnie może po prostu obiektów domenowych ... Męczy mnie pewien problem i nie wiem do końca, które rozwiązanie obrać.
Dla przykładu mamy do zrobienia aplikację, która pozwala kupować jakieś rzeczy za jakąś wirtualną walutę (nieważne jaka to waluta i nieważne co to za rzeczy). Każdy użytkownik loguje się za pomocą maila i hasła, posiada swój profil z jakimś zdjęciem i załóżmy zapisanymi preferencjami co do kupowanych przedmiotów, posiada swoje konto z tą wirtualną walutą oraz całą historię swoich zakupów.

I teraz tak .. jedna zasada mówi, żeby jakoś rozbijać te bounded contexty, aby nie powstał jeden wielki agregat .. czyli według tej zasady możemy mieć coś takiego:

UserAuthData z polami email, password i ewentualnie jakieś role bądź dodatkowe info czy loguje się przez media społecznościowe.
UserProfile, gdzie jego id to mail z UserAuthData oraz takie pola jak jego nazwa, zdjęcie, może jakaś lista znajomych.
Account ze stanem konta, gdzie id to również email.
Purchases z listą zakupów, które dokonał.

To taki przykładowy podział gdzie jakoś tam podzieliliśmy konteksty. Niby fajnie .. ale wg zasad projektowania obiektów domenowych cała logika powiinna być zamknięta w ich obrębie.
No i teraz np jeśli chcemy dokonać zakupu to mamy jakąś logikę w Purchaes, ale musimy uderzyć do jakiegoś AccountFacade o stan konta, aby sprawdzić czy jednak możemy dokonać zakupu. Czyli może jednak nie powinno być agregatu Account tylko stan konta musi być trzymany jako ValueObject w Purchases bo tam jest cała zamknięta logika zakupów.

Ale załóżmy, że dochodzi wymaganie, że zakupów nie może wykonać nikt, kto jeszcze nie uzupełnił swojego profilu o zdjęcie (i jakieś tam inne dane) .. i co, ponownie logika wychodzi z obrębu Purchases do innego kontekstu (tutaj do UserProfile). Czyli nadal nie tak ..

Agregat mówi, że ma zawierać w sobie wszystkie reguły logiczne. Czyli według tego jednak UserProfile, Account i Purchaes muszą być zamknięte w jednym wielkim agregacie .. no ale to chyba nie jest roziwązanie :D

Nie wiem jak te problem ugryźć.

Może to po prostu rozkmina dla samej sztuki ale nie daje mi to spokoju, bo często spotykam się z takimi przypadkami jak piszę jakieś apki. Najszczęściej spotykam się z podejścuuem, gdzie dzieli się to na takie małe agregaty i po prostu uderza restami do innych mikroserwisów pytać się o jakieś warunki .. czyli ta logika jest rozproszona jednak.

1

Generalnie może powinieneś zacząć od tego czym w ogóle jest agregat. Wbrew pozorom nie jest to obiekt grupujący jakieś dane, ale obiekt, który zapewnia spełnienie warunków biznesowych.

O co chodzi. Jeśli aby dokonać zakupu musza być spełnione jakieś warunki w stylu liczba sztuk na stocku, to agregat musi mieć te dane „pod ręka”, aby zwalidować polecenie kupna.

Projektuj agregaty w oparciu o komendy i warunki (tzw. niezmienniki). Agregat zapewni transakcyjna spójność danych. To znaczy, że rozbijając logikę na wiele agregatów dopuszczasz pewna niespójność.

Nie ma to nic wspólnego z mikroserwisami. W obrębie monolitu również możesz modelować domenę wieloma agregatami.

0

@Charles_Ray:

No właśnie to wiem, ale w takim razie jakbyś zaprojektował agregat do kupowanu czegoś, który ma w sobie logikę sprawdzania stanu konta oraz tego czy profil został utworzony ? Trzymałbyś w obiekcie Puchases stan konta oraz flagę profileCreated ?

1

Trzymałbym w agregacie kopie potrzebnych danych. Podkreślam - kopię. Dane konta nie zmieniają się często, można bez problemu oba agregaty skomunikować eventowo. Jeśli nie można sobie pozwolić na eventual consistency, to musisz niestety skleić te agregaty.

0

Ok o to mi chodzi ... czyli jeśli ktoś uzupełni swój profil to idzie event profile.updated i reaguję na to zapisująs pole profileCreated w agregacie z zakupami. Zgadza się ?

1

Generalnie tak. Agregaty aby zapewnić spójność reguł mogą operować na lokalnych danych. ProfileUpdated to antypattern, bo nie wiadomo co się zmieniło i taki event puchnie w nieskończoność. Fajny przykład eventu to np. UserPasswordChanged, UserAccountExpired. Teoretycznie agregat może dispatchować event domenowy po każdym wykonaniu commanda, ale tutaj już skręcamy ostro w stronę event-driven architecture, a to spora komplikacja jednak.

Co do samego zakupu jednak to sytuacja jest złożona. Może z punktu widzenia konta możesz mieć nieaktualne dane, ale z punktu widzenia stocka - już nie za bardzo. W tym wypadku musisz mieć zawsze aktualne dane, a sięgnąć w ramach jednej transakcji do innego agregatu nie powinieneś. To się ogrywa albo kontekstem rezerwacji (jest o tym talk S.Sobótki), albo po prostu masz jeden jebitny agregat, albo świadomie łamiesz zasadę DDD i odpytujesz stock (tak się robi w praktyce, prowadzi to oczywiście do ograniczenia performancu, bo transakcja robi się duża).

Reguła DDD mówi - jeden agregat na transakcje. Od tego zaczynasz, potem świadomie łamiesz. Jeśli bardzo interesuje Cię ten temat, poczytaj o odkrywaniu kontekstów i agregatów za pomocą event stormingu. Jeśli nie, pytaj tutaj ;)

0

Czyli takie bazowe zasady, żeby trzymać w agregacie dane potrzebne do zachowania reguł biznesowych, aby nie sięgać do innych kontekstów. I dane te mogą być kopiami danych z innych agregatów uaktualniane eventami. Tak jest ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1