pátek, prosince 07, 2007

Not so Test Driven...

Tuhle jsem tu psal o tom, jak mě BVer uvrtal do unit testování, a věcí okolo. Dokonce jsem na sobě zkoušel praktikovat i Test Driven Development, a nějak bych rád shrnul, co jsem zjistil.

Především chci říct, že když jsem báječný svět unit-testů objevil, říkal jsem si, jak jsem asi tak tisíc let za opicemi, a že tohle přeci musí používat každý člověk s trochou sebeúcty. Myšlenka testovat kód po malých částech ještě před tím, než zapomenete co má přesně dělat, nebo dokonce zjistit co a jak má dělat tím, že napíšete testy je tak skvělá a samozřejmá, že jsem byl zklamán, že mě nenapadla samotného.

Jaké bylo moje rozčarování, když jsem zjistil, že testování na úrovní nějakých malých komponent není vůbec samozřejmé, a že dokonce velká část lidí, kteří se živí programováním se k němu staví negativně, nebo dokonce odmítavě, a celkově v něm nevidí žádný užitek. Zkoušel jsem několika lidem několikrát opatrně vysvětlit, že čím dřív na chybu přijdou, tím dřív a rychleji ji odstraní, a i když unit testování není samospasitelné, že je to skvělá věc, a že by se jí měli věnovat.

Dokonce jsem i byl skoro úspěšný, když jsem jednoho (teď už bývalého kolegu) přesvědčil, aby si pár testů napsal. Čekal jsem, jak za mnou přiběhne s velkou krabicí belgických bonbónů, bude mi děkovně třást rukama a radostně poskakovat a povykovat, o kolik rychleji teď programuje a jak se kvalita jeho práce zvýšila a tak dále a tak podobně. Místo toho asi po třiceti minutách přišel s velmi správnou otázkou: "No a co mám jako dělat s tou databází?" I neváhal jsem, a začal ho zasvěcovat do tajů mock objektů, které okopírují rozhraní takové databáze, ale nebudou ve skutečnosti dělat nic jiného, než že na předem připravené otázky dají předem připravené odpovědi, načež zkontrolují, zda se jeho kód chová správně, a jeho kód zjistí jestli umí správně reagovat na divné stavy, do kterých se taková databáze může dostat. Čím déle jsem hovořil, tím víc zíval, až nakonec odešel, a o testování jsem od té doby spolu nemluvili.

Nerozuměl jsem tomu, protože napsat si mock-objekt na sériový port (ten z .NET) pro mě bylo opravdu zábavné, i když mi to, pravda, nějakou tu hodinku trvalo, a fakt, že jsem pak mohl pěkně ozkoušet co udělá celé komunikační rozhraní, které jsem tehdy psal, když místo očekávané zprávy přijde nějaká úplně jiná, mi pomohlo zkrátit ladění na pár desítek minut. Ještě méně jsem rozuměl odporu některých lidí, kteří se zabývají vývojem embedded aplikací, zvlášť když neměli k dispozici pořádný debugger.

Samozřejmě, že testování není zadarmo. Psát testy je někdy vážně nuda (třeba set/get metody s trochou logiky), někdy je to vyloženě masochismus (jednou jsem zkoušel, kolik úsilí by mě stálo dosáhnout 100% pokrytí kódu testy a vážně to nestálo za to, protože některé obzvláště vypečené chybové stavy je těžké vyvolat bez toho, abyste neomockovali půl operačního systému), nicméně celkově se rozumná míra testování vyplatí.

Projekt na kterém teď pracuji je poměrně agresivně naplánován, a popravdě, když jsem padesát minut psal mock na třídu zapisující do registrů, říkal jsem si, jestli to stojí za to. Nakonec se ukázalo že ano, protože jsem pak asi za deset minut odladil kód, který ten zapisovač používal, přičemž jsem odhalil asi pět velmi vypečených chyb, které by mě jinak stály spoustu ladění (určitě nejméně padesát minut, protože než bych na ně přišel, dávno bych zapomněl co jsem vlastně původně chtěl, aby kód dělal).

Rovněž jsem nabyl nezvratného přesvědčení, že i když TDD není pro mě (prostě nedokážu psát testy nasucho dopředu -- potřebuji alespoň nějaký kód, který pak třeba celý přepíšu, ale který mi dá vizuální představu jak bude celá věc fungovat a interagovat s okolím), jeho alespoň podvědomé používání vede k psaní lepších programů, které jsou lépe rozparcelovány, méně navzájem provázány, snáze udržovatelné, jednodušeji rozšiřitelné a tak dále. Myslím tím takové ty věci jako předávání objektů konstruktory, vyhazovaní výjimek, rozumné použití dědičnosti, využívání interfaců (interface nebo čistě abstraktní třída je grunt -- bez interfaců nikdy nemůžete vyměnit jeden objekt za druhý, resp. skutečný za mock) a podobné věci.

Chtěl jsem říct asi toto: jsem daleko od nejlepšího žáka Martina Fowlera, ale i když mám někdy pocit, že bych se měl na testování vykašlat, a raději smolit produkční kód, za který si zákazníci platí, vždycky se nakonec ukáže, že kdo testuje, ten vyhraje. A proto (spolu s klasikem) volám: Lidé, testujte!