neděle 30. ledna 2022

Starý junior, mladý senior

Seniorita je pojem z oblasti společenských vztahů. Vyjadřuje nadřazenost osoby nebo skupiny na základě vyššího věku nebo délky zastávání určité pozice. Takže senior je buď člověk staršího věku nebo pracující déle na nějaké pozici. Junior je autonymum.

Tímto příspěvkem se pokusím odpovědět na tyto komplexní otázky:

  • Jak je definována "kvalita vývojáře"?
  • Jak vlastně délka profesní kariéry souvisí s vlastní kvalitou vývojáře?

Dlouho jsem přemýšlel nad tím, jak téma uchopit. Nakonec jsem dal dohromady několik vstupů:

  • moje pozorování kolegů a toho, co se mi na jejich profesním chování líbí,
  • reakce lidí na můj anketní tweet,
  • seznam znalostí a dovedností, které považuji za důležité.

A výstupem se stal Honza.

Honza je kompendiem zkušeností a profesní efektivity. Je to kombinace mnoha profesních rolí - architekt, analytik, programátor, manažer, projekťák, atd. A také je to někdo, kdo reálně neexistuje. Je to ideál vývojáře, na kterém si zkusíme popsat, co všechno může mít na naši práci pozitivní vliv.

Honzův profil by nám tedy mohl pomoci s odpovědí na první otázku. Na tu druhou si odpovíme ke konci příspěvku.

Honza a práce

Honza je pracovitý a vytrvalý. To je základ.

Nevyhýbá se úkolům. Samozřejmě chápe, že práce bude vždy více než je dostupného času. Snaží se proto správně pracovat s prioritami. Rozumí, že každá záležitost obnáší investici ve formě času a generuje určitou hodnotu. Nenechá se odlákat od aktuálního prioritního úkolu pouze tím, že se právě objevil méně prioritní ale zato atraktivnější úkol.

Umí dotahovat úkoly ke zdárnému konci. Nenechá se odradit překážkami. Je orientovaný na výsledek. Ne však na úkor kvality. Má soubor profesních zásad, které dodržuje i pod projektovým tlakem. Na druhou stranu ví, kdy je z nich možné a vhodné mírně ustoupit a jaké to bude mít důsledky. Ty je potřeba správně komunikovat.

Má vybudované návyky, které mu pomáhají dělat práci efektivně. Umí si den rozdělit do delších bloků hluboké práce bez vyrušování. Umí si organizovat inbox a backlog přes všechny své profesní role. Reaguje na pracovní požadavky podle jejich důležitosti. Umí říkat NE.

Honza a kolegové

S Honzou je příjemné pracovat.

Čím komplexnější projekt, tím větší tým a tím důležitější chemie mezi lidmi. Honza si důležitost vztahů uvědomuje. Je empatický. Chápe rozdíly v typologiích osobností. Dokáže být asertivní.

Nezdůrazňuje svoji senioritu v týmu. Respekt si buduje svojí profesionalitou a tím, že respektuje ostatní. Povzbuzuje své kolegy k samostatnosti a k tomu nebát se zkoušet nové věci a hledat optimálnější řešení. Spoluvytváří pozitivní atmosféru, ve které se všem dobře pracuje. Svůj názor se snaží prosadit věcným způsobem.

Honza je pokorný. Nemá ve zvyku neustále hledat problémy pouze u druhých, když se něco nepodaří. Začně tím, že si vyhodnotí svůj podíl na problému jako první. Chápe, že i on dělal, dělá a bude dělat chyby. Nevymlouvá se, když se mu něco nepovede. Vysvětlí okolnosti, které vedly k jeho chybě a upraví své pracovní postupy a chování tak, aby se stejná chyba v budoucnu neopakovala.

Snaží se konfliktům předcházet a pokud už nastanou, tak je zmírňovat. Pokud něco nefunguje, neuchyluje se k osobní kritice kolegů. Je věcný. Nepomlouvá. Snaží se aktivně hledat příčiny problémů a ty pak konstruktivně řešit. Dokáže konstruktivně přijmout zpětnou vazbu na svoji práci. Pokud sám zpětnou vazbu poskytuje, pak nekonfliktním způsobem. Kolegové tak nemají pocit, že jsou kritizováni, ale že jsou podporováni k lepším výsledkům.

Honza zná základní principy koučinku a umí je v praxi použít. Pomáhá tím kolegům v uvědomění si jejich aktuální profesní situace a toho, kam by se mohli posunout a jakým způsobem. Takto přirozeně tým rozvíjí a pomáhá jeho členy motivovat.

Mluví otevřeně a transparentně. Buduje důvěryhodné prostředí, nemanipuluje s informacemi, poskytuje je všem konzistentním způsobem. Kolegy nezdržuje přílišným tlacháním na poradách.

Honza jako architekt řešení

Honza už chápe, že zákazník na začátku projektu často přesně neví co chce. Honzu netrápí, že nemá často přesné zadání. Chápe to jako příležitost pomáhat zákazníkovi už od začátku s hledáním řešení. Co jej občas trápí je, když se po něm chce estimace příliš hrubého zadání. Je si vědom, že taková estimace v ranné fázi projektu je pouze loterie, která se hraje hlavně proto, aby měl zákazník rámcovou představu o nákladnosti projektu. Nesnaží se dodat konkrétní číslo, ale spíše rozpětí optimistického a pesimistického odhadu. Rozloží si problém na menší celky a ty estimuje zvlášť. Umí zákazníkovi vysvětlit rizika takové estimace a obsažené stupně volnosti.

Honza se snaží aktivně porozumět rizikům projektu. Tato rizika srozumitelně popíše, navrhne protiopatření a vykomunikuje je směrem k zákazníkovi. Zkušenost mu velí, že největší rizika vznikají při integraci aplikace s externími systémy a při závislosti na úkolech, které musí zajisti zákazník sám.

Honza má zkušenosti s agilními projekty i vodopádem. Pracoval v režimu Fix-time-fix-price i Time-&-Material. Dokáže je porovnat z různých perspektiv. Preferuje agilní přistup, ale chápe, že každá metodologie je vhodná pro jiný typ projektu. Chápe, že zadavatel má určitý přístup k řešení projektů, který někdy nelze úplně změnit. Nejdříve si tedy nechá vysvětlit problém, který je potřeba řešit a teprve potom navrhuje typ metodiky. Ne obráceně. Umí vyargumentovat vhodnost jednotlivých přístupů a zohlednit připomínky zákazníka.

Honza zná principy Scrumu, Kanbanu, extrémního programování i vodopádu. Je si vědom, že málokdy se na projektu jedná o jednu striktní metodiku. Často dochází k hybridnímu modelu s prvky více metodik současně. Umí v takovém prostředí fungovat. Dokáže poznat, kdy to způsobuje problémy a kdy naopak to projektu prospívá. Uvědomuje si, že získávání zpětné vazby na práci týmu od zákazníka je klíčové pro úspěch projektu v každé metodice.

Honza jako analytik

Honza dobře chápe, že za vznikem dobrého softwarového produktu je obvykle symbióza správného technického řešení a pochopení byznysových potřeb. Aktivně se snaží porozumět byznysové doméně. Chápe, že jednoznačný doménový glosář redukující používání synonym je základem plynylé komunikace a snižuje míru neporozumění v rámci projektového týmu.

Honza umí naslouchat potřebám zákazníka, pomáhat s návrhem řešení a formalizovat požadovanou funkcionalitu ve formě use cases. Rutinně používá UML a kreslí diagramy případů užití, aktivitní diagramy, sekvenční diagramy a další.

Honza je schopen definovat funkcionální epiky a jejich rozpad na user stories. Nepodceňuje správnou formulaci všech tří hlavních částí story. Rozumí důležitosti formy a obsahu akceptačních kritérií, Definition of Ready a Definition of Done.

Když je na projektu nějaká velká neznámá nebo vysoce komplexní část, umí si s tím poradit. Nepřeceňuje význam verbální diskuze. Pozná, kdy je lepší přestat mluvit a udělat první krok k řešení problémů. Raději udělá první krok špatným směrem, než dlouho váhat a neudělat žádný. I pozdější uvědomění si nesprávného postupu je progres.

Honza nepodceňuje důležitost definice nefunkcionálních požadavků. Aktivně se zákazníkem řeší požadavky na zabezpečení, odezvu systému, propustnost, podporované prohlížeče, apod. Je si vědom toho, že právě tyto záležitosti mají často zásadní vliv na architekturu řešení.

Honza jako technický vedoucí týmu

Honza spolu s týmem nastavuje pravidla pro psaní kódu. Společně integrují nástroje pro statickou a dynamickou analýzu. Sdílejí si týmové šablony a code snippety. Snaží se zajistit rozumnou míru standardizace, která práci celého týmu zefektivňuje.

Honza chápe důležitost automatizace CI a CD procesů. Proto trvá na jejich správném nastavení již od začátku vývoje.

Honzovi je jasné, že správně prováděná code review jsou velkým přínosem pro kvalitu výstupu. Zároveň dbá na to, aby způsob komunikace v rámci review byl profesionální a konstruktivní. Chce, aby to byl proces učení a společného hledání lepšího řešení.

Honza si je vědom, že každý softwarový projekt je postupně zatížen technickým dluhem, se kterým se musí pracovat. Zná postupy jak redukovat míru jeho vzniku už ve fázi návrhu. V týmu aktivně používají Boyscout-rule. Zároveň však dokáže poznat, kdy je už další umořování technického dluhu ekonomicky neefektivní.

Komunikuje technické záležitosti srozumitelným způsobem produkťákům a mecenášům projektu tak, aby zajistil adekvátně robustní řešení. Větší refaktoring domluví jako technickou user story naplánovanou s vědomím zákazníka v souvislosti s funkcionální změnou v souvisejím kódu. Dělat refaktoring bez motivace rozšíření stávající funkcionality nebo optimalizace výkonu nepovažuje za opodstaněné.

Honza nabádá kolegy, aby přicházeli s nápady na vhodné nástroje a knihovny, které by práci na projektu vylepšily. Nejdříve si však jejich použití odprototypují a posoudí jejich přínos. Je přiměřeně konzervativní v použití nových věcí. Mnohokrát již dříve zjistil, že vhodnost technologie se nedá posoudit hned, ale spíše později při aplikaci na komplexnější záležitosti. Použití takové neprověřené technologie považuje za riziko a tak s ním i nakládá.

Honza jako programátor

Anatomii vývojového cyklu specifikace-analýza-návrh-implementace-verifikace má Honza stále v podvědomí. Snaží se tyto fáze ve svých postupech logicky oddělit.

Když začíná pracovat na novém úkolu, začne analýzou problému. Pokud problém obsahuje neurčitost, kterou potřebuje vyjasnit, neváhá sáhnout k prototypování. Udělá rychlý prototyp, který mu pomůže pochopit problém a ukáže možné cesty k řešení problému. Prototyp pak zahodí a nepodléhá lákadlu jeho použítí přímo v produkčním kódu.

Součástí Honzovy analýzy je obvykle také rozpad problému do menších celků. Tyto menší celky jsou pak lépe uchopitelné. Veškeré nejasné a problematické části zadání strukturovaně sepíše a prodiskutuje s autorem požadavku.

Ve fázi návrhu si rád pomůže nakreslením některého z UML diagramů. Pro statický pohled na řešení používá komponentový diagram a diagram tříd. Pro dynamický pohled aktivitní, sekvenční nebo stavový.

Někdy mu také pomůže TDD přístup. Jednotkovými testy postupně definuje rozhraní komponenty a iterativně její sémantiku. Snaží se o konzistentní a dostatečně samopopisný názvy testů, které poslouží jako aktuální dokumentace ke komponentám. Ze složitosti zápisu jednotkových testů dostává okamžitě zpětnou vazbu na návrh komponent a jejich složitost.

Honza si bez jednotkových testů nedokáže vývoj představit. Není však radikálním zastáncem 100% pokrytí kódu u komponent, u kterých je přínos jednotkových testů velmi malý oproti nákladům na jejich vytvoření a údržbu.

Při návrhu komponent používá Honza kombinaci různých best practices a návrhových vzorů. Základem jsou pro něho SOLID principy. Bez použití IoC kontejneru a Dependency Injection si už nedovede své projekty ani představit. Má rád volné vazby mezi komponentami, nízká čísla u metrik závislostí a vysokou soudržnost. Díky tomu může psát testy efektivním způsobem.

Pro Honzu bylo přečtení knížky Clean Code důležitým profesním milníkem. Začal přemýšlet nad svým kódem jinak. Zaměřuje se na dobré pojmenování, zkracuje metody, snižuje cyklomatickou složitost, redukuje parametry, více přemýšlí nad ošetřením možných chybových stavů. Obecně se více dívá na kód z pohledu čtenáře než autora. Zásadní důraz klade na dobrou čitelnost a samodokumentovatelnost kódu. Ovládá nejpoužívanější techniky refaktoringu právě pro dosažení lepší struktury a udržovatelnosti kódu.

Integračními testy si ověří funkčnosti přes celý aplikační stack.

Otázky výkonu Honza řeší již při návrhu architektury. Rozumí také výkonostním aspektům frameworkových komponent a vlastního jazyka. Nenechá se však vlákat do pasti dopředné optimalizace při psaní komponent. Tu provádí až poté, co má nejdříve funkční řešení.

Honza se snaží své hlavní softwarové nástroje ovládat pouze z klávesnice bez nutnosti použití myš. Aktivně se učí klávesové zkratky. Píše bez překlepů. Psaní na klávesnici pravidelně trénuje.

Honzovy znalosti jazyků a technologií

Ve svém hlavním programovacím jazyce se cítí velmi komfortně. Na druhou stranu si uvědomuje, že získat hlubokou expertízu v použití hlavních knihoven platformy je běh na dlouhou trať. Aktivně proto hledá možnosti, jak si zvé znalosti rozšířit. Čte si blogy, porovnává různá řešení stejného problému na Stackoverflow, prototypuje alternativy, diskutuje s kolegy.

Honza má rozsáhlé teoretické znalosti v oblasti softwarového inženýrství. Díky nim dokáže rychleji najít optimálnější řešení problému. Ví co hledá a umí si dát věci do souvislostí.

Má zkušenosti s jazyky a technologiemi napříč celým stackem. Dokáže napsat aplikace běžící na serveru, v prohlížeči i na mobilních zařízeních. Díky takto širokému záběru chápe souvislosti a umí navrhnout správně komunikační rozhranní. Rozumí protokolům REST, GraphQL, gRTC i SOAP.

Honza zná principy hlavních cloudových platforem. Umí navrhnout a nakonfigurovat ideální mix cloudových služeb podle potřeb daného projektu. Rozumí Dockeru a Kubernetes.

Jak dlouho je už Honza v oboru?

A odpověď na druhou otázku je ... Nevím.

Dle mého názoru se délka kariéry v IT často přeceňuje. Já sám znám několik relativně mladých vývojářů, kteří mají k Honzovi blíže než jiní, kteří ještě programovali v Turbo Pascalu. Ale rozhodně z toho nemůžeme dělat pravidlo.

Co můžeme z tak komplexního Honzova profilu tedy vyvodit? Dostat se na vysokou úroveň mnoha dovedností vyžaduje spoustu času stráveného praktikováním. To bezesporu. U některých vlastností jsou navíc nutné i životní zkušenosti, které formují především sociální inteligenci.

Důležitou složkou naší osobnosti jsou charakterově volní vlastnosti. Spolehlivost, pracovitost, zásadovost, ... Jejich správné nastavení má zřejmě zásadní vliv na rychlost profesního růstu.

Velký dopad má také to, v jakém prostředí a týmu se vývojář vyvíjel. Při dobrém vedení se může začínající perspektivní vývojář během krátkého období hodně posunout. Proto je zřejmě výhodné, aby byli mladí ve více flexibilním prostředí s variabilnějšími projekty. Samozřejmě za asistence zkušených kolegů.

Zkusme být jako Honza ...

... ale nestresujme se z toho, že takoví nejsme. Pracujme na sobě. Každý úkol je příležitostí se něco nového naučit, zlepšit se, zkusit jiný postup. Odměnou nám bude dobře odvedená práce a spokojenost. A o to přeci jde.

Vox populi

Tady si můžete přečíst, co si o tématu myslí kolegové z Twitteru. Děkuji všem za reakce.

pondělí 24. října 2016

Jednoduchá složitost nebo složitá jednoduchost

Známe to všichni. Kód, který jsme dříve napsali, byl dobře čitelný a lehce upravitelný. Ten samý kód dneska? Nakynuté třídy, dlouhé metody, vysoká komplexita a zvyšující se náklady na požadované změny.

Všude slýcháme, že musíme psát kód jednoduchý, dobře čitelný, s nízkou komplexitou. Dobře, ale co to vlastně v praxi znamená? Zjistil jsem, že my vývojáři si pod "jednoduchostí kódu" často představujeme dost rozdílné věci.

Pojďme se společně podívat na několik řešení stejného problému a přemýšlet nad tím, co si vlastně pod "jednoduchým kódem" představujeme.

Řešíme "problém života"

Jako ukázkový problém nám poslouží hra Game of Life, kterou zpopularizovaly akce typu Coderetreat. Zrovna minulou sobotu byl Global Day of Coderetreat 2016, takže pro mnohé účastníky čerstvá zkušenost.

Hra definuje několik základních pravidel pro výpočet stavu buňky v příští generaci:

  • Any live cell with fewer than two live neighbours dies, as if caused by under-population. (Under-population rule)
  • Any live cell with two or three live neighbours lives on to the next generation. (Survival rule)
  • Any live cell with more than three live neighbours dies, as if by over-population. (Over-population rule)
  • Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. (Reproduction rule)

Výpočet je tedy funkcí aktuálního stavu buňky a počtu jejich živých sousedů. Pravidla nám trochu zatajují situace (Dead,x), kde x in {0,1,2,4,5,6,7,8}. U těch se předpokládá příští stav Dead. Bude pro nás srozumitelnější, když si pro tyto případy zavedeme další "defaultní" pravidlo No-reproduction rule.

Kód je sice v C#, ale to by pro vývojáře ze spřátelených platforem neměl být žádný problém. Jde tady přeci o společné principy čitelnosti, komplexity a OOP.

Testy až na prvním místě

Jak už to u Test-First přístupu bývá, testy nám pomohou lépe pochopit problém a pokrýt celou množinu možných situací. Tento článek ale není o TDD přístupu ani o návrhu struktury testovacích případů. Dovolím si proto zjednodušený zápis finální množiny testů do jednoho parametrického jednotkového testu:

public class NextGenerationStateCalculatorTests
{
    [TestCase(CellState.Live, 0, CellState.Dead, TestName = "Under-population rule: (Live,0) => Dead")]
    [TestCase(CellState.Live, 1, CellState.Dead, TestName = "Under-population rule: (Live,1) => Dead")]
    [TestCase(CellState.Live, 2, CellState.Live, TestName = "Survival rule: (Live,2) => Live")]
    [TestCase(CellState.Live, 3, CellState.Live, TestName = "Survival rule: (Live,3) => Live")]
    [TestCase(CellState.Live, 4, CellState.Dead, TestName = "Over-population rule: (Live,4) => Dead")]
    [TestCase(CellState.Live, 5, CellState.Dead, TestName = "Over-population rule: (Live,5) => Dead")]
    [TestCase(CellState.Live, 6, CellState.Dead, TestName = "Over-population rule: (Live,6) => Dead")]
    [TestCase(CellState.Live, 7, CellState.Dead, TestName = "Over-population rule: (Live,7) => Dead")]
    [TestCase(CellState.Live, 8, CellState.Dead, TestName = "Over-population rule: (Live,8) => Dead")]
    [TestCase(CellState.Dead, 3, CellState.Live, TestName = "Reproduction rule: (Dead,3) => Live")]
    [TestCase(CellState.Dead, 0, CellState.Dead, TestName = "No-reproduction rule: (Dead,0) => Dead")]
    [TestCase(CellState.Dead, 1, CellState.Dead, TestName = "No-reproduction rule: (Dead,1) => Dead")]
    [TestCase(CellState.Dead, 2, CellState.Dead, TestName = "No-reproduction rule: (Dead,2) => Dead")]
    [TestCase(CellState.Dead, 4, CellState.Dead, TestName = "No-reproduction rule: (Dead,4) => Dead")]
    [TestCase(CellState.Dead, 5, CellState.Dead, TestName = "No-reproduction rule: (Dead,5) => Dead")]
    [TestCase(CellState.Dead, 6, CellState.Dead, TestName = "No-reproduction rule: (Dead,6) => Dead")]
    [TestCase(CellState.Dead, 7, CellState.Dead, TestName = "No-reproduction rule: (Dead,7) => Dead")]
    [TestCase(CellState.Dead, 8, CellState.Dead, TestName = "No-reproduction rule: (Dead,8) => Dead")]
    public void Calculate__For_Given_CellState_And_Neighbours__Should_Return_Expected_CellState(CellState cellState, int numberOfLiveNeighbours, CellState expectedNextGenerationCellState)
    {
        var nextGenerationCellState = new NextGenerationStateCalculator().Calculate(cellState, numberOfLiveNeighbours);
 
        Assert.AreEqual(expectedNextGenerationCellState, nextGenerationCellState);
    }
}
 
public enum CellState
{
    Live,
    Dead
}

Ve výsledku tedy máme celkem 2 [součastný stav buňky - Live, Dead] x 9 [počet sousedů 0 .. 8] = 18 testů. Mohli bychom případně udělat rozpad struktury testů podle jednotlivých pravidel. Mohli bychom vylepšit pojmenování. A další. Tím se ale nechci zdržovat. Pojďme řešit implementaci.

A. První verze - ta "nejrychlejší"

Už si nepamatuju, jak jsem na svém prvním Coderetreatu pravidla implementoval já. Často ale vidím, že programátoři napíšou něco takového:

public class NextGenerationStateCalculatorA
{
    public CellState Calculate(CellState cellState, int numberOfLiveNeighbours)
    {
        if (cellState == CellState.Live && (numberOfLiveNeighbours == 2 || numberOfLiveNeighbours == 3)
            || (cellState == CellState.Dead && numberOfLiveNeighbours == 3)) return CellState.Live;
 
        return CellState.Dead;
    }
}

Je to výsledek přístupu "Žij nebo Zemři". Náš pohled na problém je omezen na to, že stačí určit, kdy bude buňka v příští generaci Live. Pro všechny ostatní případy je Dead.

Problémem tohoto přístupu je ignorování narůstající složitosti podmínky pro Live. Případné další pravidlo by při tomto přístupu podmínku ještě více znepřehlednilo. Implementace podmínky také nenese žádnou informaci o tom, jaká pravidla zahrnuje. Není zde žádné mapování kódu na požadavky. Cyklomatická složitost (Cyclomatic Complexity) této implementace je 6. Takže docela dost.

Kód je relativně krátký, ale je snadné jej pochopit a rozšířit? Zkusíme vylepšit expresivitu kódu ...

B. Pomůžeme si pojmenováním proměnných

public class NextGenerationStateCalculatorB
{
    public CellState Calculate(CellState cellState, int numberOfLiveNeighbours)
    {
        var useSurvivalRule = cellState == CellState.Live && (numberOfLiveNeighbours == 2 || numberOfLiveNeighbours == 3);
        var useReproductionRule = cellState == CellState.Dead && numberOfLiveNeighbours == 3;
 
        return useSurvivalRule || useReproductionRule ? CellState.Live : CellState.Dead;
    }
}

V kódu se nám už objevuje terminologie prvních pravidel. Konkrétně Survival a Reproduction. Zavedené lokální proměnné nám tak přidávají do kódu částečnou vazbu na naše zadání. Ostatní pravidla ale v kódu explicitně uvedena nejsou.

C. Strukturujeme kód podle jednotlivých pravidel

public class NextGenerationStateCalculatorC
{
    public CellState Calculate(CellState cellState, int numberOfLiveNeighbours)
    {
        if (cellState == CellState.Live && numberOfLiveNeighbours < 2) return CellState.Dead;
        if (cellState == CellState.Live && (numberOfLiveNeighbours == 2 || numberOfLiveNeighbours == 3)) return CellState.Live;
        if (cellState == CellState.Live && numberOfLiveNeighbours > 3) return CellState.Dead;
        if (cellState == CellState.Dead && numberOfLiveNeighbours == 3) return CellState.Live;
 
        return CellState.Dead;
    }
}

Toto řešení nám sice zvedlo LOC, ale jeho struktura už více kopíruje jednotlivá pravidla. Opět nám však chybí informace o názvu jednotlivých pravidel a CC nám skočila na 10.

D. Extrahujme podmínky pro jednotlivá pravidla

public class NextGenerationStateCalculatorD
{
    public CellState Calculate(CellState cellState, int numberOfLiveNeighbours)
    {
        if (UseUnderPopulationRule(cellState, numberOfLiveNeighbours)) return CellState.Dead;
        if (UseSurviveRule(cellState, numberOfLiveNeighbours)) return CellState.Live;
        if (UseOverPopulationRule(cellState, numberOfLiveNeighbours)) return CellState.Dead;
        if (UseReproductionRule(cellState, numberOfLiveNeighbours)) return CellState.Live;
 
        return CellState.Dead;
    }
 
    private bool UseUnderPopulationRule(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Live && numberOfLiveNeighbours < 2;
    }
 
    private bool UseSurviveRule(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Live && (numberOfLiveNeighbours == 2 || numberOfLiveNeighbours == 3);
    }
 
    private bool UseOverPopulationRule(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Live && numberOfLiveNeighbours > 3;
    }
 
    private bool UseReproductionRule(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Dead && numberOfLiveNeighbours == 3;
    }
}

Extrahovali jsme podmínky pravidel do pojmenovaných privátních metod. Čitelnost se tím trochu zlepšila a snížili jsme CC hlavní metody na 5. Pořád mi ale vadí, že podmínky a výsledný stav jednotlivých pravidel nejsou logicky lépe seskupeny. Takto se nám v kódu 4-krát opakuje stejný pattern:

if (XRule(cellState, numberOfLiveNeighbours)) return CellState.?;

E. Sbližujeme podmínky pravidel a výsledné stavy

delegate bool RulePredicate(CellState cellState, int numberOfLiveNeighbours);
 
public class NextGenerationStateCalculatorE
{
    public CellState Calculate(CellState cellState, int numberOfLiveNeighbours)
    {
        var rules = new Dictionary<RulePredicateCellState>
        {
            { UnderPopulationRulePredicate, CellState.Dead },
            { SurviveRulePredicate, CellState.Live },
            { OverPopulationRulePredicate, CellState.Dead },
            { ReproductionRulePredicate, CellState.Live },
            { NoReproductionRulePredicate, CellState.Dead }
        };
 
        var ruleKeyToApply = rules.Keys.First(rulePredicate => rulePredicate(cellState, numberOfLiveNeighbours));
        var nextGenerationState = rules[ruleKeyToApply];
 
        return nextGenerationState;
    }
 
    private bool UnderPopulationRulePredicate(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Live && numberOfLiveNeighbours < 2;
    }
 
    private bool SurviveRulePredicate(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Live && (numberOfLiveNeighbours == 2 || numberOfLiveNeighbours == 3);
    }
 
    private bool OverPopulationRulePredicate(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Live && numberOfLiveNeighbours > 3;
    }
 
    private bool ReproductionRulePredicate(CellState cellState, int numberOfLiveNeighbours)
    {
        return cellState == CellState.Dead && numberOfLiveNeighbours == 3;
    }
 
    private bool NoReproductionRulePredicate(CellState cellState, int numberOfLiveNeighbours)
    {
        return true;
    }
}

Zadefinovali jsme delegát RulePredicate, který popisuje, jak mají vypadat metody vyhodnocující podmínku pro pravidlo. Dictionary rules mapuje tyto podmínky na výsledné stavy. Máme tak poměrně hezké přiřazení pojmenované podmínky a výsledného stavu pro jednotlivá pravidla. Za tento "funkcionální přístup" jsme odměněni hezkou jedničkou z CC.

Moc se mi ale nelíbí způsob procházení obecného Dictionary, kdy odkazujeme Keys abychom přistoupili k predikátům jednotlivých pravidel. Abstrakce pravidla stále není moc dobrá.

F. Tak dobře, zapouzdříme pravidla

public class NextGenerationStateCalculatorF
{
    private readonly RuleBase[] _rules;
 
    public NextGenerationStateCalculatorF()
    {
        _rules = new RuleBase[]
        {
            new UnderPopulationRule(),
            new SurvivalRule(),
            new OverPopulationRule(),
            new ReproductionRule(),
            new NoReproductionRule()
        };
    }
 
    public CellState Calculate(CellState cellState, int numberOfLiveNeighbours)
    {
        var ruleToApply = _rules.First(rule => rule.Predicate(cellState, numberOfLiveNeighbours));
        var nextGenerationState = ruleToApply.NextGenerationCellState;
 
        return nextGenerationState;
    }
 
    private abstract class RuleBase
    {
        public RulePredicate Predicate { get; }
        public CellState NextGenerationCellState { get; }
 
        protected RuleBase(RulePredicate predicate, CellState nextGenerationCellState)
        {
            Predicate = predicate;
            NextGenerationCellState = nextGenerationCellState;
        }
    }
 
    private class UnderPopulationRule : RuleBase
    {
        public UnderPopulationRule()
            : base((state, neighbours) => state == CellState.Live && neighbours < 2, CellState.Dead)
        { }
    }
 
    private class SurvivalRule : RuleBase
    {
        public SurvivalRule()
            : base((state, neighbours) => state == CellState.Live && (neighbours == 2 || neighbours == 3), CellState.Live)
        { }
    }
 
    private class OverPopulationRule : RuleBase
    {
        public OverPopulationRule()
            : base((state, neighbours) => state == CellState.Live && neighbours > 3, CellState.Dead)
        { }
    }
 
    private class ReproductionRule : RuleBase
    {
        public ReproductionRule()
            : base((state, neighbours) => state == CellState.Dead && neighbours == 3, CellState.Live)
        { }
    }
 
    private class NoReproductionRule : RuleBase
    {
        public NoReproductionRule()
            : base((state, neighbours) => trueCellState.Dead)
        { }
    }
}

Hlavní metoda prohledá pole pravidel inicializovaných v konstruktoru třídy. Vybraného pravidla se pak zeptá na příští stav. CC = 1. Při implementaci jednotlivých pravidel jsme si pomohli bázovou třídou RuleBase. Implementace konkrétního pravidla se nám pak omezí pouze na předání predikátu a nového stavu přes volání bázového konstruktoru.

Každé pravidlo je nyní reprezentováno dobře pojmenovanou třídou. Hlavní třída pouze definuje pořadí těchto pravidel a umí se doptat na výsledný stav buňky v příští generaci. Celková komplexita problému je rozložena do více tříd s nízkou komplexitou. Přestože je kód delší, můžeme jej stále považovat za jednoduchý.

Jak tedy psát ten kód?

Možná si říkáte, kam jsme se to v tom vylepšování až dostali. Proč tak složitě na tak jednoduchý problém? Proč vytvářet tolik tříd?

Je to trénink. Test toho, jak vnímáme komplexitu kódu a které charakteristiky nás vlastně zajímají. Reálné problémy jsou samozřejmě složitější a správná redukce komplexity přinese výraznější benefity. A příjemnější práci pro programátory.

Přemýšlejme nad každým větvením programu, zda-li se náhodou nejedná o signál pro použití polymorfismu a separaci na úrovni tříd. Nízká CC by měla být našim základním požadavkem.

Preferujme, aby v našem kódu byla snadno dohledatelná struktura reálného problému, tedy našich (správně formulovaných) požadavků.

Nejrychlejší / nejkratší řešení často nebývá nejlepší. Zvažujme různé možnosti a přístupy. Psát "složitý kód" bývá jednoduché, zato psát "jednoduchý kód" často složité.

Strach, lenost nebo neschopnost problém dekomponovat do více jednodušších tříd často vede k hromadám špaget. Nic proti špagetám, mohl bych je mít pořád. Ale v kódu se bez nich rád obejdu! :)

neděle 28. února 2016

Požadavky na požadavky

Primárním cílem každého software je řešit problémy zákazníka nebo své cílové skupiny. Řešení je popsáno specifikací požadavků na systém. Psát dobré požadavky a efektivně je spravovat není snadné. Vyžaduje to specifické dovednosti a spolupráci napříč celým týmem. Dobrá specifikace je ale stejně důležitá jako dobrý zdrojový kód.

Pojďme se společně podívat, jaké problémy nám mohou komplikovat práci s požadavky.

Tohle není můj problém

Programátor: “Od analytiků dostáváme hrozné zadání. Jak podle toho máme něco naprogramovat!?”

Analytik: “Vykomunikoval jsem to se zákazníkem, popsal hlavní ideu, navrhl postup a tím to pro mě končí. Programátoři ale chtějí, abych za ně promýšlel problém do úplných detailů. To je jejich práce. Na to nemám čas.”

Pokud mají dvě skupiny v naší firmě potřebu se vzájemně vyhraňovat, máme dost závažný problém. Týmové role nespolupracují efektivně. Chtějí si nadefinovat rigidní rozhraní místo snahy o spolupráci na nejlepším výsledku. Agilita je o společné zodpovědnosti za vše, co s vyvíjeným software souvisí. Včetně požadavků. Odolejme pokušení sortovat na ty, co dělají zadání a na ty, co podle zadání dělají konstrukci. Jsme jeden tým. Pokud můžeme, posaďme zákazníka, analytika, programátora, testera a další lidi do jedné kanceláře. Nebo je propojme nějakým efektivním komunikačním kanálem. Potřebujeme dobrou komunikaci, rychlou zpětnou vazbu a rychlé zapracování změn.

Zrovna dodělávám kompletní specifikaci

Projektový manažer: “Výborně Karle, ta specifikace vypadá neprůstřelně, teď to necháme kluky naestimovat a můžeme podepsat smlouvu.”

Pokusy vytvořit kompletní specifikaci ještě před konstrukcí (up-front) možná fungují u malých věcí nebo u opakujících se podobných projektů. Často ale ani tam. U větších věcí s vysokým stupněm inovace a nejistoty jsou ale podobné ambice tvrdě trestány. Navýšením nákladů a frustrací ze zbytečné práce, kterou musíme často zahodit. Rigidní vodopádová snaha zakonzervovat požadavky je často naivní obranou proti neschopnosti efektivně provádět změny během konstrukce. A nebo je důsledkem striktní smlouvy o dílo, kde zákazník raději vsadí na jistotu “dodání funkcionality v požadovaném rozsahu”.

Buďme připraveni na změnu. Mějme na paměti celek, ale rozdělujme na podproblémy. Specifikujme vysokoúrovňové business požadavky. Analyzujme je podle priority a rozpracujme do podrobnějších produktových požadavků ve formě user stories. Prioritizované user stories nám vytvoří produktový backlog. User story ale zatím není zadání, na které čeká programátor. Je to pouze placeholder pro následnou detailní specifikaci.

Když se na user story dostane řada, začíná její detailnější analýza a definice požadavků. Očekávanými výsledky jsou popis chování systému (use cases), upřesnění UI (mock-ups) a nefunkcionální specifikace. Analytik analyzuje problém a navrhuje řešení v úzké spolupráci se zadavatelem. Využívá znalostí a spolupráce dalších rolí v týmu. V případě rizik, omezené znalosti technologií nebo možnosti více konceptů, je prováděno rychlé prototypování. Ty nejrizikovější věci by měly být odprototypovány na začátku projektu.

Dobrou praktikou je vytvoření test cases ještě před vlastní konstrukcí. V této fázi mohou test cases odhalit závažné nedostatky ve specifikaci požadavků a ušetřit tak spoustu peněz v případě pokračování špatným směrem. Pokud tester není schopen napsat kompletní a jednoznačné testovací případy, zřejmě ani programátor nebude schopen efektivní implementace. Zkušený tester prokoukne nedefinované alternativní větve, chybějící podmínky nebo neošetřené chybové stavy. Často jsou v detailech ukryta závažná projektový rizika.

Nevíte někdo, jak to funguje?

Analytik: “Omlouvám se za hromadný email na všechny lidi ve firmě, ale nemůžu najít specifikaci business pravidel pro XY. Poradí mi někdo, prosím?”

Odpověď A: “Aleši, to by mě taky zajímalo, až to zjistíš, dej mně prosím vědět.”

Odpověď B: “Zkus složku SpecABC, jsou tam nějaké staré wordy. Kdyby to nebylo tam, tak něco možná bude na naší wiki. Jinak dělal to Lojza a ten už ve firmě není. Jak asi víš, z těch přesčasů mu nakonec hráblo. Pokud to nenajdeš, budeš to muset pochopit z kódu. Ale to ti fakt nezávidím. :)”

Na začátku každého projektu vše vypadá krásně a růžově. Lidé jsou nadšení. Všichni zúčastnění vědí o projektu téměř všechno. Nějaká specifikace možná existuje, ale její správě a aktualizaci se často nevěnuje příliš velká pozornost. Požadovaná funkcionalita se dodává rychle, všechno klape a management se poplácává po zádech. Všichni jsou happy.

Projekt roste, vyvíjí se, nová funkcionalita přibývá a stávající se mění, noví lidé přicházejí, původní odcházejí. Je nutná specializace, komplexita systému je už příliš vysoká. Začínají se zvyšovat náklady na správu všech projektových artefaktů. Kde máme aktuální informace? Co všechno se musí upravit kvůli novému požadavku? Jaká jsou rizika? Co vlastně máme před releasem otestovat?

Špatné nakládání se specifikací systému je jednou z nejrizikovějších forem softwarového technického dluhu. Členové týmu zdlouhavě dohledávají informace, dělají špatná rozhodnutí na základě nesprávných informací, vznikají duplicity, zvyšuje se chybovost, management je pod tlakem a přehazuje lidi podle toho, kde to nejvíce hoří. Lidé nemají možnost dělat práci kvalitně a proto frustrovaně odcházejí. Někdy může situaci dospět až k tomu, že údržba projektu je tak drahá, že se už dále nevyplácí a projekt je ukončen. Poslední ať zhasne.

Začněme správu požadavků řešit co nejdříve. Celý proces musí být co nejefektivnější a nejjednodušší. Složité postupy nefungují. Zde je přehled Requirement Management Software. Pokud máte s nějakým systémem větší zkušenost a můžete jej doporučit, přidejte prosím komentář.

Výkonný systém s intuitivním UI

Programátor: Arnošt mi zase poslal zadání, ve kterém píše “vytvořit dostatečně výkonný modul s intuitivním ovládáním, podobný tomu z loňska, ale upravený pro letošní administrativu”. Jdu ho intuitivním způsobem poslat k šípku, podobně jako loni.

Jak psát efektivně požadavky je popsáno v Writing Quality Requirements. Je to už sice hodně vousatý článek, ale přehledně shrnuje to nejdůležitější. Čemu se máme vyvarovat a na co se zaměřit. Jedná se o povinné čtení pro všechny vývojáře software.

Podobně jako jsme zvyklí revidovat kód, abychom našli problémy a sdíleli znalosti o implementaci, můžeme revidovat i požadavky. Analytik musí vysvětlit své chápání problému a důvody proč navrhl toto řešení. Pár tipů na review najdete v How to Conduct a Requirements Review.

Dobrý business analytik je vyladěnou kombinací doménových znalostí a analytických dovedností, viz. např. What Business Analyst Skills are Important. Ty je potřeba neustále procvičovat a vylepšovat. Jak rozvíjíte BA ve vašem týmu?

Shrnutí

Dobře definované požadavky na systém jsou prvním zásadním krokem pro kvalitní výsledek snažení celého týmu. Nesnažme se však všechno vymyslet a popsat hned na začátku. Riziko špatné specifikace je příliš vysoké. Změny pak budou bolet mnohem víc než při postupném iterativním vývoji.

Chápejme proces specifikace systému jako spolupráci celého týmu. Nechtějme programátory-opičky, kteří dostanou přesné zadání a jen klepou. To nefunguje. Chceme myslící bytosti, s určitou znalostí domény, aktivně zapojené do procesu vytváření software.

Specifikace je živá interaktivní dokumentace, která se musí efektivně udržovat po celou dobu života projektu. Úroky za macešský přístup k požadavkům jsou totiž příliš vysoké.

Podělíte se s námi o to, jak se daří spravovat požadavky u Vašeho projektu? Díky.

sobota 23. května 2015

Programátore, chceme tě mít on-site

"Po nějaké době je možné dohodnout částečný home-office"
"Projekt je krátkodobý proto klient vyžaduje on-site"

Ach jo, píše se rok 2015 a většina IT firem u nás stále není mentálně připravena a aktivně nepodporuje remote work. Vidí spásu v tom, že budou mít všechny ovečky pěkně pohromadě v budově, do které investovaly velké peníze. Ztrácejí tak možnost spolupracovat s lidmi, kteří mají odbornost, dostatek sebekontroly a požadovaný výsledek by mohli dodat dříve a ve vyšší kvalitě.

Proč? Většina projektů v IT se zpožďuje, prodražuje se a původní estimace, pracně vytřepané z rukávu a několikrát pozměněné, se nám ve finále smějou do očí. Představa, že budou muset vysvětlovat vyšší náklady na projekt a ještě fakt, že tým pracoval remote, mnoho projekťáků děsí. Nebudeme si proto komplikovat situaci, co říkáte?

"Práce remote není pro každého." Pro koho tedy není? Pro někoho, kdo při on-site na rozdíl od remote odvádí výsledky? Aha, takže pracuje dobře jen pod dohledem nadřízeného. Chcete takového kolegu?

"Jak mám jako vedoucí sledovat progres remote týmu?" A jak jej sleduješ u on-site? Efektivní vývojové metodologie nejsou nijak zásadně závislé na tom, jestli transformátory kávy na kód sedí blízko sebe nebo stovky kilometrů. Mnohem více jsou závislé na dobré komunikaci, dostatečné zpětné vazbě a dobrých návycích členů týmu. Zkuste si remote pair work, je to fajn.

"Když já opravdu nevím, co vlastně doma dělá." Dělá to, co je typické pro tvůj tým a firmu. Pokud máš dobře motivované zaměstnance, jste orientovaní na výsledek a kvalitu, bude to dělat i vzdáleně. Prostě pokud ho práce baví, neměj strach. Pokud umíš řídit lidi, poznáš, že někdo do týmu nepatří.

"Komunikace není efektivní, navíc mě pořád ruší zprávy na messengeru". V dnešní době rychlých připojení k internetu a nástrojů pro spolupráci asi nebude problém ve vzdálenosti. Hledej problém někde jinde - v organizaci času a práce, v efektivitě týmových schůzek, ve schopnosti přepnout do distraction-free režimu.

"Lidé, dokonce i programátoři, potřebují trávit společně čas". Tak určitě. Ale kolik vlastně?

Sedí tam hodně programátorů a všichni mají sluchátka, co je to? Open space.

IT firmo, chceš kvalitní lidi nebo je potřebuješ mít hlavně všechny pohromadě?

sobota 31. května 2014

Malými krůčky ke zvládnutí velkých úkolů

Tento příspěvek je krátkou obhajobou dekompozice složitých problémů na malé koncové tasky. Práce s malými tasky totiž působí přímo blahodárně na často dost zatížené nervové soustavy členů projektového týmu. Pokud se váš projekt zasekává a dostává se do vážnějších problémů, zkuste se zamyslet nad tím, zda-li nebojujete s problémy, které jsou typické pro nezvládnutí správné dekompozice složitosti.

Malý task

Co je vlastně myšleno malým taskem? Pro mě je to task s dobou realizace do 4 hodin, ale ideálně kolem 2h. A nezávisle na tom, zda-li se jedná o práci analytickou, návrhovou, implementační, testování nebo úkoly spojené s podpůrnou infrastrukturou projektu a byrokracií (paper work). Velikost commitu v případě implementačního tasku by neměla překročit řádově desítky změněných řádků (počítáno jako LLOC). Na druhou stranu je počet změněných řádků kódu dost zavádějící metrika. Někdy můžeme půl dne hledat bug a výsledkem je změna na jednom řádku (+ nový původně padající test). Jindy děláme refaktoring a jeden rozsáhlejší rename vynutí změny na stovkách řádků.

Ne vždy se to podaří ...

Rozložení řešeného problému na malé postupné krůčky je efektivní a univerzální technika ve všech oborech lidské činnosti. Ve vývoji software je ale nutné mít vhodné podpůrné nástroje a efektivní postupy. Jinak se dobře míněná snaha o zvýšení efektivity práce změní ve znechucené trápení. Je nutné zajistit splnění několika základních podmínek:

  • Pracovní postupy by neměly být zatíženy přílišným formalismem. Čím méně restriktivních opatření, tím lépe. Příliš formální metodiky jsou účinnou antikoncepcí proti vytváření malých tasků. Předpokládám, že agilita si vybojovala místo i ve vašem vývojovém týmu a proto bude tato podmínka bude splněna.
  • Používejte nástroj, který vám usnadní správu a vizualizaci tasků. Protože jsou malé, je jich také mnoho. Nástroj musí být intuitivní, rychlý a dostupný bez omezení. My jsme se rychle spřátelili s YouTrackem, který pro naše potřeby maximálně vyhovuje.
  • Vytvoření tasku musí být rychlé. Vybrat umístění (projekt, feature nebo user story), zadat název, stručný popis, akceptační kritéria a estimaci. To by mělo ve většině případů stačit. Někdy se při vytváření tasku zasekneme, neboť napsat dobré zadání je pracné. Ale zdržovat by nás mělo pouze naše myšlení a ne použitý nástroj.
  • Používejte pouze atributy, které potřebujete. Šablona tasku, která má desítky atributů je dobrá obvykle jen pro někoho, komu potřeba projektové formalizace způsobila neléčitelnou ztrátu zdravého rozumu. V jednoduchosti je síla, proto nejdůležitější položky musí být dostupné rychle, bez nutnosti překlikávání. Méně využívané položky by pak měly být schované na detailových kartách. A nepoužívané bez milosti odstraněny. Dvakrát si rozmyslete, než přidáte nový atribut.
  • Workflow tasku musí být jednoduché. Čím méně stavů tím lépe. Na našem posledním projektu jsme zvolili tyto: Backlog, Ready for Dev, Dev in Progress, Ready for Review, Review in Progress, Finished (+ Waiting) s vizualizací pomocí Kanban boardu. Pokud bychom neměli interní politiku o revidování každého tasku, pak bychom ještě dva stavy ušetřili. Některé typy tasků ale jedou v jiném režimu, např. task typu Bug nahlášený od testerů nebo v horším případě z produkce.
  • Mělo by být možné integrovat systém pro evidenci tasků s dalšími články vývojové infrastruktury. A to se správou repository, buildovacím serverem, IDE, CASE, apod. Např. k namapování změn v kódu na příslušný task pak pouze stačí odkazovat id tasku v commit message.

Ale když se to podaří ...

A v čem jsou vlastně malé tasky šikovnější než ty velké obludy?

  • Rychlé vyřešení tasku působí blahodárně na psychiku a dobrý pocit z dokončení je účinným motivátorem do další práce. Rozplizlé dlouhé tasky nás naopak demotivují, nevidíme na jejich vzdálený konec a vnášejí pochybnosti o naší pracovní efektivitě. Tak jako většina lidských činností je i vývoj software psychologickou hrou s naším podvědomím, snahou udržet nadšení, pozornost a správný kurz k požadovanému cíli.
  • Menší jednotky práce je snadnější přesně specifikovat. Problém jsme nuceni už při zadávání lépe promyslet a zadefinovat akceptační kritéria. Dobrým zadáním problému zvyšujeme pravděpodobnost správné realizace a efektivního review.
  • Přesnější estimace. Je dost deprimující, když se skutečná pracnost na hony liší od té odhadované. Malé úkoly trefíme mnohem lépe. Doporučuji mírně pesimistický přístup a zohlednit časovou rezervu. Udělat úkol dříve než se čekalo je povzbuzující. Máme ze sebe dobrý pocit a roste nám správným způsobem sebevědomí. Naopak výrazné přešvihnutí estimace nás dostává pod tlak, který často vyústí ve sníženou kvalitu výsledku.
  • Review menších změn je mnohem efektivnější. Je zřejmé, na co se zaměřit. Review trvá kratší dobu, takže reviewer je pozornější, neusíná a často i něco objeví.
  • Stává se méně často, že odcházíme domů a zůstane po nás nedokončený úkol. Já osobně nemám tyhle situace vůbec rád a když něco nedotáhnu do konce, přemýšlím nad tím ještě doma. A nejhorší je nedotahovat věci v pátek odpoledne.
  • Pokud zaneseme chybu nebo rozbijeme CI build, pak je problém mnohem lépe dohledatelný. Je rozdíl, pokud hledáte v commitu s 20 změněnými řádky nebo s 200.
  • Dostáváme rychlejší zpětnou vazbu a pokud se něco nepovede, nevracíme se příliš daleko dozadu. Víme, jak je nepříjemné zahodit kód, nad kterým jsme strávili dlouhé hodiny nebo dny. Obvykle je ale výhodnější špatný kód zahodit, než obhajovat jeho smysluplnost a tím jeho eutanázii pouze oddalovat a zvyšovat tak náklady na vývoj.
  • Malé tasky vnášejí do vývoje větší dynamiku a celý tým může sledovat postup řešení většího celku, třeba user story. Nestává se, že programátor dostane zadání, pár dnů o něm nevíte a pak se objeví s “vymazlenou” implementací, která se ale hodně odklonila od původního záměru a trpí mnoha nedostatky.
  • Jistě znáte techniku TDD, která nabádá ke krátkým implementačním cyklům se strukturou: 1. rozmysli si co chceš (napiš test), 2. naimplementuj to (napiš produkční kód), 3. zkontroluj, jestli změna nerozbila celek (všechny testy zelené), 4. vylepši fungující implementaci (refaktoring). Díky TDD dostáváme okamžitou zpětnou vazbu o stavu našeho kódu. Malý task by pak v tomto chápání mohl mít podobný efekt jako cyklus TDD, ale s větší granularitou. Nutí nás více rozmýšlet požadovaný výsledek, ten dostáváme již během několika hodin. Po uložení změn do repository získáme skrze CI build informaci o stavu celku. V rámci review můžeme řešení ještě vylepšit.

S malými tasky můžeme dosáhnout velkých výsledků. A navíc velmi efektivním způsobem. A za každé dokončení tasku se můžeme nějak odměnit. Třeba procházkou k lednici, krátkou rozcvičkou nebo dobrým kafem. A život programátora bude zase o něco veselejší! ;)