Richard Šerý
5.3.2012

Implementační fiasko ve čtyřech dějstvích



Zažili jste při vývoji softwaru nějaký ten „epic fail“? To se jistě rádi pobavíte na cizí účet. Následující řádky budou o tom, jak se posloupností logických kroků a racionálních rozhodnutí dopracovat k neúspěchu. Podotýkám že osoby vystupující v tomto příspěvku jsou čistě smyšlené 🙂 

Dějství první: Plánujeme

User story byla prostá: Umělec nabízí svým fanouškům odměny za to, že přispějí na realizaci jeho projektu. Čím vyšší příspěvek, tím lepší odměny. Měli jsme vyvinout uživatelské rozhraní, které umožní umělci zadat jednotlivé odměny do systému, který je pak zobrazí fanouškům. Dle hesla “dohnat a předehnat” jsme se rozhodli udělat více než konkurence: tam kde si jiní vystačili s prostým seznamem odměn, máme dva objekty: samotnou odměnu (název a popis), která ovšem nemá cenovku, a balíček, který má cenovku (ale chybí mu název) a obsahuje jednu či více odměn.

Co nás vedlo k takovému zjevnému nesmyslu? Alibismus, v podobě klasické věty „byznys to tak chce“. Věta, která vede ke zkáze, zní „Je to asi nesmysl, ale technicky to není nic složitého, tak to uděláme“. Tento způsob uvažování vede vždy ke katastrofě. Jestliže byznys nedokáže o nezbytnosti něčeho přesvědčit vývojáře, jak o tom chce přesvědčit zákazníky? Krutou zbraní na straně byznysu je psychologický tlak na efektivitu v podobě osvědčené věty „už o tom kecáme tak dlouho, že za tu dobu byste to měli naprogramované“. To je podpásovka a třeba v tomto konkrétním případě by pár hodin analýzy a diskusí navíc možná ušetřilo stovky hodin vývoje. Rozhodnutí nakonec opravdu vedlo k obrovskému množství problémů, neboť složitější struktura je obtížnější na pochopení a tím i na ovládání. Na strukturu typu “n x n” nelze použít žádný z osvědčených vzorů UI a ani architektura serverové části nám implementaci neusnadnila. Navíc jsou odměny lokalizované a odměny i balíčky mají stav (schvaluje je moderátor serveru, již schválené odměny a balíčky nelze nadále editovat). Poučení: Jestliže nevidíte jasnou konkurenční výhodu, udělejte méně než konkurence. Pokud nějaká vlastnost vypadá jako nezbytná, najděte způsob, jak se bez ní obejít, a teprve až ho budete znát, rozhodněte se pro nebo proti.

Dějství druhé: Navrhujeme architekturu

Rozhodovali jsme se mezi dvěma variantami řešení. První varianta předpokládala, že odměny a balíčky odměn se budou spravovat samostatně. Tvůrce si nejdříve nadefinuje, jaké nabízí odměny, a pak je v další obrazovce seskupí do balíčků a dá jim cenovky. Druhá varianta typu “všechno v jednom” předpokládala, že tvůrce vytvoří balíček, a ten bude rovnou plnit odměnami, které si hned na místě vytvoří. Nejdříve jsme se pustili do první varianty, která vypadala jednodušší. Brzy jsme se však dostali do potíží a navíc se ukázalo, že řešení má vážné vady v oblasti použitelnosti. Uživatel musel stále přecházet z jedné obrazovky do druhé, nechápal co je balíček odměn ani proč odměna nemá cenovku atd.

 



Prohlásili jsme tedy koncept za neúspěšný a pustili se do druhé varianty. Ta kupodivu docela fungovala, ale občas se tam děly prapodivné věci. Považovali jsme je za drobné potíže, které bude snadné odladit, řešení však už obsahovalo skrytý technologický dluh a navíc nebylo tak docela kompatibilní s architekturou nižších vrstev aplikace. Oprava jednoho problému obvykle odhalila další potíže, práce se táhly zdánlivě do nekonečna.

Poučení: Jestliže všechna řešení, která se nabízí, jsou špatná, nezapomeňte hledat chybu v zadání. Zpochybněte cíle. Snažte se najít to podstatné a ostatního se zbavit. Hledejte taková řešení, která jsou v souladu s dostupnou technologií, neútočte hlavou proti zdi. Proces plánování je bezpochyby nutný a užitečný, hotový plán je však přítěž, která svazuje vaše myšlení. Zbavte se sentimentality a zahoďte plán, když jeho realizace začne váznout. Důležité je dosáhnout cíle, nikoli držet se plánu.

Dějství třetí: Programujeme

Znáte ty části kódu, které sice fungují, ale nikdo neví jak? Pravděpodobně je napsal programátor s pragmatickým přístupem “zbouchám to aby to bylo” a tím vám zadělal na problémy v budoucnu. Jistá dávka pragmatismu je samozřejmě nezbytná, v podstatě ale jde o škodlivý přístup, který do projektu vnáší zbytečná rizika a zvětšuje technologický dluh. Čím větší projekt, tím důležitější je psát kód přehledný a transparentní a vyhýbat se zkratkovitým řešením. Náš kód od začátku trpěl neduhem pragmatického přístupu. Programátor sestavil controller tak, že sice fungoval, ale dalo opravdu hodně přemýšlení pochopit, jak je to možné. Kodér pak nad tím sestavil javascriptovou aplikaci, jejíž kód byl v podstatě v pořádku, ale měla naprosto tragickou strukturu. Názvy proměnných nedávaly smysl, parametry funkcí a metod se jmenovaly a fungovaly pokaždé jinak. Například pod názvem “id” se někdy skrývalo skutečné databázové id, jindy ale pořadové číslo položky v seznamu a občas i něco úplně jiného. Na nečitenosti kódu se také podepsalo časté používání různých zájmen, hlavně klíčového slova “this”, v kódu.

Neštěstí by asi nebylo tak velké, kdyby si někdo včas všimnul, co se děje. Ale celý tým byl tou dobou pod enormním tlakem, protože projekt se blížil dokončení a kvůli špatně nastavenému rozsahu “hořel” na mnoha místech. Proto tuto funkcionalitu programovali junioři bez jakéhokoli dohledu (“není čas dělat code review”). Poučení: Kód, který je pochopitelný a čitelný, ale nefunguje, můžete snadno spravit. Kód, který funguje, ale je nepochopitelný, se může kdykoli rozbít a neuděláte s ním nic. Nejlepší forma boje proti “pragmatickému přístupu” jsou pravidelné code reviews, které by měl vždy provádět vývojář-senior. Zdánlivě jde o ztrátu času, ale pečlivou kontrolou před každým commitem zabráníte mnohem větším nákladům a zdržením v budoucnu.

Dějství čtvrté: Refactoring

Když se po několika sprintech ukázalo, že vývoj definitivně uváznul, sáhli jsme k nepopulárnímu opatření: refactoringu. Refactoring byl velmi bolestný a nakonec trval přibližně dvakrát déle, než jsme původně odhadovali. Ukázalo se, že hlavní zdroj problémů byl špatně čitelný kód. Většina práce tedy spočívala v přejmenování všech proměnných, funkcí, objektů a metod tak, aby názvy odpovídaly projektovému slovníku. Druhý důležitý krok spočíval v novém rozdělení existujícího kódu do logicky pojmenovaných funkcí, s jasně definovaným rozhraním. Přibylo tak velké množství funkcí, které však byly jednoduché a jednoúčelové, což se později ukázalo jako výhoda.

Jakmile začalo být fungování aplikace zřejmé i z kódu, ukázaly se skryté problémy a zjistili jsme, že některé funkce zcela chybí. Co bylo horší, zjistili jsme také, že stávající řešení nelze správně propojit s naším validačním frameworkem a že je nutné celý front end přepracovat. Naštěstí, vyčištěná struktura umožnila kompletní přepracování celého řešení během jediného sprintu. Poučení: Je opravdu důležité, jak pojmenujete svoje proměnné. Vytvořte si projektový slovník a přísně ho dodržujte, nejen v běžné řeči a v dokumentaci, ale i v názvech objektů, vlastností a metod, v pojmenování tříd a id v HTML kódu, v pojmenování funkcí v JavaScriptu, v názvech souborů a pojmenování sloupců v databázi… Dbejte na čitelnost názvů, nevytvářejte zbytečně různé zkratky. Pište kód tak, aby ho přečetlo i malé děcko (má-li samozřejmě příslušné vývojářské certifikace). Máte-li se rozhodnout mezi elegantním, výkonným kódem a kódem, který je čitelný, zvolte čitelný kód.

Dějství páté: Bilancujeme

Po bitvě je každý generál. I my, když se podíváme zpět, nechápeme jak jsme mohli být tak tupí, akceptovat podivné zadání a snažit se ho implementovat i přes jeho zjevné nedostatky. U některých věcí je jasné, že jseme udělali chybu, ale už vůbec není jasné, jak se jí příště vyhnout: Porušili jsme pravidlo Ockhamovy břitvy. Pravidlo zní “Pluralitas non est ponenda sine necessitate.” což většina vývojářů zná spíše pod zkratkou KISS (keep it simple stupid). Máme sice dobrou výmluvu – zadavatel na tom trval – nicméně i tak je to jenom výmluva. Náš postoj v této otázce nebyl tak pevný, abychom trvali na zjednodušení zadání i za cenu vážného konfliktu se zadavatelem, a to se obrátilo proti nám. Tohle je problém, na který zatím neznám jasné řešení – má vývojář vystupovat jako despotický egomaniak, který šikanuje zadavatele “pro jeho vlastní dobro”, nebo raději bez odporu realizovat nesmyslné vize zadavatele a po nevyhnutelném neúspěchu být označován za neschopného packala? Existuje nějaká třetí cesta? Uvažovali jsme od začátku příliš pragmaticky. Pragmatický vývoj s sebou přináší technologický dluh. Jestliže technologický dluh vznikne na konci projektu, je to v pořádku – vývoj pravděpodobně nebude pokračovat, takže ho nebude třeba splatit. Pokud ale vznikne hned na začátku, zaplatí vývojový tým všechno i s úroky. Proto je na začátku projektu nutné vyvíjet toho co nejméně, co nejčistším způsobem a nebát se velkých refactoringů. Později tyhle věci už budou mnohem dražší. Problém je, že v každém týmu se najde nejméně jeden fanoušek “pragmatického přístupu” a že v krátkém časovém horizontu tento přístup skutečně přináší oslňující výsledky. Bohužel v dlouhodobém horizontu zruinuje jak projekt tak i vztah se zákazníkem. Ani tady nemám jasný recept, jak tento problém řešit. Vize rychlých, snadných řešení je prostě příliš lákavá a kdo je zpochybní, je nevyhnutelně v roli neschopného škarohlída. Nenašli jsme včas odvahu zahodit rozdělanou práci. Když zazní věta “teď už jsme do toho investovali příliš, než abychom to zahodili a celé předělali”, je třeba začít hodně přemýšlet. Pokud tato věta zazní o čtrnáct dnů později a týká se stejného problému, je to jasné – přišel čas na bolestivý řez. Opět je výhoda, pokud vývojář je ochoten udělat ze sebe exemplární příklad arogantního tvrdohlavého idiota a říci kategorické “ne” dalšímu vývoji. Pokračování může být v podstatě dvojí, buď vyletí z projektu nebo prosadí refactoring. Možná tím nezachrání projekt, ale určitě tím ušetří svoje nervy. Jak skončit v pozitivním duchu? Poučili jsme se z neúspěchu? Silně o tom pochybuji, tahle rozhodnutí jsou vždy těžká a nepopulární. Ale projekt jsme dokončili a spustili, takže vlastně nakonec všechno dobře dopadlo.

Vaše emailová adresa nebude zveřejněna

Komentáře

Děkujeme za váš komentář
Další
  • Tom

    Ahoj díky za výborný článek. S podobným přístupem jsem se také již setkal. Tom

  • emik

    "Jestliže všechna řešení, která se nabízí, jsou špatná, nezapomeňte hledat chybu v zadání." - to si snad vyvěsím na zeď. Zrovna dneska jsem se vracel. Ještě přidejte moji starou slabost: Než začneš programovat, prašti se přes pazoury, na nic nesahej a jenom piš nápady. Další den si to celé zgruntu znova nakresli/napiš a pak teprve začni programovat. Ušetříš čas.

  • emik: Pořádně se do problému ponořit, pak se na to vyspat a pak teprve začít s realizací, to je dobrá metoda. Ve spánku mozek funguje trochu jinak a "schroustá" i věci, na které by jinak člověk nepřišel.

  • Radek

    Výborný článek ... díky :-)

  • Možná bych mohl připojit svůj pohled na věc z velké dálky managementu realizace projektů. Cílem bylo napsat funkčnost spravující dvě jednoduché entity. Na zelené louce. Pouze s interním zákazníkem, takže zadání se mohlo libovolně měnit. A výsledek? Kýbl hnoje, co trval napsat asi 10x déle než musel :)

  • Skvělý článek! Poznávám známé prvky v každé z kapitol a jsem rád, že to někdo tak hezky pečlivě zformuloval. Myšlenka "validace datového modelu návrhem GUI" mi přijde velmi praktická.

  • benzin

    OT: V cem delate ty prototipy GUI? Nebo to nejsou prototipy?

  • Prototypy GUI dělám v Balsamiq Mockups. Šikovný program, časem o něm něco napíšu.

  • plan-9

    zkusil jsem to webove demo balsamiq mockups a fakt je to pekne :-)

  • Výborný článek, díky! Zkušenost je v tom, najít chyby a nesmyslené požadavky v co nejrannější fázi vývojového procesu. Balsamiq Mockups vypadá dobře.

    1. Což o to, najít chybu není až takový problém, mnohem těžší (aspoň pro mě) je přesvědčit zákazníka, že je to opravdu chyba. Přesně jak píše Pavel - při pohledu "z dálky" to vypadá strašně jednoduše - ďábel se skrývá v detailech. Argumenty typu "dělám to 15 let, takže prostě vím že je to chyba" nefungují. Občas funguje objasnit detaily, ale to strašně trvá, na konci má zákazník hlavu jako balón a správné rozhodnutí stejně udělat nedokáže, protože správné rozhodnutí obvykle bolí.