wtorek, 13 maja 2014

Microservices w kontekście DDD

Mamy nowy buzowrd: mokroserwis, który zdążył być już w typowy da naszej branży - Montypythonowy - sposób wypaczony:)

Autor artykułu Microservices: Usage Is More Important than Size stawia retoryczne pytanie:
czy mikroserwis to
- SOA, które wreszcie doczekało się poprawnej interpretacji (bez ESB i smutnego SOAP)
- czy może stara "dobra" CORBA i RMI tylko, że podana na REST wraz ze wszystkimi smutnymi konsekwencjami zbytniego rozproszenia?

Kolejne figury retoryczne pojawiają się w tekście Microservices? What about Nanoservices?: Sto linijek to jeszcze makro-serwis czy już nano-serwis (funkcjonalność a nie serwis), który jest antywzorcem?

Mierzenie linijek kodu od linijki to jak zwykle znak, że "coś się dzieje";)

Patrząc z dystansu widać to co zwykle: onanizm techniczny zamiast zrozumienia jaki problem próbujemy rozwiązać.

Wydaje mi się, że gdyby za definicję zakresu mikroserwisu przyjąć: API dla Bounded Context z DDD, to wszystko stałoby się jasne...

17 komentarzy:

ToJaJarek pisze...

Hm... też mam problem z artykułami o mikrousługach, pisał o tym Fowler, tego przesłania chyba nie zrozumiałem, granica "tego pomysłu" dąży do obiektu/agregatu z jego interfejsem... ale to chyba już przegięcie... SOA złożone z pojedynczych use cas'ów??? Kontekst i dziedzinowa specyfika raczej wyklucza "jednej czynności" jako kompletnej kontekstowo aplikacji ....

Marcin pisze...

Na papierze idea "micro services" wygląda bardzo kusząco. W praktyce pojawiają się przynajmniej dwa dylematy:

Essential Complexity - jak podzielić system? Znajomość strategic design z DDD może dać tu jakieś wskazówki. Ale zagadnienie jest naprawdę trudne.

Accidental Complexity - próba rozproszenia systemu bez świetnej infrastruktury (event bus / command bus, monitoring, deduplication etc.) i procesów (continous deployment) to strzał w stopę.

Jak przychodzi mi chęć na rozpraszanie systemów to zawsze powtarzam sobie najpierw ze 100 razy, don't do that, don't do that ...

Ale pewnie czasem trzeba ze względu na złożonośc, wielkość zespołu, skalowalność itp.

Polecam lekturę CQRS Journey, jest ebook i kodzik http://msdn.microsoft.com/en-us/library/jj554200.aspx. Mamy trzy gotowe bounded context-y, więc można sobie spróbować zrobić z tego microservices.

Nie wiem czy mogę ale tu są moje piersze próby wykorzystując Axon-a żeby nie utkąć na infrastrukturze:

https://github.com/mkuthan/example-axon

Wojtek (szogun1987) pisze...

To i ja coś podlinkuje. http://highscalability.com/blog/2014/4/8/microservices-not-a-free-lunch.html

Sławek Sobótka pisze...

@Jarek - też wydaje mi się, że zejście do poziomu Agregatu to kuriozum. To byłoby niżej niż Use Case... nanoserwis czyli stare "dobre" RMI.

Podszedł bym tak: Bounded Context to jakieś kilka/kilkanaście agregatów, nad nimi warstwa Application Logic, która koncepcyjnie modeluje usługi (układające się w podproces złożony z kilku UC) a z technicznego puntu widzenia jest de facto API modułu (mikroserwisu po nowemu).

Sławek Sobótka pisze...

@Marcin
Tak... podstawowa zasada rozprasza obiektów Fowlera: "Just don't":)

Fajnie, że nawiązałeś do złożoności esencjonalnej - gdzieś musi być orkiestracja całego procesu.

W poście podlikowałem klasyczny teskt: http://www.rgoarchitects.com/Files/fallacies.pdf


Dzięki za linka do Journej (zaraz zaczynam czytać, fajny obrazek mają na głównej) i za linka do Twojego projektu - trochę klasek jest więc pewnie za kilka wieczorów ogarnę:)

Sławek Sobótka pisze...

@Wojtek
Dzięki za linka, lektura szczególnie komentarzy uświadamia, że ludzie walczą z różnymi bólami i dlatego nie mogą się dogadać...

Jednych boli wdrożenie, innych potrzeba różnych technologii a innych podział logiczny.

IMHO trzeba zacząć od pakietów/namespace:)
Czyli Bounded Context - namysł nad podziałem logicznym. Bo to jest trudne i później praktycznie nieodwracalne oraz brzemienne w skutkach jeżeli chodzi o zrozumienie problemu domenowego.

A dopiero w dalszej kolejności można zacząć zastanawiać się czy chcemy to rozpraszać, wprowadzać asynchroniczność itd...

Marcin pisze...

Dokładnie tak, zacząć do znalezienia bounded contexts i odpowiednim użyciu pakietów czy namespace-ów.

Mimo że wywołania są robione w ramach jednego procesu (JVM) lub nawet w ramach jednego "unit of work" (Thread Local), kodować tak jak gdyby komunikacja przekraczała te granice. To trudne, jak podświadomie wiemy że to ten sam proces czy transakcja i można pójść na skróty :-(

Dzięki temu mamy szansę na jako taki decoupling naszych bounded contexts.

Jak już upewnimy się że wszystko działa, granice bounded context i publiczne api są ok, to można myśleć o "distibuted architecture".

Wystarczy prześledzić historię Axon Framework, wersja 1.x w zasadzie pozwalała zbudować system w ramach jednej JVM. I co? goście z Trifork i tak tego używali bo dawało dobrą architekturę i decoupling.

Dopiero wersja 2.x pozwala rozproszyć system i wcale nie jestem pewien że robi to wystarczająco dobrze ;-)

Sławek Sobótka pisze...

Chyba zbliżamy się do uber-definicji:)

MS powinien mieć dobrze zdefiniowaną strukturę - np. warstwową: co najmniej api i domena.

I dzięki temu pojawi się model kanoniczny - kontrakt na poziomie API i hermetyczna domena modelująca BC.

Jak to będzie ogarnięte, to prawdopodobieństwo porażki jest mocno zredukowane, znacznie mocniej niż techniczne sposoby wdrożenia tego kodziku...

Piotr Wyczesany (@pwyczes) pisze...

A to nie jest troszkę tak, że pojęcie microservice'u możnaby umiejscowić w infrastrukturze?
Jeśli tak, to wówczas w zależności od problemu (jak @Marcin pisze) możemy _wykorzystać_ microservice na poziomie
- Bounded Contextu,
- Business Componentu w danym Bounded Context'cie (http://www.udidahan.com/2012/02/10/udi-greg-reach-cqrs-agreement/),
- Kilku agregatów blisko leżących ze sobą - przykładowo współdzielących jakiś Workflow, czy też Sagę (trochę j.w.),
- pojedynczego agregatu,
- w ogóle nie wykorzystywać microservice'u, bo to nie ma sensu
Jeśli tak popatrzymy, to uzyskujemy dodatkowy cenny młotek do naszego toolboxa, którego użycie na odpowiednim poziomie mogłoby mieć uzasadnienie (uzasadniając nawet w.w. kuriozum).

Jeśli z technicznego punktu widzenia popatrzymy na wnętrze microservice'u jako Haxagon (Ports & Adapters), to znowu wracamy do dyskusji jak Hexagon wpisuje się w DDD (i ponownie wybór na poziomach wymienionych powyżej).

Co do rozpraszania - zgadzam się z @Marcinem. Być może, w niektórych przypadkach, okaże sie, że nie potrzeba specjalnej infrastruktury, bo wszystkie porty i adaptery działają w jednej maszynie wirtualnej (czy tam procesie), choć samo logiczne wydzielenie microservice'u wpłynie na jakość kodu.

@Sławek - pełna zgoda z rozpoczęciem na poziomie logicznym. Tylko potem (jak już mamy Bounded Contexty) - co dalej? ;) Jaki klucz przyjąć do określenia kiedy microservice jest tym, co nam najlepiej pomoże?

Sławek Sobótka pisze...

@Piotr
Zacznę od końca, bo zastanowienie się nad tym jakie problem rozwiązuje MS jest właśnie "kluczem" o jaki pytasz...

Są różne głosy
- coś coś mieści się w głowie - ok też jestem zdania, że problem niemieszczenia się w głowie jest przyczyną bałaganu i błędów.

Ale można by to rozwiązać po prosto modularyzacją i komponentami (technicznie zależy od platformy).

Pytanie jeszcze w czyjej głowie się nie mieść:) Bo to zależy.

Ale w nietrywialnym systemie w głowie się nie zmieści koordynacja MS.

- odporność na awarie. pada nam jeden MS, ale reszta działa. Idea piękna, ale coś potrzeba czegoś ponad MS (ESB, Saga itd)

- Skalowanie - jw.

Więc jak zwykle wracamy do klasycznych problemów... MS ich nie rozwiązuje, przenosi w inne miejsce...

Piotr Wyczesany (@pwyczes) pisze...

@Sławek, dzięki za bardzo fajne spostrzeżenia. Z uwagi na to, że są bardzo techniczne, to jeszcze bym dodał bardziej organizacyjne:
- coś, co można niezależnie developować (oddzielny team, oddzielne repo ze źródłami, oddzielny proces budowania i releasu)
- coś, co można oddzielnie "sprzedawać" klientom (np. produkty na półkę z pluginami)

Problemy się nie przenoszą - zostają tam, gdzie były - MS dają nam (IMHO) dodatkowe narzędzie, które może wpłynąć na podejmowanie decyzji przy tych problemach.

Co niestety dalej nie daje nam mierzalnej heurystyki, która mogłaby nam służyć przy (nie)decydowaniu się na użycie MS. :)

Sławek Sobótka pisze...

Podsumowując nasze listy "cnót" można się zastanowić jak inaczej można by rozwiązać te problemy (np. jarki, pod warunkiem, że uda się nam ustalić stabilne api:).

...oraz czy problemy tak na prawdę się rozwiążą gdy wejdziemy w szczegóły - np: stabilność api, zarządzenie wersjami itd...

Michał Bartyzel pisze...

Ja bym spojrzał na to MS jako na rozwiązanie pewnego problemu - rozwoju i utrzymania. Wybrażam sobie, że rozumowanie mogło wyglądać tak: "Soft staje się coraz wiekszy, biznes rozwija się coraz dynamiczniej, jest dużo zmian, dużo eksperymentów. Nawet, gdy stosujemy wszystkie seksi wzorce, to żmudnie się refaktoryzuje i rozbudowuje soft. Jest po prostu za duży, a działanie "dziel i rządź" jest b. kostowne po przekroczeniu pewnej skali. Hmmm....co zrobić...No to może piszmy tak, aby nie trzeba było refaktoryzować! Piszmy tak, aby taniej było zaorać dany fragment i napisać go od nowa. Takie mini systemy w systemie...O! Micro services!"

W tym kontekście MS z zakresie Use Case - dlaczego nie? MS jako BC brzmi dobrze. Ale też kierowałbym się nalogiczną zasadą co do Agregatów - projektuj małe BCs.

Tak jak koledzy wspomnieli - gwóźdź programu jest w pytaniu: "Jaka jest metoda na wyznaczanie "właściwych" BCs i jak dobierać ich "rozmiar" ?

Sławek Sobótka pisze...

@Michał

Tak, o tym właśnie rozmawiamy:
1. z jednej strony: jak jeszcze technicznie można osiągnąć tę separację, np: pakiety, widoczność bibliotek itd...
Tak samo jak mogę przepisać MS, mogę przepisać artefakt mavena. MS ew. bardziej bezkompromisowo wymusza granice i dobre api. Ale można zadać pytanie: dlaczego zespół nie potrafi projektować granic i przestrzegać ich reguł? Problemem jest skill techniczny czy wiedza o domenie problemu? Oba problemy są symptomami głębszych problemów w organizacja.

2. Kosz MS. To się samo nie skoordynuje w proces i samo się nie wdroży...


A co do granicy BC to najlepsza zasada: granica wiedzy Eksperta Domenowego - zakładając, że w dużym projekcie bierze udział wielu ED. A duże BC można w głębi dzielić na poddomeny (kilka poddomen jest spiętych jedną warstwą API) - i z poddomen bym jednak nie robił osobnych MS ze względu na koszt zarządzania tym. BC ma spójne API, które techniczne może żyć jako MS.




A tak w ogóle to pojawia się jeszcze kwestia stylu projektowania API: drobno czy grubo ziarniście. Pomysł za uczynienie MS z agregatu wydaje się szalony, ale trzeba by zdać pytanie: po co ktoś może potrzebować takiej ziarnistości? Skończymy z remote interfejsem do EJB... po co? "because we can" jak mawia się w daleko stąd:P

Tomek C pisze...

Bardzo ciekawe spostrzeżenia pojawiają się tu w komentarzach, szczególnie Sławka, żeby zacząć od podziału logicznego.

Szum wokół MS może trochę przesłaniać fakt, że problemy dobrego modelu rozwiązania i jego wdrożenia są do pewnego stopnia ortogonalne.

Idea MS wypłynęła na szersze internetowe wody, gdy paru lekko już brodatych architektów mających w głowie filozofię UNIXa, zaczęło głośno się wypowiadać, że król jest nagi, to znaczy przykładowy JBoss nie jest jedynym słusznym sposobem wdrażania, zwłaszcza, jeśli praktycznie nie korzystamy z gazyliona usług które przeciętny kontener J2EE oferuje. Mikroserwisy są bardzo DevOps-friendly (aplikacja == proces w systemie, każdy to zrozumie i ogarnie) i w drugą stronę, wymagają bardzo dojrzałego działu DevOps, bo w przeciwnym razie będzie bolało.

Z drugiej strony zaczynam się obawiać, że nasza światek mody i hype'u przejmie ideę MS, i przemieli na swój sposób. Z jednego onanizmu możemy przejść w drugi. Już byłem świadkiem dyskusji nad pomysłem zastosowania mikroserwisów, ale brak wsparcia do dependency injection w jednym z gotowych "frameworków" już go dyskwalifikował :)

Piotr Buda pisze...

Moim zdaniem MS warto stosować, jeśli chcesz rozwiązać problem skalowalności i ewentualnie wdrażania zmian. Dopóki nie ma jednego z powyższych, chyba lepszym rozwiązaniem będzie odpowiednia izolacja BC na poziomie pakietów (byle nie na zasadzie 'domain', 'usecases', 'services'). Pamiętajmy, że MS powinien mieć swój model, więc schodzenie niżej niż BC będzie w moim mniemaniu powodowało konieczność stworzenia jakiegoś shared modułu z domeną, co przeczy idei łatwości przepisania/izolacji MS.
Jeśli mamy podział funkcjonalny w pakietach, z dobrze zdefiniowanym API to IMHO łatwo wtedy stworzyć MS, problemem zostaje infrastruktura, ale od tego też są spece.
Na MS jest hype, ale z czasem wszystko sie uspokoi i tak jak kiedyś do wszystkiego próbowano zastosować DDD, tak teraz do wszystkiego próbuje się zastosować MS.

Jakub Nabrdalik pisze...

To ja jeszcze dorzucę taką myśl:

Przy MS zamieniamy ogromny problem miękko-organizacyjny (współpraca między wieloma rozproszonymi zespołami nad jednym code-basem, propagacja wiedzy domenowej i synchronizacja, pilnowanie granic kontekstów) na masę średnich problemów technicznych (deployment, provisioning, monitoring, testowalność, network issues, etc.).

A jakby nie patrzeć, ludzie którzy maczają w tym palce, mają dużo większe predyspozycje do rozwiązywania problemów technicznych, niż miękko-organizacyjnych.

Dlatego, czym bliżej jesteś kodu i czym więcej musisz współpracować pomiędzy zespołami, by coś zaimplementować, tym masz większe parcie na mikroserwisy.