Zapisz się do Newsletter i odbierz bonus! Okładka e-booka

Events vs Commands

Zgłębiając tematykę Domain Driven Design zainteresowałem się różnicami pomiędzy zdarzeniami (events) a komendami (commands) oraz kiedy powinniśmy które stosować. I jeśli przyjrzymy się definicji to na pierwszy rzut oka wygląda jakby rozgraniczenie było oczywiste. Porównajmy zatem Events vs Commands.

Event

Event – wysyłamy gdy chcemy zakomunikować, że coś się wydarzyło i nie za bardzo nas interesuję kto otrzyma to powiadomienie i co z tym zrobi. Na Event może nasłuchiwać wielu subskrybentów – relacja jeden do wielu. Ważnym aspektem jest tutaj czas – event jest wysyłany po zaaplikowaniu akcji – mówi o tym co się już zdarzyło.

Command

Command – to bardziej opakowany request, który wysyłamy do konkretnego (teoretycznie tylko technicznego) serwisu w celu wykonania przez ten serwis danej czynności – relacja jeden do jeden. W tym przypadku jeśli chodzi o czas to jesteśmy przed wykonaniem akcji. W przypadku błędu w wysłaniu komendy – nic się jeszcze nie zdarzyło, możemy powtarzać próbę wysłania command.

Wydaje się proste, prawda?

Sprawdźmy to na przykładach

Niestety z przykładami do DDD jest zawsze cieżko. Jeśli weźmiemy takie z prawdziwego systemu to ciężej będzie je analizować nie znając całej domeny. Pozostają więc oklepane ecommerce lub bank.

Kolejność akcji użytkownika:

  • Order Creation
  • Adding Product to the Order
  • Tax Calculation for the Order
  • Order Confirmation
  • Order Payment

Przykłady komend (commands)

Diagram przedstawiający komunikację synchroniczna opartą na request/response

W przypadku command wszystko wykonuje się synchronicznie. User tworzy zamówienie, dodaje produkty do zamówienia, potwierdza zamówienie i je następnie opłaca. Komunikacja przechodzi przez kolejkę, na której odrazu dostaje dany komponent odpowiedź.

Przykłady zdarzeń (events):

W przypadku eventów zastosowaliśmy wszędzie komunikację asynchroniczną z osobnymi topic-ami dla responsów. Tutaj można się zastanowić czy w przypadku komunikacji wejściowej PaymentRequested – Event oraz Tax Calculation Requested – Event nie można by zastąpić przez command a jako odpowiedź dostawalibyśmy tylko eventy. Jest to właśnie taki przypadek, w którym tak na prawdę nie ma różnicy czy użyjemy eventu czy command. Do momentu, w którym nasłuchuje tylko jeden komponent!

Przykład w świecie rzeczywistym

Obrazek przedstawiający kowboja zamawiającego piwo - przykład opisany obok aby porównać event vs command w modelu zamawiania produktu
  • [Klient w barze -> kelnerka] poproszę 2 piwa [Command]
  • [Kelnerka -> barman] klient zamówił dwa piwa [Event]
  • [barman -> kelnerki] 2 piwa gotowe [Event]
  • alternatywnie:
  • [barman -> kelnerki] (podaj) 2 piwa dla tego pana [command]
  • [kelnerka -> klient] 2 piwa gotowe, proszę sobie zabrać [event]
  • alternatywnie:
  • [kelnerka -> klient] te 2 piwa są dla pana, proszę [command]

Events, Commands czy oba razem?

Patrząc na przykład powyżej, i pomijając wcześniejesze definicje (event – 1 do wielu, commend – 1 do 1) możemy założyć że eventów możemy użyć zamiast komend. Jak i na odwrót – komend zamiast eventów. Możemy również, użyć ich razem (nazwał bym to przeplatanką): komenda triggeruje akcje w serwisie następnie wysyłany jest event komunikujący zaaplikowanie akcji. Na ten wysłany event reaguje kolejny serwis, który z eventu wykonuje wewnętrzną komendę zmieniająca stan w serwisie i generowany jest kolejny event do kolejnego serwisu.

Transport Layer

Popatrzymy na warstwę komunikacji między serwisami w odniesieniu do events jaki commands. W przypadku command najczęściej użyjemy kolejki (Queue), w przypadku events powinniśmy zastosować publish/subscribe (Topic).

Jeśli chodzi o konkretnych brokerów jakich użyć to raczej większość wspiera oba podejścia, queue oraz topic:

  • IBM MQ
  • Apache Kafka
  • RabbitMQ
  • ActiveMQ
  • Amazon SQS (Simple Queue Service)
  • Google Cloud Pub/Sub

Kto decyduje o strukturze Zdarzenia/Komendy?

Kolejną istotną różnicą, której na pierwszy rzut oka nie widać, miedzy event a command jest odpowiedzialność za strukturę. W przypadku eventu, to publisher będzie decydował, jak ma wyglądać dany event. Jeśli z definicji nie interesuje go, czy ten event ktoś przeczyta, i jeśli tak, to ile podmiotów, to na tej samej podstawie on jest właścicielem struktury i decyduje, jak ma dany event wyglądać.

Inaczej jest w przypadku command. Tutaj istnieje bezpośrednia komunikacja między dwoma serwisami i to odbiorca decyduje co może przyjąć i jak ma wyglądać komenda, którą obsłuży.

Async/Sync w odniesieniu do Events vs Commands

Po stwierdzeniu, że komand używamy w kolejkach a event-ow w topic-ach, możemy stwierdzić kolejną różnice. Domyślnie każdy command jest synchroniczny natomiast, każdy event będzie asynchroniczny. Chociaż tak na prawdę nic nie stoi na przeszkodzie aby wysłać command w stylu asynchronicznym przez kolejkę i oczekiwać na odpowiedź zwrotną na kolejce zwrotnej w stylu asynchronicznym. Jeśli na przykład spodziewamy się, że procesowanie takiego command będzie trwało długo.

Podsumowanie

Wracając do przedstawionych wyżej przykładów, czy możemy stwierdzić, że któreś z podejść jest lepsze od drugiego? Wydaje, się, że podane przykłady są zbyt trywialne aby dostrzec potencjalne wady i zalety każdego z nich. W przypadku podejścia z eventami rozszerzalność takiego rozwiązania wydaje się łatwiejsza. Podpięcie dodatkowego serwisu nasłuchującego na event „Payment Processed” jest łatwiejsze niż w przypadku podejścia request/response gdzie aby się wpiąć w proces musimy zrobić modyfikację w istniejącym serwisie i dodatkowo dostawić nową kolejkę lub zrobić komunikację bezpośrednią. Oczywiście temat jest bardziej złożony i wychodzi poza ramy samych różnic pomiędzy Event vs Command. Ten post oryginalnie miał się skupić tylko na tych różnicach właśnie a i tak niechcący wyszedł za bardzo na architekturę Events/Messaging. Dlatego na tym zakończę.

Źródła:

Mastering Software Architecture: Part 5 — The Enigma of Event-Driven Architecture

Focusing on Events

Event Driven Architecture, The Hard Parts : Events Vs Messages

Czy ten wpis Ci się podoba?

Jeśli ten artykuł przypadł Ci do gustu, byłbym bardzo wdzięczny za zostawienie komentarza poniżej lub podzielenie się nim w mediach społecznościowych (ikonki po lewej stronie artykułu). Możesz również kliknąć w ikonę "klaśnięcia", znajdującą się po prawej stronie artykułu. Twoje wsparcie jest dla mnie ogromną motywacją do dalszego tworzenia i pokazuje, że warto było poświęcić czas na napisanie tego wpisu. Natomiast jeśli artykuł nie spełnił Twoich oczekiwań, tym bardziej proszę o konstruktywny feedback w komentarzach. Twoje uwagi są dla mnie cenne i pomogą mi tworzyć lepsze treści w przyszłości. Dziękuję za poświęcony czas i zaangażowanie!

Postaw mi kawę na buycoffee.to

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *