Komunikacja między dwoma ograniczonymi kontekstami w DDD

Mam kilka różnych ograniczonych kontekstów w domenie. Walidacja operacji CRUD jest budowana w każdym ograniczonym kontekście.

Na przykład, mogę utworzyć encję o nazwie Gra tylko wtedy, gdy osoba tworząca ją jest liderem grupy .

W tym przykładzie mam dwa ograniczone konteksty (BC). Jednym z nich jest Gra BC, a drugim jest Użytkownik BC . Aby rozwiązać problem, w grze BC, muszę wykonać usługę domeny jak IsGroupLeader () do użytkownika BC Przed przystąpieniem do tworzenia gry.

Nie sądzę, aby tego typu komunikacja była zalecana przez DDD. Mogę mieć User entityrównież w grze BC, ale nie chcę, ponieważ ta sama User entity jest używana inaczej w innym kontekście w innym BC.

Moje pytania to:

  1. Czy powinienem używać zdarzeń domenowych gdzie Gra BC ma wysłać Zdarzenie do Użytkownik BCpytanie o status użytkownika? Przy takim podejściu nie wykonuję synchronicznego wywołania jak IsGroupLeader , ale zdarzenie o nazwie is_group_leader. Następnie gra BC musi poczekać, aż użytkownik BC przetworzy Zdarzenie i zwróci status. Gra BC utworzy podmiot gry dopiero po przetworzeniu zdarzenia przez użytkownika BC.

  2. Czy CQRS jest rozwiązaniem mojego problemu?

Każdy pomysł doceniony.

Author: wonderful world, 2013-05-23

6 answers

Podczas integracji BCs, masz kilka opcji. Powodem, dla którego odradzane jest wołanie do zewnętrznego BC, jest to, że wymaga to, aby oba BCs działały w tym samym czasie. Jednak często jest to całkiem dopuszczalne i jest prostsze niż alternatywa. Alternatywą jest, aby gra BC subskrybowała wydarzenia od użytkownika BC i przechowywała lokalne kopie danych, których potrzebuje, co w tym przypadku jest informacją o tym, czy użytkownik jest liderem grupy. W ten sposób, gdy gra BC musi określ, czy użytkownik jest liderem grupy, nie musi wołać do użytkownika BC, tylko odczytuje lokalnie zapisane dane. Wyzwaniem tej alternatywy opartej na zdarzeniach jest synchronizacja zdarzeń. Masz upewnij się, że gra BC otrzymuje wszystkie odpowiednie wydarzenia od użytkownika BC. Innym wyzwaniem jest radzenie sobie z ewentualną konsystencją, ponieważ BCs może być nieco zsynchronizowany w dowolnym momencie w czasie.

CQRS jest nieco ortogonalny do tego problemu.

 34
Author: eulerfx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-23 14:59:37

Oto, jak bym to rozumował.

Argumentowałbym, że gra BC nie wie o "użytkownikach", może jednak wie o"graczach".

Jeśli gra BC jest zależna od aktywnego / bieżącego gracza, to powinna zostać przekazana do BC podczas tworzenia instancji gry BC.

Np.

 Player currentPlayer = GetPlayerSomehow...();
 GameBC gameBC = new GameBC(currentPlayer);
 gameBC.DoStuff();

Teraz Twoje dwa BC są nadal oddzielne, można je przetestować oddzielnie itp.

I aby to wszystko działało, po prostu zrób coś w stylu:

 User currentUser = GetCurrentUser();
 Player currentPlayer = new Player();
 currentPlayer.IsGroupLeader = currentUser.IsGroupLeader;
 GameBC gameBC = new GameBC(currentPlayer);
 gameBC.DoStuff();

To służy jako warstwa antykorupcyjna pomiędzy UserBC a GameBC, możesz przenieść i zweryfikować żądany stan z UserBC do stanu potrzebnego dla Twojego GameBC.

A jeśli twój GameBC potrzebuje dostępu do wielu użytkowników, nadal możesz przekazać jakiś rodzaj usługi mapowania do gry BC, która wykonuje tego rodzaju transformację wewnętrznie.

 18
Author: Roger Johansson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-24 07:47:54

Myślę, że już prawie jesteś. Blisko dobrego rozwiązania. Nie jestem pewien, czy musisz dzielić te dwa na dwa BC. Twój agregator użytkowników (?) i gra może należeć do jednego BC i zależeć od siebie nawzajem. Użytkownik " ma "członkostwo" do jednej lub wielu" gier (tylko zgadywanie relacji z podmiotem). Ale teraz tylko burzę mózgów. Spróbuj podążać :) różne podejścia:

Pierwszy GameBC posiada metodę Create (), która w rzeczywistości przyjmuje nazwę Użytkownika jako param. Create (UserMembership). Następnie poprzez jednostkę UserMembership wiesz, jakiego rodzaju członkostwo i użytkownik to. Jeśli zostanie zaakceptowana, gra zostanie utworzona. Jeśli nie zostanie wyrzucony wyjątek lub gra otrzyma komunikat o złamanej zasadzie, zależy od tego, jakie podejście chcesz komunikować się z klientem. Koordynacja może odbywać się w warstwie aplikacji bez wycieku wiedzy z dziedziny.

Drugi Zrobisz to jako jedna z innych odpowiedzi. Podnosisz CreateGameEvent w grze.Metoda Create (UserId). To wydarzenie jest przechwycony przez EventHandler (zarejestrowany przez IoC podczas uruchamiania aplikacji), który znajduje się w warstwie aplikacji i wyszukuje członkostwo Użytkownika za pośrednictwem repozytorium. Mały wyciek wiedzy domeny jest to, że zasada biznesowa, która wie, kto może yo zrobić to, co są weryfikowane w warstwie aplikacji. Można to rozwiązać, pozwalając CreateGameEventHandler pobierać UserId i RuleRef (może to być łańcuch "CAN_CREATE_GAME" lub enum) i pozwalając obiektowi UserPermission zweryfikować uprawnienia. Jeśli nie. Wyjątek jest wyrzucany i uchwycony w warstwie aplikacji. Wadą może być to, że nie chcesz, aby ciągi odniesienia uprawnień były zakodowane na twardo w metodzie Create.

Trzeci ...kontynuuje tam, gdzie kończy się drugie podejście. Wiesz, że GameBC może nie być właściwym miejscem do wyszukiwania uprawnień użytkownika, jeśli postępujesz zgodnie z zasadą SRP. Ale akcja jest wyzwalana wokół tej metody w jakiś sposób. Alternatywą bądź twórz (użytkownik GroupLeader). Albo możesz zagrać.Utwórz (User user) następnie wykonaj walidację, że użytkownik jest typu GroupLeader. Create (GroupLeader) mówi, co trzeba wywołać tę metodę.

Ostatni Może alternatywa, którą bardziej lubię teraz pisząc to. Gdy chcesz utworzyć encję, zazwyczaj pozwalam tej metodzie Create (Save) być w repozytorium. Interfejs IGameRepository znajduje się obok encji gry w projekcie domain assembly. Ale możesz również utworzyć GameFactory, które są odpowiedzialne za rozpoczęcie cyklu życia jednostki gry. Tutaj jest również dobre miejsce do umieszczenia metody tworzenia... GameFactory.Create (GroupLeader) { return new Game.OwnerUserId = GroupLeader.Id; } Więc po prostu zachowaj to i tak.Save (Game)

Następnie masz intuicyjny i samoopisujący sposób mówienia innym programistom, że "musisz mieć instancję GroupLeader, aby stworzyć grę".

W końcu mam nadzieję, że zdasz sobie sprawę, że znasz domenę i dowiesz się, co najbardziej Ci odpowiada. Bądź pragmatyczny i nie idź do Erica Evana hardcore ' a. Jest tak wielu deweloperów, którzy utknęli w "religia" w tym, jak rzeczy mają być zrobione. Wielkość projektu, pieniądze, czas i zależności od innych systemów itp. wpływa również na to, jak dobrze możesz być surowy w robieniu DDD.

Powodzenia.

 3
Author: Magnus Backeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-24 13:12:41

Aby poradzić sobie z problemami, z którymi się borykasz, używamy ograniczonych ról wzorca modelowania, który pojawił się na przestrzeni lat i okazał się działać bardzo dobrze. Ograniczone konteksty są definiowane po jednostkach semantycznych, które często w organizacjach korporacyjnych mogą być mapowane do określonych ról.

To powinno być oczywiste, biorąc pod uwagę, że różne role borykają się z różnymi problemami i dlatego mówią nieco (lub całkowicie) różnymi językami.

Dlatego zawsze modelujemy role, które oddziałują z naszą aplikacją jako punktem styku wymagań aplikacyjnych (Infrastruktura, trwałość, interfejs użytkownika, lokalizacja itp...) i reguł biznesowych (domeny) i kodujemy je w różnych modułach (aka assemblies lub packages).

Jeśli chodzi o twoje drugie pytanie, CQRS może być sposobem na kodowanie rodzaju interakcji między BCs, które opisujesz, ale nie podoba mi się to w tym konkretnym kontekście.

 2
Author: Giacomo Tesio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-23 16:12:34

Proponuję przekazać rolę użytkownika i informacji o użytkowniku Game bounded context service, a także mieć GroupLeader value object w grze BC. w ten sposób zawsze możesz wiedzieć, kto jest group_leader.

 0
Author: Asad Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-06 09:54:07

Myślę, że będę musiał zastosować inne podejście, gdzie zrobię User entity Część Gry BC (ta sama jednostka jest częścią User BC również). Użyję repozytorium do odczytania flagi IsGroupLeader z db w grze BC. W ten sposób usuwa się zależność od użytkownika BC i nie jest wymagana komunikacja z użytkownikiem BC.

Co o tym myślisz?

 -1
Author: wonderful world,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-24 00:53:19