Jak dobrze podzielić aplikację na moduły

2

@nobody01: oczywiście że to może mieć sens, wszystko zależy od konkretnego przypadku. Ja akurat jest raczej przeciwnikiem bezpośredniej komunikacji HTTP pomiędzy serwisami i stawiam na podejście event-driven ale nie oznacza to że ślepo stosował bym takie podejście do wszystkiego.

1

@Aventus: Tak jak piszesz, zależy co jest potrzebne i jaki problem chce się rozwiązać. Jakie masz powody przeciwko komunikacji przez http (czy inne protobuffy), generalnie pobieranie danych na żądanie?

1

@piotrpo: podstawowym powodem jest wspomniany przeze mnie wyżej możliwy łańcuch wywołań. No bo nie ma żadnej gwarancji że wysłanie jednego requestu nie skończy się kilkoma requestami, kolejno do dalszych serwisów. Pomijając to że mamy wiele możliwych punktów błędu, zwiększony czas obsługi procesu, to jeszcze siłą rzeczy moduły będące bezpośrednimi klientami innych modułów muszą wiedzieć o ich istnieniu. Ogólnie jest to podejście raczej odradzane.

Do tego dochodzi również łatwość skalowalności. Wiem że można wystawiać API za load balancerami, używać kontenerów itp. W każdym przypadku jednak competing consumers nasluchujacy eventów (lub commands) to zwyczajnie łatwiejsze podejście. A przynajmniej tak wynika z mojego doświadczenia.

0

@Aventus: Nie wiem czy dobrze rozumiem, dla uproszczenia załóżmy, że mamy jakiegoś klienta, koszyk, katalog produktów, koszyk ma zwrócić przechowywaną przez siebie liczbę wrzuconych produktów i jakieś ich dane z katalogu.

  • klient żąda od koszyka danych
  • koszyk wrzuca na event bus prośbę o dane konkretnych produktów i czeka z wysłaniem odpowiedzi http
  • katalog odbiera żądanie, czyta sobie z bazy danych potrzebne informacje, wrzuca na event bus zwrotkę
  • koszyk odbiera informację i ostatecznie odpowiada klientowi

Dziwność tego rozwiązania bierze się z mojego niezrozumienia, czy nie pasującego do takiego modelu przykładu?

Rozumiem, oczywiście, że asynchroniczność jest generalnie fajniejsza niż synchroniczność i jeżeli np. klient coś zamówi, to koszyk wyśle komendę realizacji do usługi zamówienia, która pobierze sobie to kiedyś z kolejki i obsłuży, ale jeżeli masz na wejściu synchroniczne żądanie, to gromadzenie danych do jego obsługi asynchronicznie wydaje mi się trochę na siłę, bo całą tą asynchroniczność trzeba zamknąć w ramach synchronicznego żądania.

---edit
Chyba, że zakładamy, że koszyk zawsze posiada w cache/kopii dostatecznie dobre dane (eventual consistency), żeby obsłużyć żądanie, które dostaje od klienta.

0

@piotrpo: tutaj chyba nie bardzo pasuje przykład. A przynajmniej ja w serwisie Koszyk widział bym coś znacznie bardziej prostego i po prostu przechowywał tam informacje o aktualnym stanie koszyków, a więc w nich IDs produktów. Jeśli trzeba by również zachować dodatkowe informacje takie jak cena czy nazwa produktu, to byłaby to bardziej obsługa pewnego widoku, a więc te dane mogłyby pochodzić nawet od klienta UI, który już wcześniej je otrzymał wraz z IDs produktów.

to gromadzenie danych do jego obsługi asynchronicznie wydaje mi się trochę na siłę

To prawda, jeśli mowa o gromadzeniu "w locie", tzn. takie gdzie trzeba zwrócić dane na potrzeby konkretnej, aktualnie wykonywanej operacji. Od tego właśnie jest wcześniejsze budowanie danych pochodzących z innych serwisów, ale na potrzeby konkretnego serwisu. W przeciwnym razie masz słuszne wątpliwości, bo bawimy się w zastępowanie asnychronicznoścą odpytywania poprzez HTTP. Sens asynchroniczności jest taki aby wykonywać różne operacje, ale poszczególne moduły już mają gotowe dane do obsługi tych operacji.

5

@piotrpo: A propos wad komunikacji synchronicznej to polecam obejrzeć prezentację

0

Powiedzmy, że chcemy aby Ordering i Products komunikowały się ze sobą asynchronicznie.

W module Products mamy hierarchię grup produktów. Każda grupa produktów ma jakieś swoje cechy (np. produkty z grupy X nie są kupowane od zewnętrznej firmy, tylko wytwarzane przez nas). Jeśli grupa produktów ma cechę Y, to wszystkie produkty będące w tej grupie również mają domyślnie tę cechę. W module Ordering potrzebujemy wiedzieć, czy produkt Z jest wytwarzany przez nas, czy kupowany od kogoś innego po to, żeby np. wyliczyć rabat.

Moje rozumowanie jest takie: moduł Ordering nie potrzebuje wiedzieć nic o grupach produktów. Jego nie interesuje, w jakiej grupie jest produkt. Interesuje go tylko, czy produkt jest wytwarzany przez nas. W Ordering powinniśmy więc jedynie przechowywać przy produkcie flagę, czy produkt jest wytwarzany przez nas, czy nie. I tu pytanie, jak to zrobić. Jeśli ktoś w Products zmieni dane grupy produktów i okaże się, że produkty z grupy Z również są teraz wytwarzane przez nas, to jak powiadomić o zmianach moduł Ordering? Po aktualizacji danych grupy pobrać wszystkie produkty, które są teraz w tej grupie, i wysłać event zawierający zmienianą cechę i identyfikatory wszystkich produktów, które mają teraz tę cechę? Ordering w zależności od tego, jaka cecha została zmieniona, zaktualizuje swoją bazę produktów lub nie. Dobrze myślę?

1

Masz moduł Products, który odpowiada za przechowywanie całości danych o produktach. To jak je sobie przechowuje jest jego wewnętrzną sprawą, a nikt na zewnątrz nie musi i nie powinien być świadomy relacji pomiędzy produktem a grupą i reguł biznesowych wykonywanych w momencie zmian wykonanych na poziomie grupy, Czyli:

  • Masz grupę nasze w niej 5000 produktów. W praktyce ta grupa jest jedynie narzędziem ułatwiającym zarządzanie produktami.
  • Dodajesz jakąś wartość domyślną typu kolor = różowy do grupy
  • Zmieniasz w ten sposób stan tych 5000 produktów i musisz o tym poinformować resztę systemu, więc emitujesz 5000 nowych stanów po jednym dla każdego produktu. Stan zawiera wszystkie informacje o produkcie i jest rozgłaszany przez jakiś service bus w topicu product-updates
  • Moduł Ordering jest zainteresowany częścią danych produktu, subskrybuje topic product-updates, bierze interesujące go dane i zapisuje lokalnie w dogodnej dla siebie formie (np. key-value jeżeli wyszukiwanie zawsze będzie po indeksie). Oczywiście zapisuje tylko te dane, które są mu potrzebne.

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