Distribuovaný monolit

Disclaimer: Tento článek je napsán pod vlivem confirmation biasu.


Měli jsme v práci takovou planou diskuzi o microservices vs. monolit. Jelikož to k ničemu nespělo (ehm, jsem z toho vycouval 🤭), řekl jsem si, že si v tom udělám trochu jasno a abych si potvrdil, že to, co tak nějak intuitivně tuším, je podepřený nějakými reálnými zkušenostmi.

Následující text je kompilací článků, které jsem četl, respektive rekonstrukcí z výpisků, které jsem si během jejich čtení pořídil. Z toho důvodu neuvádím žádné odkazy. Ve výsledku stejně jde jenom o názorové selekce a přesvědčení. 🤷‍♂️

O co mi vlastně jde? 🤔

Jiskrou, která zažehla onu chabou diskuzi, bylo, když jsem řekl, že jsme nepřešli od monolitu k microservices, ale že máme… distribuovaný monolit.

Problém většiny článků diskuzích o microservices a distribuovaných monolitech je v tom, že se soustředí pouze na aspekt architektury. Ale to je málo — tak jako by slušný softwarový inženýr měl vědět i o jiných aspektech vývoje, než jen o programování (buildy, procesy, project lifecycle/management, atd.), zajímá mě problém distribuovaného monolitu jako celek, ne jen jeho nejzjevnější část (takový ten programátorský cognitive bias 😈).

Začněme otázkama

Samozřejmě, otázek souvisejících s distribuovaným monolitem si můžeme položit spoustu, ale pokud se budu soustředit na aspekty které zajímají mne, formuloval bych tyto:

  • Existuje nějaká část (modul, služba, atd.), která se mění mnohem rychleji, než zbytek systému?
  • Existuje nějaká část, která vyžaduje častější deploymnent, než zbytek systému?
  • Vyžaduje změna nějaké části, aby byl nutný deployment i zbytku systému?

Zejména odpověď na poslední otázku dává jasný náhled, jestli máme distribuovaný monolit.

Jaké jsou typy monolitu?

Než se podívám na jednotlivé fasety distribuovaného monolitu které mě zajímají, neuškodí si vyjmenovat i ty ostatní. Není to vyčerpávající, ani kompletní, ale pokrývá to ty hlavní:

  1. Aplikační monolit: klasika — jedna velká aplikace, se spoustou závislostí, pokrývající mnoho use casů. Často vystavuje větší, či menší množství služeb.
  2. Sdílená databáze: opět klasický příklad — několik aplikací, nebo služeb je společně provázaných skrze sdílené databázové schéma.
  3. Monolitický model: nařízená/doporučená jazyková a modelová konzistence napříč různými kontexty. Často zdůvodněné premisou “každý může pracovat na čemkoliv”. Důsledkem bývají leaking domain models. Často sem spadají různé common moduly a sdílené knihovny.
  4. Monolitické buildy: jeden obrovský build (dnes už většinou součástí continuous integration), který musí proběhnout pro novou verzi jakékoli komponenty. Tj. buildujeme všechno, i když potřebujeme pouze malou část systému.
  5. Monolitické releasy: více malých komponent zabalených jako “release”, které se deployují najednou. Obdoba monolitický buildů — deployujeme všechno, i když potřebujeme deployment jen jedné (malé) části.
  6. Monolitické myšlení: to je to známé one-size-fits-all aplikované na procesy a týmy. Vede to k nadbytečným až zbytečným restrikcím ohledně týmových technologií, implementací a procesů. Spadá sem i neotřesitelná logika “takhle jsme to vždycky dělali”.

Jednotlivé typy monolitů si lze představit buď jako slupky cibule, nebo jako pipelines. Týmy a organizace často věnují velké úsilí aby původní monolit rozbily do microservices, bohužel jen s tím výsledkem, že posunou monolitičnost svého produktu do další vrstvy, či fáze.

Pravděpodobně tím získají nějaké částečné benefity, ale zároveň se izolují od těch fundamentálních přínosů. V horším případě přesunou strukturální problémy hlouběji pod povrch (či dál od sebe), kde zůstanou pod rozlišovací schopností většiny zúčastněných.

Aplikační monolit & sdílená databáze

O tomhle tématu byly popsány kvanta (virtuálního) papíru a je zbytečný to rozmazávat. Je potřeba to řešit, ale nezajímá mě o tom psát.

Nicméně bych vypíchnul jedno důležité pravidlo, aby se to při tom řešení příliš nepřehnalo, protože často slýchám, že single-responsibility principle je něco jako svatý grál. 🏆 V případě microservices platí:

Favor autonomy over the single responsibility principle. — Unknown microservices ninja guru

Monolitický model & sdílené knihovny

Monolitický model má několik úhlů pohledu. Jedním z nich může být relativně(?) známý integrační vzor canonical data model (CDM). Jakkoli jsou zde zjevné (teoretické) benefity, v praxi to končí zpravidla hypertrofovaným modelem, který vyžaduje spoustu adaptérů/konvertorů a, podobně jako sdílená databáze, ovlivňuje všechny zainteresované komponenty. Plus velká režie na údržbu.

Proč je CDM z hlediska microservices špatný a vede k distribuovanému monolitu? Protože nutí jednotlivé servisy implementovat podmnožinu CDM, resp. na změny CDM reagovat.

Odpovědí na problémy CDM může být jiný design pattern, který pochází z knihy Domain-Driven Design od Erica Evanse: Anti-Corruption Layer (ACL). V podstatě jde o tenkou fasádu, která řeší mapování mezi dvěma systémy s různou sémantikou. Ovšem ACL má také svoje mouchy (např. latence, přidaná komplexita, atd.), takže je otázka, jestli se do CDM vůbec pouštět. V případě microservices zní odpověď: ne.

Na implementační rovině bývá CDM zhusta poskytován jako sdílená knihovna. A sdílené knihovny — ať už obsahují CDM, či ne — jsou z určitého pohledu také monolitické modely. Prorůstají jako závislost mnoha aplikacema a jejich změna způsobuje vždy drtivou řetězovou reakci — čím více týmů/projektů nějakou sdílenou knihovnu (či soubor knihoven) používá, tím větší “škodná událost”.

Jakmile microservice použije sdílenou knihovnu, ztrácí svoji panenskou 🤭 nezávislost. — SoftWare Samuraj

Monolitické buildy & deploymenty

Celkem chápu myšlenku stojící za monolitickými buildy — mít “jeden příkaz, který zbuilduje vše”.

Ash nazg durbatulûk, ash nazg gimbatul, Ash nazg thrakatulûk agh burzum-ishi krimpatul.

Všichni víme, kde ta myšlenka pramení a k jakým strašným koncům vedla. Podívejme se, co k tomu dále říká moudrá Wikipedie (potřebné substituce si každý domyslí):

Creating the Ring simultaneously strengthened and weakened Sauron. With the Ring, he could control the power of all the other Rings, and thus he was significantly more powerful after its creation than before; but by binding his power within the Ring, Sauron became dependent on it.

Jestli že se bavíme o microservices, tak žádná závislost zde nemá místo. 🖐️

Monolitické buildy a deploymenty mají své odpůrce a zastánce (a ti by si měli přiznat, že mají distribuovaný monolit). Jak ale o tématu smýšlejí povolaní? Sam Newman, autor knihy Building Microservices, k tomu říká:

There are lots of reasons why we might pick a microservices architecture, but the one I keep coming back to is this property of independent deployability.

Ta slova mému uchu lahodí, protože o tom, si myslím, softwarové inženýrství je — ne o programování, ale o doručování softwaru.

Sam Newman říká i další zajímavé věci:

Applications deployed as a single process, or monoliths, can be modular in their design, with different teams working on each module. It is nothing new — it’s an idea from the early 1970s around structured programming.

Zde mi opět mluví z duše, protože to je to co často vídám — rozsekat aplikaci na služby (moduly), ale deployovat (buildovat) jako jeden celek.

Je smutnou pravdou, že týmy používaji modularizaci i tam, kde to není nutné. 😢 — SoftWare Samuraj

Ačkoli pro to můžou být i rozumné důvody, je dobré mít na paměti jeden velice důležitý aspekt — rollbacky. Protože jedna věc je udělat monolitický deployment. Ale udelět monolitický rollback, aby byl konzistentní, může být nad síly leckterého ostříleného matadora, či týmu. A samozřejmě se tím hrubě kompromituje celá myšlenka microservices.

Monolitické myšlení

Ignorance is Strength — Ministry of Truth

Ignorance is Strength — Ministry of Truth

O monolitckém myšlení by se dal napsat samostatný článek (a to se mi nechce), tak se jen omezím na konstatování, že monolitické myšlení není nic jiného, než totalita — jakýmikoli prostředky udržet status quo a zabránit jakýmkoli změnám. Bez ohledu, jak to škodí týmům, ať už v exekuci, tak v motivaci.

Ze všech výše zmíněných monolitů je tenhle nejtrvalejší. Protože to vyžaduje změnu kultury.

Je (distribuovaný) monolit nutné zlo? 😈

Důvod, proč jsem napsal tenhle článek je primárně pro to, aby si týmy přestaly nalhávat, že mají microservices, když mají ve skutečnosti distribuovaný monolit. Avšak otázka, jestli je distribuovaný monolit něco špatného je legitimní a na místě.

Odpovědí je ono okřídlené “to záleží…”. Protože distribuovaný monolit může být — v daném kontextu — efektivní řešení, které bere v úvahu pro a proti: jak monolitu, tak microservices. Může to být rozumný a funkční kompromis.

Prvotní podmínkou ovšem je, že si tým upřímně přizná, že to co teď mají, je… distribuovaný monolit. Teprve pak je smysluplné s tím začít něco dělat.

Mind Map