Krev, pot a testy
26. 6. 2019
Krev, pot a testy

Je to vždycky smutná situace: vaše kdysi oblíbená aplikace už rok nedostala pořádný update s novými užitečnými funkcemi, ačkoliv dříve bývala aktualizovaná i několikrát za měsíc. Kdysi bleskurychlá odezva jejích serverů nyní odpovídá spíše tempu astmatického lenochoda a stabilní je asi jako kurz Bitcoinu. Frustrace uživatelů (kteří ale mají naštěstí téměř vždycky možnost odejít ke konkurenci) ovšem není nic proti tomu, co se děje na druhé straně. 

Software v tomto stádiu rozkladu má totiž velmi často jednoho společného jmenovatele: absenci testů.

Zápisky z mrtvého domu

Nikdo nechce pracovat na aplikaci, která se dostala do této fáze (i když všichni jsme to kdysi jednou zažili a kdo tvrdí, že ne, ten to dělá dodnes). Atmosféra v takovém týmu je tvořená smrtícím koktejlem lhostejnosti (těch, kterým už na výsledku přestalo záležet) a strachu (těch, kterým na něm ještě trochu záleží). Nejhorší druh strachu je přitom ten, kdy se všichni bojí sáhnout do kódu, aby se aplikace (většinou na překvapivém, nesouvisejícím místě) nerozbila—ale jak si to spolehlivě ověřit? Klasický manuální přístup „šťourání klackem do náhodných míst“ následovaný rádoby sebevědomým „jo, to je dobrý“ samozřejmě není spolehlivý a už vůbec ne škálovatelný, a z toho plyne jediná věc: testování je nutné automatizovat!

Ono totiž ztratit kontrolu nad chováním bestie o mnoha stech tisíců řádků (kolikrát stačí i řádově míň!) postavené na ball-of-mud™ architektuře je příšerný, frustrující pocit. Zevnitř se tento zničující strach logicky projeví fatálním zpomalením výkonnosti týmu (kromě přidávání funkcí taková situace samozřejmě neumožňuje ani spolehlivý refactoring) a navenek postupným vymizením inovací a nestabilitou. Když už je situace opravdu hodně neúnosná (úroveň zoufalosti manažerů se vyrovná vývojářům), může se stát, že stakeholdeři svolí ke zdánlivě jedinému možnému řešení—tzv. „přepisu od nuly“.

Zní to lákavě: složíme slib čistoty, začneme úplně na zelené louce a už určitě neuděláme ty chyby, co minule. A vůbec, hlavní chyba byla použít monolitické neresponzivní převaděče spojitosti, do nové verze dáme mnohem lepší a tento týden zrovna nejpopulárnější framework pro cloudové funkcionálně-reaktivní agregované artisan minimicroservices on rails a všechno bude krásné a zalité sluncem.

Škoda, že právě automatizované testy součástí takového přepisu většinou nebývají. Pak to dopadá tak, že o dva roky později nyní již legendární verze 2 stále není vydaná (nebo vydaná je, má polovinu funkcí co verze 1, ale zhruba stejně bugů), zákazníci mezitím dávno odešli jinam a jediný měřitelný rozdíl je ve spotřebě psychofarmak napříč týmem. Jedná se o projev dobře známého „syndromu druhého systému” (v extrémních případech i třetího, čtvrtého...), čili tudy cesta nevede. Hlavní změna se totiž musí odehrát v hlavách zúčastněných.

Software musí být soft

Testy jako ochrana proti regresi jsou samozřejmě skvělá věc, ale kupodivu to není jejich hlavní přínos. Ona totiž zdaleka nejúžasnější výhoda toho, co děláme, je nehmotná povaha našich výrobků. Nápověda je už v názvu: aby byl software pro naše zákazníky i uživatele skutečně přínosný, musí být jako plastelína (a ne jako ta ve školce, kdy vám po smíchání všech vždycky vyšla hnědošedá), ohebný, přizpůsobitelný, rychle a jednoduše tvarovatelný. Odlít si verzi 1.0 z betonu a opracovávat ji pak později výhradně sbíječkou postrádá finesu a nakonec i smysl.

Bohužel často nedostatečně akcentovaný, primárně byznysový požadavek na ohebnost a pružnost vede na technické úrovni k nutnosti umět dělat změny spolehlivě a rychle (potřeba je obojí). A tady je jádro pudla (on je to spíš pořádný vlkodav)—jak to tedy zařídit?

We would like to teach you of our lord and savior TDD

TDD, čili „test-driven development”, česky něco jako „to děláte dobře”. Způsob vývoje, který, pokud je správně používán, působí jako živá voda na všechny zúčastněné. Navzdory požehnanému věku této techniky (v měřítku IT času odpovídá zhruba příchodu Cyrila a Metoděje, náhoda?) ovšem kolem ní pořád panuje spousta mýtů, pochybností a nereálných představ.

S vědomím toho, že na lidi, kteří ortodoxní testování praktikují, je zvenčí občas pohlíženo jako na náboženské fanatiky (případně arogantní chytráky), se vám pokusím přiblížit některé ze zkušeností, které jsme za léta používání TDD nashromáždili, a jeho důsledky pro vývojáře, manažery, stakeholdery i uživatele. Upozornění předem: spousta z uvedených tvrzení bude na první pohled totálně postavených na hlavu a spoustu věcí je potřeba si zažít na vlastní kůži. Nicméně, pojďme začít nejčastěji pokládanou otázkou:

Proč?

„Proč bychom se měli zabývat nějakým TDD? Je to neznámá, poměrně radikální technika, nemáme na to čas, beztak to nikdo nepoužívá a tady Franta, co to jednou zkoušel, z toho dostal ošklivou vyrážku.” OK, pojďme hned zkraje zavrhnout všechny nefunkční důvody jako „přišel šéf a řekl, že to máme dělat”, „přišel klient a řekl, že to máme dělat”, „šéf zaplatil drahého konzultanta a ten přišel a řekl, že to máme dělat” a nejnebezpečnější ze všech, „protože to je správná věc” (aneb dláždění cesty do pekla).

Ty pravé důvody jsou mnohem přízemnější, ale zato upřímné, a proto efektivní: jsme líní (lenost je matka inovací) a chceme si usnadnit práci. Nechceme se v práci bát/chceme pracovat v klidu. Chceme dodávat rychleji bez obětování kvality, pořád stejným tempem. Chceme kdykoliv bez obav refaktorovat. Nechceme praktikovat programming by coincidence™ a nechceme každé dva roky přepisovat svůj systém od začátku. A taky chceme využívat všechny další benefity, které TDD přináší jakoby mimochodem… 

Pro uživatele to znamená stabilní, správně fungující a rychlou aplikaci a pro stakeholdery spokojené uživatele. A ještě taková drobnost—tohle všechno razantně snižuje finanční i časové náklady na vývoj.

Nechci slevu zadarmo

To zní všechno báječně, ale zároveň se hned dostáváme k prvnímu kontroverznímu bodu: nemá cenu slibovat pečené holuby do ústních otvorů a zároveň neříct, že všechny uvedené výhody vám přinese pouze správně a důsledně aplikované TDD, zatímco špatně používané TDD skutečně může způsobit značné problémy. Správně aplikovat TDD je těžké, vyžaduje to na začátku velmi radikální změnu myšlení vývojového týmu a posléze dlouhodobé nabírání zkušeností, tudíž napoprvé se vám to pravděpodobně nepovede. To ovšem neznamená, že nemá význam se o to pokoušet! Taktéž udržet skutečně striktní disciplínu tváří v tvář deadlinům a zběsilým požadavkům z různých stran je občas těžké, ale naprosto zásadní je nepolevit.

A když už jsme v tom, pojďme si odbýt i tu druhou nepříjemnou zprávu: TDD je pro úspěch projektu podmínka nutná, nikoliv postačující. TDD je něco jako bezpečnostní pásy v autě—samospasitelné nejsou, ale jezdit bez nich je prostě nerozum. Stejně tak se může stát, že i projekt bez testů do jisté míry uspěje (když není tvárný kód, může být tvárná aspoň definice úspěchu), nebo že projekt s testy potopí jiné faktory, ale pokud lze něco udělat pro (v tomhle případě zásadní) zvýšení šancí na úspěch, je prostě hloupé a téměř až neprofesionální to vynechat.

Zpátky ke kořenům

Zajímavé je postavení TDD z hlediska historie dnes tolik populárních (tj. zmocnili se jich konzultanti a totálně vyrabovali původní principy) agilních metodik vývoje.

Spousta principů tzv. extrémního programování, dědečka všeho dnešního agilna, je dnes všeobecně přijímána—coding standard, kolektivní vlastnictví kódu, kontinuální integrace i deployment, refactoring, akceptační testy, scrum, párové programování… Jenom to TDD se pořád vidí poměrně málo—a je to škoda. Přitom jak říká jeden z otců XP, Kent Beck: „Pokud je nějaká technika, která je srdcem extrémního programování, je to unit testing.” A na ten i další druhy testů se prakticky podíváme příště.

Jiří Hutárek