Modularita 3: Mosty, katastrofy a bajtkód

Přepis (resp. původní textová verze) mojí přednášky z jOpenSpace 2018 na téma spolehlivosti software a komplexních systémů.

Jako úvodní všeobjímající rámec tohohle zamyšlení bych chtěl říct to, že se považuji za softwarového inženýra a že jako svůj životní úděl jsem si vybral rozvoj toho oboru jako takového. To není nějaký bezobsažný pohovorový slogan, chci tím říct to, že se neidentifikuji s úspěchy svých produktů, ani pro mě nejsou prioritou synergie v komunitách mých týmů a podobně, ale svojí prací chci hlavně přispívat k rozvoji téhle profese.

Protože náš obor je mladý a ještě trochu tápe a hledá sám sebe, pošilhávají často lidé jako já pro svoje vzory a inspiraci k jiným oborům, přičemž suverénním favoritem je stavařina od které bezostyšně krademe terminologii (slova jako architektura, build projektu apod.) a kterou bereme jako vzor predikovatelnosti, kvality a spolehlivosti. A jestli něco reprezentuje creme de la creme těchto vlastností jsou to ve stavařině mosty.

Zhroucené mosty

Pád Morandiho mostu pro mě byl smutným mementem, že i idoly z plakátů mohou fatálně selhat (asi jako když si přečtete seznam signatářů anticharty). Vždycky jsem si představoval, že sbližování těch oborů bude probíhat spíš opačným směrem. Z těchhle chmur mě přispěchal zachránit Banter citací strejdy Roberta a ujištěním, že to musela být výjimečná událost.

Citace Uncle Bob

Nejdřív jsem si spokojeně čvachtal, jaká je to pravda, ale nějak se mi to zaseklo v hlavě a ‎nutilo mě to zamýšlet se hlouběji a hlouběji, až jsem najednou zjistil, že všechny příklady, na které jsem pomyslel, svědčí ve skutečnosti o přesném opaku.

Terminátor

Pro začátek si vemte třeba takové HTML. Ačkoli se na HTML díváme svrchu, je to de facto programovací jazyk. A je prakticky nezničitelný. Nejen že ho nerozhodí jeden špatný bit, ale i kdyby jste v půlce jeho psaní dostali mrtvici a pak se po klávesnici prošla kočka a ještě si u toho hrála s myší a ještě se vám do té klávesnice vychcala, tak pokud se takový soubor dostane do prohlížeče, trufám si říct, že bude velmi pravděpodobně zobrazen dostatečně dobře na to, aby byl čitelný a nejspíš dokonce tak, že bude i graficky ‎připomínat původní záměr. To rozhodně není ukázka křehkosti.

Můžete namítat, že HTML je ve skutečnosti markupový jazyk a jako takový představuje spíše uživatelský vstup než binární maso opravdového programu a jestli něco umíme fakt dobře, tak je to právě ošetřovat uživatelský vstup. I když bych i tenhle argument chtěl vyvrátit, nechám si to na později, protože mám v rukávu daleko větší trumf: moje zkušenosti s QA nástrojem od jednoho univerzitního spin offu - VerifaLabs.

Aby pro vás ty zkušenosti měly nějaký význam, musím nejdřív obětovat dva tři slajdy na vysvětlení konceptu tohoto nástroje. Je určený pro Javovskou VM a operuje na úrovni, na které v jiných technologiích pracuje linker, Mějme například dva jary zkompilované z následujícího kódu:

Zdroják

VerifaLabs, velmi zjednodušeně řečeno, kontroluje konzistenci cross-referencí mezi jednotlivými jary. Možná jste překvapení, že v tom vůbec nějaká chyba být může, protože to by přeci měl odchytit kompilátor. Hlavní problém kompilátoru ale je, že validuje konzistenci jen mezi vaším kódem a přímo volanou knihovnou, nikoli mezi dvěma knihovnami, které se ve vašem projektu octli již zkompilované. To může udělat až linker, který Java nemá, resp. má jen dynamický linker, který je pro tyto případy bezcený.

Pokud je tedy tohle pro vás novinka, doporučuji pozvat si kluky z VerifaLabs osobně a nechat si od nich udělat přednášku, protože ve skutečnosti existuje mraky důvodů, proč může dojít k takové nekonzistenci a já tu pro ukázku zmíním jen ten jeden exemplární a to jsou tranzitivní závislosti.

Diamond závislosti

Klasický zástupce této třídy problémů je tzv. diamond‎ problem. Vzniká, když dvě přímé závislosti mají stejnou tranzitivní závislost, ale každá ji požaduje v jiné verzi. Dependency tree solver prostě vybere jednu z verzí, ale jestli je tato verze skutečně kompatibilní se všemi, kdo na ní závisí, už nikdo doopravdy nezjišťuje. Případný problém aplikaci zabije až za runtime, takže já bych pro ten problém měl v češtině daleko výstižnější název.

Píča

Teď, když zhruba víte, jaký problém VerifaLabs řeší, se můžeme vrátit k tomu, že jsme ho jednou zkusili pustit proti jednomu našemu středně velkému projektu a tipněte si, kolik našel chyb. Nebojte se tipovat, jste vývojáři a všichni očekávají, že vaše odhady budou minimálně o dva řády vedle.

100 000

Jak je to možné? Bylo v našem projektu sto tisíc chyb, které čekali na příležitost? Samozřejmě, že ne. Základní chyták je v tom, že přestože může být v bajtkódu příslušný invoke, je to problém až ve chvíli, kdy se onen invoke octne v reálně dosažitelné code path.

Chyba nechyba

To se může zdát jako okrajová situace, ale vzhledem k masivní modularitě v současných projektech je to naopak velmi běžné. Co je a co není reálně dosažitelná code path nelze určit statickou analýzou, protože to závisí na runtime datech, kterými budete aplikaci, stejně jako ty mosty, zatěžovat.

Code path v modulárním software

Teď dejte chvilku přemýšlení o tom, co to znamená. Běžný větší projek může spolehlivě běžet přesto, že jeho binárka obsahuje stovky tisíc fatálních chyb. To neznamená nic menšího než že ve skutečnosti opravdu doslovně můžete vzít majzlík a začít přímo z binárky vašeho programu odsekávat tuny a tuny materiálu bez toho, aby se v běžném provozu něco stalo. Právě jsme viděli, že kdyby to tak nebylo, běžný software by vůbec nebyl provozuschopný.

Můžete namítat, že to není fér, že odbourávat materiál mimo živou code path je samozřejmě bezpečná činnost, že Uncle Bob mluvil implicitně právě o chybách v živé code path. Pak se ale podívejme zpět na ty mosty. I ony totiž mají ve skutečnosti svou code path. Jsou to ty pruhy asfaltu, kde se kola dotýkají vozovky, tedy taková wheel path. Všechen ostatní materiál není na mostě proto, aby se po něm jezdilo, ale proto, aby vedl zátěž z wheelpath do níže umístěných bloků. Když příměr mezi mostem a softwarem definujete takto pak i pro most platí, že stačí jen jeden jediný bit, rozumějte hřebík, umístěný na této kritické cestě a přes most neprojede vůbec nic.

Wheel path

Co víc, celý most je, stejně jako software, navržen pro zcela specifickou wheel path, pro kterou je jeho spolehlivost a výdrž garantována i testována. Když necháte kamiony jezdit po chodníku pro chodce, tak ten most dřív nebo později spadne úplně stejně jako software, kterému runtime daty pošlete živou code path do netestovaných končin.

Mostní chodník

Co jsem tím vším chtěl říct? Určitě jsem nechtěl odrazovat od čerpání inspirace z jiných oborů. Chtěl jsem ale upozornit, že příměry, které k tomu používáme, mohou být zrádné a někdy dokonce kontraproduktivní. Chtěl jsem nastolit otázku, jestli projevem nedospělosti našeho oboru není už samotný fakt, že jej bezhlavě srovnáváme s nesrovnatelnými příklady. Základním znakem dospělosti je totiž právě schopnost přesné reflexe vlastní jedinečnosti a dobrá práce s ní.

Kam dál?

  • Prakticky identické téma dokonce i ve spojení s mosty rozebírá Jeff Attwood na svém blogu (našel jsem až po vytvoření této přednášky).
  • Podobné téma vadných příměrů mezi obory, taky na příkladu mostů, taky rozebírají v přednášce Real software engineering (to je moje přímá inspirace).
  • Dovolil bych si doporučit i svoje poznámky k modularitě obecně, protože rozebírají to, co v marketingových materiálech většinou nenajdete: že modularita je problém fundamentální od které vás žádný nástroj úplně osvobodit nemůže.
  • Ohledně spolehlivosti komplexních systémů doporučuji k přečtení tohle a tohle
  • Opačný názor než je v tomto článku a ještě k tomu z druhé strany barikády poskytuje toto Twitter vlákno