2014-04-23 14 views
8

Istnieje wiele opinii na temat CQRS z DDD i tego, co składa się na każdy komponent. Nie zacząłem jeszcze szukać informacji na temat pozyskiwania zdarzeń, więc poniższa lista nie zawiera niczego związanego z tym. Chociaż wgląd w ES byłby interesujący.Role i zadania komponentu CQRS z interfejsem API REST

Do tej pory posiadam następujące komponenty o powiązanych obowiązkach (patrz poniżej). W poniższych punktach przedstawiłem kilka pytań.

REST Punkty końcowe/Application

  • Otrzymuj żądanie od użytkownika/UI/etc
  • budowy i wysyła odpowiednie polecenia
  • Jeśli polecenie wymaga wartości od innych ograniczonych kontekstach, a następnie wykonać odpowiednie Finder wywołania wymagane do prawidłowego utworzenia polecenia (np. zamówienie wymaga identyfikatora użytkownika)
  • W przypadku GET: odpowiedni Finder nazywa się
  • Finders siedzą na tym poziomie aplikacji. Strona zapisów Bounded Contexts (program obsługi komend, agregacja, fabryka, usługa domeny itp.) Nie powinna wywoływać Finderów. Utrzyma to hermetyzację i przekazanie do komend tylko wymaganych danych (zamiast pełnych DTO) staje się skromną warstwą antykorupcyjną.
  • Na przykład:

AggregateId idZamówienia = AggregateId.get(); AggregateId userId = finder.findUserAggregateIdByEmail (e-mail); dispatcher.fire (nowy CreateOrderCommand (orderId, userId, orderItems));

poleceń

  • Zmiany w domenie są dokonywane za pomocą poleceń dyspozytorskich
  • Polecenia są niezmienne i zawierać dane niezbędne dla ograniczony kontekst zmienia to stan lub wyjątek
  • Komenda dane wejściowe można zweryfikować podczas tworzenia obiektu, aby uniknąć wysyłania nieprawidłowych poleceń.
  • Na przykład: new CreateOrderCommand(orderId, userId, orderItems);

poleceń Handler

  • może też z powodzeniem stosować komendy lub wyjątek Handler
  • Nie może być tylko jeden obsługi poleceń dla każdego polecenia
  • Handler załaduje lub utwórz kruszywa Katalog główny (repozytorium lub fabryka agregatów)
  • Program obsługi zastosuje to polecenie do agregatu root
  • Transakcja handlowa s z repozytorium
  • Nie powinien uruchamiać komend (w kontekście z ograniczeniami)
  • Czy polecenie obsługi powinno wysyłać zdarzenia? Na przykład po pomyślnym zapisaniu do bazy danych? A może to wyłącznie odpowiedzialność Aggregate'a?

Kruszywo Fabryka

  • oddaje logikę wymaganą do zainicjowania się Agregat Korzeń poprawnie
  • Fabryka może uzyskać dostęp do repozytorium
  • powinny dostępie fabryka Domain Services?
  • Na przykład: factory.createOrder(orderId, userId, orderItems);

Kruszywo root/Kruszywa

  • zawiera logikę domeny, stan i zachowanie
  • odpowiedzialny za dysponowanie Wydarzenia
  • Kruszywo głównej hermetyzuje dostęp do kruszywa
  • Korzeń agregatu powinien mieć identyfikator, który unikalnie dentifies to
  • nie powinien wchodzić w interakcje z usług zewnętrznych (innych niż wydawcy zdarzenia)
  • na przykład: order.cancel();

Domain Służby

  • zawiera co nie bardzo pasuje w Korzeń agregatu
  • Z jakich składników może współpracować usługa domeny?
  • Czy usługi/zdarzenia związane z usługą domeny powinny być uruchamiane?
  • Na przykład: Nie wiesz, czego użyć, pierwszy punkt powyżej jest w najlepszym razie niejasny. Większość zachowań jest ładnie w Aggregate lub można je osiągnąć poprzez Sagi/Zdarzenia/Polecenia. Jaki byłby tutaj ważny przykład?

Repository

  • dba o załadunku/zapisywania/aktualizacji/etc Nasze kruszywa
  • Na przykład: repo.load(orderId);

imprez

  • Przedstawia coś, co miało miejsce w agregacie (lub obsługi poleceń, etc, jeśli mogą one także ogień zdarzenia)
  • wydarzenia są niezmienne
  • Inne ograniczony konteksty w systemie można użyć zdarzenia do podejmowania decyzji
  • Na przykład : new OrderCancelledEvent(orderId);

Event Handler

  • reaguje na zdarzenia tha t odbyła
  • Może istnieć wiele obsługi zdarzeń dla pojedynczego zdarzenia w tej samej lub różnych kontekstach ograniczonych
  • może współdziałać z usług infrastrukturalnych: OrderCancelled => OrderCancelledHandler => EmailService.sendEmail()
  • może wystrzelić nowe polecenia
  • Może porozmawiać z Finders
  • Gdy obsługa zdarzeń uruchamia polecenia, rozmawia z Finderami i współdziała z infrastrukturą, ma ona charakter podobny do Sagi (lub zachowania REST Enpoint). Poza tym jest to reakcja na pojedyncze wydarzenie, a nie łańcuch/zestaw zdarzeń.

Saga

  • Utrzymuje procesu biznesowego, który siedzi po drugiej stronie tej samej lub wielokrotność ograniczony kontekstach (współrzędne)
  • odbiera zdarzenia
  • Utrzymuje stan łańcucha/zestaw zdarzenia
  • Normalnie stan jest zachowywany
  • Limit czasu można ustawić, aby sprawdzić/zmienić stan (może mieć pojęcie czasu)
  • Stany mogą wywoływać efekty uboczne, takie jak: wypalanie poleceń, rozmowa z Finderami, interakcja z usługami infrastruktury (np.e-mail)
  • Na przykład: czekać na OrderShipped i OrderReceived wydarzenia => ogień CancelOrderCommand Poczekaj na OrderCancelled => rozkaz ogień odwołany email

Finder

  • do odtworzenia readmodel z kontekst (y)
  • Ogólnie zwraca obiekty typu Data Transfer Object (DTO)
  • Fin nie należy szukać po stronie zapisu naszej aplikacji (mniej sprzężenia)
  • Model zunifikowanej bazy danych Single (odczyt + zapis): Finder może wywoływać inne lokalizatory (w różnych kontekstach), aby zaspokoić zagnieżdżone obiekty.
  • Przeczytaj konkretne znormalizowany Database model: Finder otrzyma danych w jednym wywołaniu Database
  • na przykład: finder.findOrdersOnDate(date);

Infrastructure Services

  • promocji z infrastruktury: db dostępu, wysyłać e-maile, kolejki komunikatów, itp

Pytanie

czy jest to dokładne zestawienie składników vs. obowiązków? Czego brakuje i co należy przenieść? Mogę zaktualizować listę z odpowiednimi odpowiedziami.

+1

["Implementing Domain-Driven Design"] (https://vaughnvernon.co/?page_id=168) autorstwa Vaughna Vernona dostarcza szczegółów technicznych dotyczących każdego z tych komponentów. Polecam go jako bardzo przydatne źródło oprócz Eric Evans "Domain-Driven Design". –

+0

Przypadkowo znalazłem artykuł Vaughna Vernona zeszłej nocy. Bardzo interesujące! Będę kupować książkę. Czy chcesz dodać coś do listy na podstawie książki? –

Odpowiedz

3

Tak jak powiedziałeś, istnieje wiele opinii na ten temat i musisz je filtrować, ponieważ większość ludzi wydaje opinie bez żadnego doświadczenia w tej sprawie. CQRS to duży temat, więc nie sądzę, że bez wcześniejszego doświadczenia powinieneś wskoczyć całkowicie do DDD i ES. Usługi powinny być dobrze umiejscowione i mieć ściśle określone granice, a jeśli zastosujesz się do tych zasad, będziesz mógł mieć różne implementacje w swojej domenie, więc zacznij od teraz tylko CQRS i dodaj DDD/ES do następujących usług po opanowaniu CQRS.

radziłbym Ci więc rozpocząć budowę CQRS część swojej architektury, brama dla poleceń i jeden dla zapytań, ponieważ jest to powszechne i tylko on, że istnieje tak wiele decyzji, które mają być wykonane:

  • Rest API

  • kontrakty wiadomości/walidacji

  • modele lektura ...

i zacznij wdrażać usługę w bardziej tradycyjny sposób bez DDD, używając tylko wzorca repozytorium. Kiedy zaczynasz czuć się pewnie, możesz przejść do DDD w kategoriach agregatów, a później do ES. Zawsze możesz zmienić początkowe usługi na późniejszym etapie.

Moja rada nie będzie próbowała zrobić wszystkiego naraz, ponieważ zawiedziesz; Widziałem to już wiele razy.

Na przykład: Czekaj na OrderShipped i OrderReceived zdarzeń => Ogień CancelOrderCommand Odczekaj OrderCancelled => rozkaz ogień odwołany email

Sagi nie powinna publikować zdarzenia (saga wzorzec), sag wydarzenia kruszywa i złożyć poleceń . Fakt, że struktury takie jak NServiceBus pozwalają sagi na publikowanie wydarzeń, nie pomaga, więc bądź świadomy.

Jedynka (odczyt + zapis) znormalizowanego Database Model: Finder mogą wywoływać inne Finders (po drugiej kontekstach), aby zaspokoić obiektów zagnieżdżonych

Jakie inne konteksty chcesz mieć w swoich modelach czytać?

Infrastructure Services

Deals with infrastructure: db access, send emails, message queues, etc 

Nie wiem, co masz na myśli przez to, ale na pewno nie wygląda dobrze. Kolejka wiadomości lub usługa bazy danych?

+0

Cześć Marco, dzięki za odpowiedź. Zgadzam się z rozbiciem wdrożenia na etapy. Przeprojektowałem już system, aby był bardziej zorientowany na DDD. Jednak interakcja między kontekstami zawsze odbywała się poprzez bezpośrednie wywoływanie do elewacji innego kontekstu. To oczywiście łączy wszystko ściśle ze sobą. Dzięki podejściu CQRS oddzielenie staje się znacznie łatwiejsze. Najważniejsze jest to, w jaki sposób koordynujesz teraz komunikację między kontekstami: używając zdarzeń i sag (w razie potrzeby). –

+0

Pozwól mi odpowiedzieć na trzy wyciągi, które wyciągnąłeś z listy: 1) Saga nie publikuje żadnych zdarzeń, czeka na zdarzenia, a następnie odpala polecenia lub współdziała z infrastrukturą. –

+0

2) Znormalizowany DB: na przykład, mogę mieć ekran z użytkownikiem i informacjami na temat interakcji użytkownika z systemem. Zamiast wykonywać dwa połączenia i zestawiać je razem, spodziewałbym się połączyć z pojedynczym Finderem, który zwróci dane potrzebne do tego ekranu. Jest to łatwe w przypadku zdenormalizowanego modelu, ale w celu znormalizowania dane mogą być rozłożone w różnych kontekstach, co oznacza, że ​​muszę użyć innego Findera (jeśli były to różne agregaty w tym samym kontekście, to mógłbym po prostu użyć odpowiedniego repozytorium). –