Čistý kód v JavaScriptu: méně chyb díky malým funkcím
Kontrakty místo kopírování scénář
Měníte zadání každý týden a vaše testovací pyramida se rozpadá? Nejčastější chybou je držet se u strmých pyramid s důrazem na unit testy, které jsou příliš úložné prostory v malém bytěázané na implementaci. Jakmile se změní požadavek, přepisujete stovky testů a ztrácíte čas. Řešení není v zahazování testů, ale v přesunu těžiště.
Uložení klíče patří do transakce spolu s vlastní operací. Pokud nejdřív zapíšete výsledek a pak klíč, může selhat zápis klíče a při opakování vznikne duplicita. Vhodné je použít databázi s unikátním indexem na kombinaci klíče a uživatele. Při souběhu dvou požadavků se stejným klíčem jeden zápis uspěje a druhý dostane konflikt. Tento konflikt se nemá vracet jako chyba 500, ale jako 409 nebo 200 s původním výsledkem. Doba platnosti klíče má být omezená, obvykle hodiny až dny. Příliš krátká expirace dovolí duplicitu později, příliš dlouhá zbytečně plýtvá místem.
Začněte pojmenováním. Proměnná data neříká nic, seznamUzivatelu říká všechno. Funkce process() nutí čtenáře otevřít tělo funkce, vypocitejSlevu() ho pustí dál. Platí přitom jedno pravidlo: pokud název potřebuje komentář, je název špatný. Komentáře mají vysvětlovat proč, ne co. Když vidíte // zvyšujeme o jedna nad i++, komentář jen opakuje kód a rekonstrukce koupelny krok za krokem měsíc bude lhát.
Čistý kód v JavaScriptu není o estetice, ale o tom, aby se v něm dalo rychle najít problém a bezpečně měnit chování. Největší zdroj zmatku bývají funkce, které dělají příliš mnoho věcí najednou. Pokud funkce načítá data, upravuje je, zapisuje do globálního stavu a ještě mění DOM, každá změna je riskantní. Rozdělte ji na menší celky, z nichž každý má jednu odpovědnost. Konkrétně: pojmenujte funkci podle toho, co vrací nebo jaký stav vytváří, a pokud název obsahuje spojku „a" (například „nactiAUprav"), je to rozdělení.
Kde konkrétně ubrat a kde přidat Zaměřte se na testy chování, ne na testy metod. Napište testy, které volají veřejné rozhraní a kontrolují výstup, nikoli vnitřní volání. Tím se vážete na kontrakt, který se mění pomaleji než implementace. Dále zaveďte testovací datové továrny nebo fixtury, které umožní snadno měnit vstupy bez přepisování celých testů. Vyhněte se mockování všeho – přílišné mocky vytvářejí křehké testy, které se rozbijí při každé změně.
Nakonec měřte dobu, kterou trávíte opravou testů po změně. Pokud přesahuje 20 % času vývoje, pyramida je špatně nastavená. Cílem není mít nejvíce testů, ale mít testy, které vydrží změny a přesto odhalí regrese. Přesuňte těžiště do středu pyramidy a udržujte ji plochou.
Pojmenování a předvídatelnost Názvy proměnných a funkcí mají odpovídat tomu, co drží. Vyhněte se zkratkám jako `tmp`, `data2` nebo `x`, pokud nejde o krátký matematický výraz. U booleanů používejte předpony `je`, `ma`, `muze` — čtenář pak nemusí dohledávat, co znamená `true`. Stejně tak se vyhněte „magickým" hodnotám. Číslo 7 v podmínce nic neříká; konstanta `MAX_POKUSU = 7` řekne vše. Když se hodnota použíúložné prostory v malém bytěá na více místech, patří do jedné konstanty, jinak při změně zapomenete na jednu z kopií.
Druhým častým problémem je míchání úrovní abstrakce. Na jedné řádce voláte databázi, o pár řádků níže řešíte formátování data a za tím vším se skrývá ruční práce s polem. Držte jednu úroveň: buď funkce skládá jiné funkce, nebo pracuje s konkrétními hodnotami. Pomůže pojmenovávat mezivýsledky. Místo vnořeného výrazu s pěti tečkami si vytvořte proměnnou `aktivniUzivatele` a teprve tu dál zpracujte. Kód se tím prodlouží o dva řádky, ale zkrátí se doba hledání chyby.
Nezapomínejte na chybové stavy. Kód, který předpokládá, že všechno projde, je křehký. Místo tichého `undefined` použijte raný návrat nebo vyhození chyby s jasnou zprávou. Kontrolujte vstupy na začátku funkce, ne uprostřed. Tím se hlavní logika odsadí a čte se jako příběh. Zároveň se vyhněte hlubokému vnořování podmínek; častěji pomůže obrácená podmínka a návrat.
Základem je rozdělit testy podle toho, co ověřují, ne podle vrstvy. Místo poměru 70/20/10 začněte s 30 % unit testů, 50 % integračních a 20 % end-to-end. Unit testy pište jen pro čistou logiku, která se nemění – výpočty, validace, transformace dat. Integrační testy na úrovni API nebo služeb pokryjí interakce mezi komponentami, které se sice mění, ale jejich rozhraní zůstává stabilní. End-to-end testy používejte pouze pro kritické scénáře, které se mění zřídka.
Dále si hlídejte mutace. JavaScript dovoluje měnit objekty předávané do funkcí, což snadno vede k nečekaným vedlejším efektům. Pokud funkce nemá měnit vstup, pracujte s kopií nebo použijte čistý přístup, kdy funkce vrátí novou hodnotu a původní nechá být. U polí a objektů se vyhněte přímému zápisu do parametru, pokud to není záměr.Čistý kód také znamená, že se funkce chová stejně při stejném vstupu, bez ohledu na pořadí volání.