Modularność, modularny monolit i mikroserwisy
Moduły, czyli podstawowy klocek w DDD
Komunikacja modułów
Komunikacja asynchroniczna w prawdziwym świecie
Kolejka w programowaniu
Kolejka, jako optymalizacja
Zdarzenia, czyli eventy
Komendy, czyli command
Zdarzenia w praktyce, czyli droga do decoupling
Kulisy prowadzenia bloga
System do prowadzenia bloga, jako praktycznie zastosowanie praktyk DDD
Prawdziwy przykład na komendy i zdarzenia
Podsumowanie, czyli event czy command?
Spis treści
Od kiedy zacząłem więcej interesować się architekturą, to śmiało można nazwać mnie fanatykiem modularyzacji. Za każdym razem jak myślę o jakimś systemie staram się go ułożyć w jakieś sensowne pudełka, które będą szczelnie zamknięte i komunikować będą się przez wystawione przez siebie API. Zmniejsza to coupling między sobą, co jest bardzo pożądanym efektem, ale to już opisałem w poprzednim wpisie.
Modularność, modularny monolit i mikroserwisy
Nie chcę też teraz opisywać dokładnie całej modularyzacji, bo to temat prawdopodobnie na więcej niż jeden wpis. Wydaje mi się, że w dużym skrócie każdy system można przedstawić na osi dwóch współrzędnych. Na jednej osi mamy modularność, a na drugiej rozproszenie. Wychodzą zatem 4 możliwości.
modularny | rozproszony | mikroserwis |
modularny | nierozproszony | modularny monolit |
niemodularny | nierozproszony | monolit (często big ball of mud ) |
niemodularny | rozproszony | rozproszony monolit |
Chętnie szerzej opiszę ten temat w oddzielnych wpisach, jeśli będą ku temu chętni. Chciałbym tylko dodać, że moim zdaniem najlepszym rozwiązaniem jest modularny monolit, gdyż daje nam ogromny komfort pracy, jednocześnie jest bardzo łatwy do zmigrowania na mikroserwisy. Dodatkowo wybacza błędnie postawione granice. Z drugiej strony najgorszy jest rozproszony monolit, czyli system w którym usługi są rozproszone, ale każda rozmawia z każdą.
Modularność nie jest celem! Jest bardziej rozwiązaniem, które zapewnia ewolucyjność i łatwość rozbudowy systemu.
Moduły, czyli podstawowy klocek w DDD
Wiemy jakie mamy możliwości. Teraz krótko czym jest moduł? Niestety słowo moduł może być bardzo niejednoznaczne, na przykład w funkcyjnym języku programowania - Elixir , funkcje grupuje się właśnie w moduły. Dla uproszczenia można przyjąć, że jeden plik to jeden moduł. W ujęciu DDD i w naszym kontekście jako moduł traktowałbym jakąś odseparowaną usługę, czy funkcjonalność w systemie, która jest zamknięta i wystawia jakiś publiczny interfejs.
Czytając mój poprzedni wpis o couplingu można zauważyć, że bardzo pilnowałem, żeby elementy systemu były zamknięte i w tym ujęciu moduł nie różni się od klasy. Może za wyjątkiem, że grupuje wiele klas.
Komunikacja modułów
W monolicie mamy ten komfort, że możemy rozmawiać ze sobą synchronicznie, po wspólnie wypracowanym interfejsie. Natomiast w mikroserwisach taka sama komunikacja może być już problematyczna, bo taka synchroniczna komunikacja najczęściej przebiega po http, a to może być najzwyczajniej w świecie wolne. Dlatego w mikroserwisach preferuje się bardziej komunikację asynchroniczną. Nie znaczy to, że w modularnym monolicie nie można tak robić. Otóż można i czasem jest to dobra praktyka, bo moduły będą od siebie jeszcze bardziej oddzielone i ewentualne wyniesienie ich jako oddzielnie wdrażane usługi będzie znacznie łatwiejsze.
Komunikacja asynchroniczna w prawdziwym świecie
No dobra, ale jak rozumieć taką komunikację asynchroniczną? Najłatwiej przez analogię. Wyobraźmy sobie sklep do kupowania książek, który jeszcze nie ma strony internetowej. Podejrzewam, że mogłoby to działać następująco
- Dział BOK odbiera telefon od klienta i zapisuje zamówienie
- Zamówienie trafia do działu księgowości i płatności
- Dział księgowości podlicza wszystko i wystawia fakturę, a następnie wysyła ją do klienta
- Po uiszczeniu opłaty zamówienie trafia do działu magazynowego w którym książki z tego zamówienia są pakowane
- Na koniec spakowane książki trafiają do kuriera, który paczkę wysyła do klienta
Widzimy, że są tu jawne cięcia i przyjmijmy, że gdybyśmy projektowali system dla tego sklepu, to powstały moduły dokładnie takie same jak działy w organizacji ( tak, wiem że często to jest błędne podejście, natomiast do celów edukacyjnych to w zupełności wystarczy ). A więc po podziale mamy moduły
- BOK
- Księgowość i płatność
- Magazyn
Teraz jeśli mielibyśmy zrobić komunikację pomiędzy tymi systemami, to wydaje mi się, że spokojnie komunikacja między nimi mogłaby przebiegać asynchronicznie. Dlaczego? Jeśli teraz dział BOK musiał na przykład wysłać maila do księgowości, to naturalnie była to komunikacja typu fire&forget , czyli BOK wysłał informację i nie czekał na informację zwrotną. A to jest właśnie definicja komunikacji asynchronicznej. Podobnie z księgowością, która po dopięciu formalności wysłała zawiadomienie do magazynu, żeby ci z kolei spakowali tę konkretną książkę. W zasadzie idąc tym podejściem gdyby wprowadzić do systemu sprzedaż cegieł zamiast książek, to jedyną zmianę poczułby magazyn, który musiałby to inaczej pakować. BOK pewnie otrzymałby nową ofertę, ale jego praca zasadniczo by się nie zmieniła. O księgowości nie wspominając, bo u nich to nieważne czy ktoś kupuje książki, cegły czy komputery. Ważne, żeby zgadzała się kwota i ewentualnie podatek, jeśli system ma również go rozliczać ( chociaż z punktu prawnego, pewnie podatek jest ważniejszy ;) ).
Kolejka w programowaniu
Jeśli mówimy o komunikacji asynchronicznej, zwłaszcza w mikroserwisach, to musimy wziąć pod uwagę, że serwis wysyłający informację i serwis odbierający informację nie muszą być dostępne w tej samej chwili. To kolejny powód dla którego komunikacja synchroniczna w usługach rozproszonych jest średnim pomysłem. Jak więc sobie z tym poradzić? Z pomocą przychodzi kolejka, czyli swoisty bufor operacji do przetworzenia.
Czyli odnosząc to do naszego przykładu, jeśli BOK pracuje od 6 do 20, a księgowość od 8 do 18, to normalnie od 6 do 8 oraz od 18 do 20 system jakoś musi sobie z tym radzić. Najprościej jest to ująć tak, że BOK wszystkie telefony po godzinie 18 przetwarza i wysyła maila do księgowości, lub w nowym systemie zaznacza, że dane zamówienie jest przygotowane. Księgowość przychodzi do pracy i zaczyna od przerobienia zaległości z maila/systemu, a następnie przechodzi do bieżących tematów. I tak właśnie w skrócie działa kolejka.
Kolejka, jako optymalizacja
Skoro wiemy, że kolejki potrafią być buforem, to pozwalają nam również skalować system. Ile razy zdarzyło się Wam, że w dniu premiery zapisów na dane wydarzenie, sprzedaży biletów, bądź promocji na black friday system przestawał działać po pierwszych minutach? Mi wielokrotnie, jak chciałem na przykład zarejestrować się na limitowane wydarzenie, albo sklep z planszówkami pomylił się z ceną i gry śmigały po kilka złotych. Nie wspominając już o stronach rządowych, gdzie na przykład musiałem coś w CEIDG zmienić, a tam przerwy, bo jakaś ważna zmiana i nagle wszyscy muszą się aktualizować. Prawdopodobnie aplikacja nie była dostosowana do nagłego skoku ruchu przez co po prostu wysiada. I przez to dany sklep nie zarobiłby praktycznie nic. Zastosowanie kolejki by tu mogło sporo pomóc, bo każde zamówienie mogłoby wpadać właśnie do takiego buforu, a system do ich obsługi realizowałby je po kolei, w dostępnym dla siebie tempie. Dzięki takiemu rozwiązaniu UX całej aplikacji podniósłby się niesamowicie, bo czas odpowiedzi byłby znacznie krótszy, no i przede wszystkim system nie padłby podczas nagłego skoku, co przełożyłoby się na większą sprzedaż. Oczywiście nie ma nic za darmo. W takim podejściu mogłoby się zdarzyć, że dwóch klientów kupiłoby ten sam produkt. Co wtedy? Pytanie biznesu, czy mogłaby się zdarzyć taka sytuacja prawdopodobnie skończyłoby się odpowiedzią, że to jest wykluczone! Natomiast zastanówmy się tak realnie. Po pierwsze, jakie jest tego prawdopodobieństwo, a po drugie jeśli sprzedajemy książki o wartości 20, 50, czy nawet 100 złotych i na 10 tysięcy sprzedanych egzemplarzy w black weekend zdarzyłyby się dwie takie sytuacje, to czy danie bonu rabatowego dla jednego z tych klientów, nawet o dwukrotności jego zamówienia nie byłaby bardziej korzystne? Myślę, że taka argumentacja przed biznesem byłaby już jak najbardziej akceptowalna.
Praca w systemie Kanban również jest formą kolejki. Trzeba pamiętać, żeby praca szła płynnie. Jeśli w zespole jest więcej osób i każdy sam dba o dobieranie sobie pracy, to naszym obowiązkiem jest pobranie kolejnego zadania, zrealizowanie go i przesunięcie do kolejnej listy. Z tej nowej listy kolejna osoba, na przykład tester będzie mógł dobierać swoje zadania i tak dalej. I w ten sposób można porównać kolejne kolumny Kanbana właśnie do kolejek. Oczywiście jest to uproszczenie ale myślę, że w miarę zrozumiałe.
Zdarzenia, czyli eventy
Poznaliśmy już ogólną zasadę modularyzacji, wiemy czym są kolejki, to teraz przejdźmy do jednego z kluczowych zagadnień tego wpisu, czyli zdarzeń. Zdarzenie to nic innego jak wyemitowanie informacji o dokonanej czynności. Czyli jest to fakt dokonany. To jest bardzo ważne!
Na kilku przykładach z życia, zdarzeniami mogą być
- głośny okrzyk - "puściłem dropa bazy na produkcji! Pomocy!" - nie interesuje mnie, kto mi pomoże. Mówię to głośno, bo każde wsparcie jest ważne
- wyjście z biura mówiąc do wszystkich "cześć" - w sumie nie interesuje Cię, czy odpowiedzą czy nie. Komunikujesz, że idziesz żeby inni wiedzieli, że Cię już nie ma, lub po prostu z grzeczności
- przepchnięcie zdarzenia na tablicy kanbanowej - w zasadzie jeśli w moim zespole jest na przykład 3 testerów, to nie jest istotne który z nich sprawdzi i odbierze moje zadanie, ja przepchnąłem zadanie i czekam aż któryś je zweryfikuje
Widać zatem już na pierwszy rzut oka, że zdarzenia mają do siebie to, że w zasadzie odbiorca wiadomości jest nieistotny. Odbiorca może być jeden, a może być ich wielu. Z mojego punktu widzenia to jest nieważne. Ba, może się nawet zdarzyć, że nie ma żadnego odbiorcy i w sporadycznych przypadkach, to również jest OK. Dobrą heurystyką jest określenie ilu odbiorców będzie oczekiwało mojej wiadomości. Jeśli jest ich więcej niż 1, to często zdarzenie będzie dobrym wyborem.
Komendy, czyli command
Komendy, to drugi, kluczowy element wpisu. W przeciwieństwie do zdarzeń nie emitują faktu dokonanego, ale raczej wykazują intencję, czyli są formą rozkazu. Kilka przykładowych komend z życia codziennego
- Dawid, wynieś śmieci - wiem, że jeśli powiem w próżnię, żeby ktoś wyniósł śmieci, to prawdopodobnie wszyscy to zignorują
- Marcin, wyślij maila - konkretna instrukcja do Marcina, żeby ten wysłał maila (prośba ;) )
- Tresura psa, np komenda siad - tu z samej nazwy wiemy, że chodzi o komendę
Jak widać tutaj kluczowym elementem jest fakt, że znamy odbiorcę i jawnie każdemu mu zrobić to o co go prosimy. Tak więc ten typ komunikacji jest dobry właśnie jeśli chcemy nadać intencję, albo wydajemy rozkaz. Możemy to rozumieć jako zwykłe funkcje, bądź metody, które wykonują się asynchronicznie.
Zdarzenia w praktyce, czyli droga do decoupling
Poznaliśmy już trochę teorii, a teraz przejdźmy do przykładów w programowaniu. Weźmy na tapet wpominiany już system do sprzedaży książek. Jeśli zaprojektujemy system tak, że dział obsługi klienta miałby swój panel i po zakończeniu pracy emitowało by się specjalne zdarzenie, na przykład " zamówienie zostało przyjęte ", to moduł do księgowości mógłby słuchać takich zdarzeń i na ich podstawie budować listę dokumentów do księgowania. Jaką mamy z tego korzyść? A no taką, że teraz moduł dla BOK nie wie nic o tym co dalej dzieje się z tym zamówieniem, tzn nie interesuje go, że dalej jest jakaś księgowość, a więc mamy bardzo mały coupling. Dodatkowo jeśli chcielibyśmy wprowadzić dodatkową warstwę, na przykład w firmie powstaje dział analiz, który również potrzebuje informacji o przyjętych zamówieniach, to możemy ro zrobić bez ingerencji w istniejącym module. Zauważmy, że teraz moduł BOK nie musi wprowadzać żadnej modyfikacji. Tworzymy nowy moduł, który również nasłuchuje na wysłanym zdarzeniu i buduje specjalne raporty. Przypadkiem dostosowaliśmy nasze modułu do zasady OpenClosed i to na wyższym poziomie niż klasa. To się nazywa zdrowe podejście do architektury!
Podobna sytuacja mogłaby mieć miejsce w dziale księgowości, bo zastanówmy się czy moduł księgowości musi wiedzieć, że jest jakiś magazyn? Moim zdaniem nie. Jest to księgarnia, więc jest szansa, że w przyszłości sprzedawane będą na przykład ebooki, lub audiobooki. Jeśli byśmy zaszyli jawnie, że księgowość wysyła informację do magazynu, to podczas wprowadzania do sprzedaży form elektronicznych trzeba by rozkuwać system do księgowości, a chyba nie o to chodzi. Dlatego tutaj również sensowne wydaje się wyemitowanie zdarzenia po zaksięgowaniu wpłaty system, tak żeby system magazynowy do wyczekiwał. Jak pojawi się coś do roboty, to natychmiast by przekazywał paczkę do pakowania. W przypadku pojawienia się ebooków, to magazyn ignorowały paczki bez wymiarów, a do form elektronicznych powstałby na przykład system mailingowy. Ten wysyłał by maila jeśli zamówienie byłoby właśnie w formie elektronicznej.
Zauważmy kolejną równie ważną zaletę, która wyszła tutaj przypadkiem. Mianowicie mając taki podział w każdym module możemy mówić o zamówieniu jako czymś zupełnie innym. W module BOK zamówienie, to lista pozycji do kupienia z konkretnymi tytułami, cenami i być może promocjami. W module księgowości, to już po prostu lista z nazwą i ceną. Z kolei na magazynie to już fizyczne przedmioty, które posiadają wymiary i wagę. Dzięki temu nie musimy robić boskich klas z atrybutami "na zapas". Teraz klasy mają tylko te atrybuty, które są faktycznie istotne w danym procesie biznesowym, a więc kohezja tych klas i modułów rośnie. Kolejna zaleta, która wyszła niejako przypadkiem. Widać zatem, że dobre praktyki programowania przenikają się wzajemnie i uzupełniają
Kulisy prowadzenia bloga
To nie jest tak, że tylko zdarzenia są dobre. W poprzednim przykładzie przyjęliśmy pewne założenia, które nas tak ukierunkowały. Myślę, że aby pokazać dobry przykład komend lepiej przejść na mojego bloga. Co prawda teraz robię to sam, ewentualnie z pomocą mojej żony, albo dwójki przyjaciół, którzy przed publikacją czasem recenzują moje wpisy. Zedrę trochę tajemnicy jak wygląda proces tworzenia wpisów i zaproponuję moduły, które Ja bym widział, gdybym robił system do prowadzenia swojego bloga na szerszą skalę.
Zanim wezmę się za jakiś wpis robię listę ciekawych tematów. Niestety jest to lista, która nie ma końca. Czasem jak w zespole pojawi się jakaś trudność, to przesuwam kolejność wpisów, tak żeby wpis wyjaśniający zespołowi trudny w danym momencie fragment trafił na pierwsze miejsce. Jest to swoisty backlog mojego bloga.
Jak mam już swój backlog, czyli listę pomysłów, to zabieram się za realizację wpisu. Najczęściej pierwszym krokiem jest zrobienie ogólnego brief oraz kumulacja wiedzy. Do tego przypominam sobie wszystkie materiały, które były inspiracją do powstania wpisu. Niestety, czasem inspiracją są całe materiały wideo trwające po 2 godziny, albo całe rozdziały książek po 50 i więcej stron. Innym razem są to MRy, albo dyskusje przy kawie w których wywiązywały się ciekawe wnioski. Czasem są to wpisy, które po prostu płyną. Ale za każdym razem mam jakiś ogólny zarys.
Kolejnym krokiem jest napisanie właściwego tekstu. I to paradoksalnie często jest czas krótszy niż wyszukiwanie informacji.
Po napisaniu tekstu wybieram odpowiednią grafikę, którą w 90% przypadków konsultuję z żoną, bo jakoś Ona ma lepsze oko ode mnie ;)
Mając już tekst i grafikę zabieram się za poprawki gramatyczne. Czyli czytam tekst, przepuszczam go przez walidację i staram się wyłapać wszystkie literówki, czy proste błędy.
Przedostatnim krokiem jest optymalizacja pod kątem SEO. Tutaj przepuszczam przez kilka narzędzi i zmieniam treść zgodnie z uwagami. Cały proces powtarzam kilkukrotnie. Dlatego niektóre moje teksty mogą wyglądać jak typowe teksty pod google, w których treści się powtarzają. Niestety google to lubi ;)
Ostatnim, opcjonalnym krokiem jest wysłanie do recenzji. Jeśli ta przejdzie pozytywnie, to publikuje swój wpis.
System do prowadzenia bloga, jako praktycznie zastosowanie praktyk DDD
Jak widać są tu konkretne kroki z jawną intencją. Co prawda proces optymalizacji SEO i wybierania grafiki można zrównoleglić, ale poza tym cała reszta musi wykonywać się asynchronicznie i w moim przypadku jest to konkretna intencja, którą chcę osiągnąć. Czyli jakbym robił system, to po zrobieniu listy założeń, prawdopodobnie wysłałbym komendę do modułu z treścią prawdziwą. To akurat jest dość dyskusyjne, bo zdarzenie również by tutaj pasowało. Natomiast komenda pozwala mi nadać intencję i to byłaby główna heurystyka.
Jasną sprawę miałbym natomiast w module recenzji. Już tłumaczę dlaczego. Moduł do recenzji w moim systemie byłby całkowicie autonomiczny. Powiem więcej, prawdopodobnie byłby to gotowy komponent. I w zasadzie nie chciałbym, żeby wiedział z jakiego powodu nastąpiła recenzja. Bo zastanówmy się, co recenzenta interesuje, że tekst przeszedł weryfikację SEO? Jeśli zacząłbym publikować galerie, albo wideo, a nie artykuły, to tutaj zrezygnowałbym z weryfikacji SEO w całości. Więc tutaj komenda " zrecenzuj mi to " jest bardziej uzasadniona. Teraz to moduł recenzji jest autonomiczny. Mamy również inną korzyść. Możemy bowiem wysyłać do recenzji cokolwiek i na jakimkolwiek etapie, oby tylko było to zgodne z interfejsem modułu do recenzji. Czyli teraz niektóre wpisy mogą mieć ścieżkę krótszą, bądź dłuższą.
Prawdziwy przykład na komendy i zdarzenia
No dobra, trochę tu wymyśliłem jakiś sklep, czy blog, ale jak to ma się do prawdziwego systemu? Weźmy prosty system symulujący twittera, z kilkoma założeniami
- Użytkownik może założyć konto
- Po założeniu konta przychodzi mail z linkiem aktywacyjnym
- Użytkownik może napisać krótką wiadomość, którą widzą wszyscy inni użytkownicy systemu ( celowo nie robię znajomych, żeby całość była łatwiejsza )
- Administrator ma możliwość podejrzenia we własnym panelu wszystkich zarejestrowanych użytkowników
- Administrator ma możliwość podejrzenia wszystkich wysłanych wpisów
Bez głębszej analizy widać tu 3 główne moduły
- Moduł użytkownika (z logowaniem i rejestracją)
- Moduł wiadomości / twittów
- Moduł administracyjny
Po dłuższym zastanowieniu się myślę, że warto wprowadzić kolejny moduł, czyli notyfikacje, który będzie odpowiedzialny za wysyłkę maili do użytkownika. Przyjmijmy, że chcemy iść za modą i projektujemy mikroserwisy. Przejdźmy przez dwie proste ścieżki
Rejestracja użytkownika i zdarzenia
- użytkownik po zarejestrowaniu się emituje zdarzenie "user.created"
- system notyfikacji nasłuchuje na zdarzenie "user.created" i wysyła maila z linkiem aktywacyjnym
- system administracyjny nasłuchuje na zdarzenie "user.created" i tworzy zdegenerowaną kopię użytkownika w panelu CMS ( w końcu mamy moduły, więc nie powinniśmy za każdym razem pytać użytkownika. Trzymanie takiej kopii to często dobra praktyka. Choć należy pamiętać, że nie zawsze! )
Blokowanie użytkownika i komendy
- administrator przeglądając wiadomości widzi wulgarne treści i wysyła komendę " block_user "
- Użytkownik reaguje na komendę " block_user ", poprzez ustawienie statusu na zablokowany, co uniemożliwi mu następne logowanie
Dobrą praktyką na walidacje naszych pomysłów jest zadanie sobie albo biznesowi kilku pytań, które pozwolą nam określić czy mamy dobry kierunek zależności. Zauważmy jak teraz to wygląda
-
moduł użytkownika nie wie nic o panelu administracyjnym.
- wysyła jakieś zdarzenie i nie interesuje go, co z tym się stanie
- odbiera informację o tym, że został zbanowany. Nie musi wiedzieć kto ani dlaczego go zbanował. Oczywiście biznesowo pewnie można zrobić jakiś email itd. natomiast technicznie jest to klocek, który jest zupełnie autonomiczny. Można zatem go wymienieć, bez obawy o resztę systemu
- moduł administracyjny musi nasłuchiwać na stworzenie użytkownika, żeby odtworzyć jego zdegenerowaną kopię
- moduł administracyjny wie i rozumie czym jest gracz, dlatego to ten moduł wysyła zdarzenie blokujące gracza
- moduł mailingowy słucha zdarzenia na stworzenie użytkownika, podobnie jak administracja
A teraz zadajmy sobie kilka wspomnianych pytań, żeby określić, czy to dobrze, że mailing słucha na użytkowniku, a nie odwrotnie, czyli to użytkownik komendą żąda, żeby email został wysłany
Pytania weryfikując, pozwalające wybrac komendę i zdarzenie
1. Czy jest więcej niż jedna usługa, która jest zainteresowana tworzeniem użytkownika?
TAK, mailing i panel administracyjny
2. Czy w przyszłości mogą dojść inne maile?
Nie wiemy, ale rozmawialiśmy o kilku usprawnieniach do linka aktywacyjnego:
jeśli ktoś nie kliknął w link aktywacyjny, to mail przychodzi ponownie po 30 dniach
jeśli ktoś nie kliknął w link aktywacyjny nawet po 30 dniach, to wysyłamy mu mail co 10 twit.
Jak widać możemy eksperymentować z różną wysyłką maila bez dotykania innych modułów. Ogromna zaleta tego rozwiązania
Gdyby nie był to link aktywacyjny, tylko na przykład mail powitalny, który na 90% wysyłany jest tylko raz, albo link aktywacyjny byłby wymagany do dalszego logowania, to raczej poszedłbym w kierunku komendy, natomiast teraz zdarzenie wygląda na bardziej przyszłościowe
A teraz przejdźmy do sprawdzenia, czy to dobrze, że moduł administracyjny wysyła komendę blokującą użytkownika. Tu ciężko zadać pytania, ale możemy postawić tezy z przyszłymi wymaganiami, np. że dochodzi nowy system który automatycznie rozpoznaje wulgarne zwrotny i blokuje użytkowników - super, ten również wysyła komendę, administrator będzie odciążony. Inny przykład, to nowy system, który automatycznie blokuje użytkowników jeśli ten zaczyna spamować i wysyła więcej niż 100 wiadomości na sekundę - super, bo nie trzeba rozkuwać modułu użytkownika. W zasadzie z punktu widzenia systemu całość jest praktyczna, bo można dodawać nowe reguły, które blokują użytkownika. Można też podejść szerzej i zaproponować cały system blokad, który słuchałby na wszystkim, od akcji użytkownika, po prośby administratora i podejmował decyzję czy zablokować użytkownika, a może go odblokować, bo na przykład wprowadzamy blokady tymczasowe. Teraz to wszystkie systemu stają się niezależne od czegoś takiego jak blokada, a ta jest ładnie zamknięta w jednym miejscu. Tylko tu musimy pamiętać, żeby nie robić wyjątków i absolutnie wszystko przepuszczać przez ten system. Nawet jeśli administrator chciałby zablokować użytkownika, to nie robi tego bezpośrednio, tylko wysyła informację do naszego nowego systemu i ten zajmuje się dalszym procesowaniem.
Podsumowanie, czyli event czy command?
Wpis wyszedł znacznie dłuższy niż podejrzewałem. Starałem się zawrzeć w nim wszystko co sam chciałbym usłyszeć wcześniej. Zdarzenia i komendy to bardzo praktyczna wiedza. Sam pracowałem z takim systemem przez ostatnie 2 lata i nie do końca byłem świadomy jak to działa pod spodem. Dopiero po bliższym zapoznaniu się z materiałami Martina Fowlera, Grega Younga i kursu DNA zgłębiłem to mocniej.
Nie ma jednoznacznej odpowiedzi kiedy lepsza jest komenda, a kiedy zdarzenie. Wszystko wynika z kontekstu. Jeśli miałbym dać jedną radę, to byłoby to słuchanie biznesu. Ale to dosłowne słuchanie biznesu . Bo bez zrozumienia biznesu niestety nie zaprojektujemy dobrego systemu, a tym bardziej nie podzielimy go na dobre moduły i nie zaproponujemy sensownej komunikacji. Pamiętajmy, że komunikacja asynchroniczna nie zawsze ma sens i należy stosować ją rozważnie. A jak już się na nią decydujemy, to korzystajmy z jej potencjału maksymalnie
Czy wpis wystarczająco wyjaśnił Ci czym jest komenda i zdarzenie? Jeśli nie, to śmiało pisz w komentarzu, a Ja postaram się rozjaśnić twoje pytania.