CQRS - Command vs Event

0

Powiedzmy, że mam aplikację, w której użytkownik może publikować zdjęcia. Najpierw w bazie zapisywane są metadane na temat zdjęcia (tytul, data publikacji itd.), a potem plik jest zapisywany fizycznie na dysku. Czy zapis pliku na dysku powinien być w handlerze komendy CreatePhoto czy w handlerze zdarzenia PhotoCreated? Jeśli mam przestrzegać SRP, to raczej to drugie, tylko czy to nie jest przykład sztucznego tworzenia eventu?

2

Raczej nie ma na to pytanie jednoznacznej odpowiedzi, jak zawsze to zależy od szerszego kontekstu i własnego doświadczenia.

Ostatnio natrafiłem na artykuł poruszający dość luźno właśnie ten problem z podziałem na komendy i zdarzenia:
Message design for event-driven architecture: anti-patterns and pitfalls

1

Uwaga: teoretyzuję, bo nie bawiłem się w CQRS + ES w praktyce:
Nie wiem jak wygląda CQRS bez ES, ale przy ES musisz być w stanie odtworzyć stan aplikacji z samych zdarzeń, bo komendy nie są nigdzie zapisywane. W takim połączeniu komendy służą tylko do tego by wygenerować listę zdarzeń, a dopiero przy obsłudze zdarzeń zmieniamy stan aplikacji. Obsługa pojedynczego zdarzenia polega na najpierw zapisaniu zdarzenia, a potem ewentualnie modyfikacji stanu aplikacji gdzie indziej (jeśli przechowujesz w aplikacji coś więcej niż tylko zdarzenia, a prawie na pewno tak jest).

1

Tak jak kolega wyżej napisał- to zależy. Natomiast mam pytanie co do tego:

Jeśli mam przestrzegać SRP, to raczej to drugie(...)

Dla czego tak uważasz? Nie ma sensu pchać na siłę eventu (no chyba że stosujesz event sourcing, ale to inna bajka), a również nie wydaje mi się żeby fizyczne zapisanie na dysku lamalo SRP w tym przypadku (chociaż to czy i kiedy SRP jest łamane to sprawa bardzo dyskusyjna). Ewentualnie możesz mieć oddzielne polecenie i handlera do fizycznego zapisu.

Dodam jeszcze, że nie jestem pewny co do idei zapisywania czegoś na dysku w handlerze eventu. W takim przypadku mamy do czynienia z czymś co już zaszło, a więc taki handler może co najwyżej zaktualizować swoje dane (np. zapisać do bazy metadane jak i link do fizycznego pliku). Skoro (...) Created, to stworzony a nie częściowo stworzony. No ale raz jeszcze - to zależy

3

Jeśli bawisz się w Event Sourcing. To eventy muszą być napisane tak, żeby:

  • prawdopodobieństwo wywalenia przy odtwarzaniu było minimalne,
  • żeby prowadziły do tego samego rezultatu,
  • obsługa eventu była relatywnie szybka,

Odczytywanie czegokolwiek z dysku (IO) w event to recepta na katastrofę. Zapis/ odczyt może się nie udać, albo ktoś zmieni zawartość pliku, folderów etc.
(ale może u Ciebie coś takiego nie może zajść, prawdopodobieństwo jest nikłe).

Podejsćie dość klasyczne:
Komenda - coś co chcemy od systemu. W Command handlerze walidujemy dane itp. jak wszystko jest ok to tworzymy eventy (jedna komenda daje w wyniku zero lub więcej eventów).
Eventy są generalnie faktami (ostatnio u siebie zmieniłem nawet nazewnictwo na fakty, bo w powalonym DDD jest tyle typów eventów, że można się pogubić). I wiadomo, że się stało. W eventach zasadniczo nie robimy już żadnych walidacji, IO, nie czytamy nawet daty obecnej, ani nie robimy całkiem losowych randomów.

Przy okazji: Kiedyś stowosowało się command sourcing, ale to było mentalnie trudniejsze. Trzeba było przed komendą zrobić wszystkie możliwe walidacje.

Przy okazji: Co do CQRS - ostatnio mnie wkurza. Albo przestałem rozumieć CQRS, albo to nonsens. Jak może operacjqa nie zwracać wyniku? To jest nawet niemozliwe :-), co więcej niepotrzebne.

0

Przy okazji: Co do CQRS - ostatnio mnie wkurza. Albo przestałem rozumieć CQRS, albo to nonsens. Jak może operacjqa nie zwracać wyniku? To jest nawet niemozliwe :-), co więcej niepotrzebne.

Przekonanie że operacja (komenda) nie może zwracać wyniku bierze się z mylenia podejścia command-handler, CQRS oraz event-driven. Są ze sobą powiązane (a konkretnie CQRS korzysta z command-handler), natomiast to nie to samo. Do tego w grę wchodzi jakieś sztywne trzymanie się nie-uniwersalnych zasad. Ktoś patrzy na DDD z wykorzystaniem ES i myśli że agregaty odbierają komendy i tworzą eventy, to w takim razie nigdzie indziej nie można zwracać wyników z handlerow. Z tym że command handler to coś całkowicie innego niż agregat, który w odpowiedzi na komendę tworzy eventa. W takim przypadku owszem, fundamentalnie błędne byłoby zwracanie jakiegoś wyniku ponieważ "z natury" podejście takie zakłada asynchronicznosc oraz eventual consistency.

Natomiast w każdym innym przypadku gdzie komenda jest zwykłym poleceniem zrobienia czegoś, a szczególnie polecenia wyciągnięcia danych to zwrócenie wyniku jest czymś jak najbardziej normalnym. Warto tutaj dodać że przeważnie komenda nie pytająca o dane, a nakazująca ich zapisanie (np. ConfirmOrder) nie zwróci wyniku, bo brak wyjątku będzie sam w sobie wynikiem wskazującym na pozytywne zakończenie operacji.

1

Ktoś patrzy na DDD z wykorzystaniem ES i myśli że agregaty odbierają komendy i tworzą eventy, to w takim razie nigdzie indziej nie można zwracać wyników z handlerow

Aggregaty nie odbierają żadnych komend to serwisy lub dedykowane handlery odbierają komendy.

ostatnio u siebie zmieniłem nawet nazewnictwo na fakty, bo w powalonym DDD jest tyle typów eventów, że można się pogubić

Możesz mi wyjaśnić, o co ci chodzi?

Przy okazji: Co do CQRS - ostatnio mnie wkurza. Albo przestałem rozumieć CQRS, albo to nonsens. Jak może operacjqa nie zwracać wyniku? To jest nawet niemozliwe :-), co więcej niepotrzebne.

Jeśli masz na myśli architekturę, która nie bazuje na eventach to masz rację.

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