Stabilní a vratké řešení

Na každou otázku existuje jednoduchá, snadno pochopitelná, nesprávná odpověď.
2. Murphyho zákon

Asi znáte ten pocit, kdy programujete a tušíte jak by ten kód měl správně vypadat. Chvíli třeba i vzdorujete, ale něco vás pořád tlačí do toho správného řešení. Obvykle vyplave na povrch nějaký problém a vy si říkáte: „Jó, kdybych já to tenkrát udělal dobře. To bych tenhle problém neměl.“ Ještě to třeba nějak ošulíte a ono to za nějakou dobu vyhřezne jinde. Nakonec svoji lenost přemůžete a uděláte to tak, jak to mělo být od začátku. Jste odměněni úžasným zážitkem. Máte před sebou jednoduché a elegantní řešení problému. Cítíte že je to dobře, že na tom není moc co zlepšovat. Zase jste jednou něco udělali dobře. Je to úžasný pocit.

Takovému výsledku říkám stabilní řešení. Nejen že je to očividně dobře, ale stejně jako kuličku táhne gravitace na dno důlku, tak i vás k tomuto řešení něco táhne. Stačí jen dávat pozor. Včera jsem to v opilosti někomu vykládal a přišlo mi to úplně mystické. Takhle za střízliva to není ono, ale moc daleko to k tomu nemá. Je to asi něco podobného, jako když fyzici hledají elegantní matematické vyjádření fyzikálních zákonů. Když je zákon ošklivý, tak mu nevěří. Příroda ale přeci nemá důvod generovat hezké rovnice. Stejně tak nemají problémy v programování důvod generovat hezký kód. Ale přesto to tak často je.

No jo, jenže pak tu máme další množinu problémů, která je naprosto opačná. U ní vybíráte jen ze špatných řešení. Ať děláte co děláte víte, že to bude tak či tak špatně. Volíte mezi jednoduchým a rychlým, mezi testovatelným a kompaktním, mezi robustním a čitelným. Když takový kód někomu ukazujete, tak se trochu stydíte. Víte, že to je špatně, ale alternativy jsou ještě horší. Je to takové vratké. Stačí malá změna požadavků a musíte to celé předělat. Stačí další zádrhel a předěláváte to znovu. Prostě ne a ne najít to správné východisko.

Zajímalo by mě čím to je. Je to tím, že to správné řešení někde je a já ho jen nevidím? Nebo pro daný problém hezké řešení neexistuje? Nebo je špatně navrženo všechno kolem, takže mi tam to případné elegantní řešení nepasuje? Nebo je to nevyzrálostí nástrojů? Třeba je špatně programovací jazyk, v kterém se to snažím vyřešit. Jako kdybych se snažil popsat fyzikální zákony a neuměl bych násobit. Pak by také některé rovnice vypadaly neelegantně a hloupě. Nevím. Asi jsem jako ti fyzici, myslím si, že by ke každému problému mělo být elegantní řešení. Tak proč se mi ho sakra tak často nedaří najít?

Pokud jde kód špatně otestovat, je špatně navržený.

Píšete unit testy? Pokud ano, přemýšleli jste nad tím co vám přináší? Já ano a čím dál tím víc začínám zastávat názor, že unit testy tu nejsou od toho, aby hledaly chyby v kódu.

Účelem unit testů je totiž hledání chyb v návrhu. Je to takový rychlý detektor. Zkusíte napsat unit test na kus kódu a když to jde špatně, tak je ten kód špatně navržený. Tečka. Platí totiž jednoduché pravidlo:

Pokud jde kód špatně otestovat, je špatně navržený.

Nevím jak bych vám to dokázal, ale když se nad tím zamyslíte, tak je to evidentní. Když mám stořádkovou metodu, tak přeci nemůžu napsat jednoduchý test, který pořádně otestuje všech sto řádků. Pokud mám třídu, která dělá několik věcí současně, tak ani nebudu vědět, kde s testováním začít. Na a když mám třídu, která má hromadu závislostí, tak se zblázním z mockování.

Takže pokud vám připadá, že psaní a udržování unit testů je hromada ošklivé práce, tak není chyba v testech, ale v kódu, který se snažíte testovat.

Jediné co vám mohu doporučit je TDD. Když začnu psát testy před kódem, tak dojde k takovému kouzlu. Nebál bych se použít i slovo zázrak. I patlal jako já najednou začne psát jasný a jednoduchý kód. Když procházím svůj starší kód, na první pohled poznám, který kód jsem psal pomocí TDD a který klasicky. Když mám testy hotové před tím, než začnu kazit kód, tak mě udrží v mezích a nenechají mě překomplikovat návrh a psát špagetykód. Když si nechávám testy na potom, tak je ten kód prostě mnohem ošklivější. A to je podle mě největší přínos unit testů. Žádné hledání chyb, ale nástroj, který vás dovede ke správnému návrhu.

Takže, pokud už to tedy dávno neděláte, tak opravdu zkuste psát testy před kódem. Je to kouzlo, které když nezkusíte tak o hodně přijdete.

Poznámka: Tento blog jsem napsal proto, že jsem hledal něco podobného v češtině a nic nenašel. Přišlo mi to škoda. Jsou i lidé, kteří tvrdí, že TDD je největší změna v našem odvětví za posledních deset let. Nebo tak nějak (nedaří se mi najít zdroj). Jinak pěkný článek o tom k čemu jsou unit testy najdete tady.

Při hledání podkladů, jsem narazil na tento svůj zápisek a hlavě dokument z něj odlinkovaný, na který jsem úplně zapomněl a který mě úžasně pobavil. Doporučuji.

Soustřeďme se na jednu věc

Dneska mi (znovu) došla jedna věc. Tím jak se snažím dělat spoustu věcí najednou, udělám toho mnohem míň. Teď nemluvím o moderní roztěkanosti, o tom, že potřebuji zkontrolovat zprávy na internetu několikrát do hodiny.

Ne. Mluvím o tom, že když něco děláme, neumíme si vybrat co to vlastně bude a proč to děláme. Mám několik příkladů. Dnes jsem se třeba pustil do opravy chyby a zároveň refaktoringu. Nakonec jsem se v tom úžasně zamotal. Proč? Protože jsem se snažil splnit dva odlišné cíle najednou. Naštěstí jsem si to uvědomil už po hodině bloudění, vrátil se na začátek a jen opravil tu chybu. To bylo relativně jednoduché. Refaktoring nás bohužel ještě čeká, ale až ho budeme dělat, nebudeme si muset lámat hlavu s nějakou chybou.

Další příklad je podobný. Měli jsme produkční problém. Na něj jsme nasadili záplatu, která jakž takž drží. Ale protože jsme pečliví, vyrobili jsme si další task, v kterém to chceme opravit pořádně. No jo, ale když už to děláme, tak proč k tomu něco nepřidat, že? Třeba docela velikou architektonickou změnu.

Proč mi to vadí? Vždyť je to jedno, ne? Není. Dokud nemáme jasno v tom proč něco děláme, tak si hrozně komplikujeme život. Je snadné se ztratit v tom, jestli řešíme akutní problém, který musí být vyřešen co nejdřív nebo jestli předěláváme infrastrukturu, což bude potřeba za pár měsíců. Je nemožné určit prioritu. Pokud by to byla oprava produkčního průšvihu, tak by to mělo prioritu velikou. Pokud je to „jen“ příprava na budoucnost, tak by to mohlo třeba chvíli počkat. Pokud to má velkou prioritu, tak si zbytečně přiděláváme práci u něčeho, co musí být hotové rychle. Pokud to může počkat, tak ať to sakra počká.

Zkuste se sami zamyslet, kdy jste naposled zaslechli něco takového: „Jasně, děláme X Ale když už jsme v tom, tak bychom mohli udělat i Y“. Podobným nápadům se snažte zabránit všemi dostupnými prostředky. Jak? Nejjednodušší metoda je to rozfázovat. Udělat nejdřív X a pak Y.

Lidé se zkrátka nedovedou soustředit na víc věcí najednou. Když se snažím dělat X i Y zároveň, tak hrozí že neudělám ani jedno. Navíc se ochuzuji o ten krasný pocit z odškrtnutí dalšího hotového úkolu. Zkrátka, když se snažím dělat moc věcí najednou, tak se to vleče, lidé jsou zmatení, žena s vámi nemluví a má to spoustu dalších negativních důsledků.

Zamysleme se ještě, jaká je vlastně motivace, pro to dělat víc věcí najednou? U mě je to obvykle takový ten pocit, že když už do toho vrtám, tak ať to stojí za to. Jako kdyby rozvrtání kódu byla nějaká výjimečná událost. Občas se také přistihnu při naivní myšlence, že když budu dělat několik věcí najednou, tak to bude rychlejší, než kdybych je dělal postupně. Přiznám se, že netuším, kde se ve mně takové blbosti berou. No a často je to asi také snaha propašovat do kódu to zatrolené Y, které se stále odkládá, protože má nízkou prioritu. Slyšel jsem i o firmách, které mají tak zbytnělé procesy, že je pro programátory lehčí udělat víc věcí najednou za jedno papírování. Ale to snad není váš případ.

Jsou i legitimní důvody. Třeba pokud máte nákladné testování. Pak se může vyplatit najednou testovat celou rozvrtanou oblast. Ale i to je diskutabilní. Testování jedné přímočaré opravy chyby je obvykle málo náročné. Takže ten refaktoring, který bychom k tomu chtěli přibalit, můžeme otestovat stejně dobře i zvlášť. Navíc se testeři nebudou divit, jak to že se opravou chyby rozbilo tolik věcí. Těžko se vysvětluje, že jsme tam přibalili refaktoring jako bonus. Z takového překvapení má radost málokdo.

Takže si opakujte po agilistech: „Rozsekejte si práci na co nejmenší ještě smysluplné celky a dělejte je postupně.“ Ohromně si tím ulehčíte život. No a já si jdu připravovat argumenty, jak Dagiho přesvědčím, že není dobrý nápad komponentizovat aplikaci a zároveň se učit nový programovací model. Oboje samozřejmě najednou. Však víte, když už do toho vrtáme…