Následující článek popisuje způsob vývoje webových aplikací, který už nějakou dobu praktikuji a který mi připadá jako zdaleka nejlepší z těch, které jsem měl možnost vyzkoušet. Text je teoretickým shrnutím toho, co lze nalézt v mých seriálech na Zdrojáku. Jde zde proto, abych na něj mohl odkazovat ty, kteří seriály na Zdrojáku nečetli a číst kvůli jeho rozsahu ani nechtějí.
První faktor úspěchu: možnost rychlých a bezbolestných změn
Dle různých statistik končí až 80% (některé studie uvádějí i více než 90%) projektů neúspěchem. Za neúspěch se považuje nejčastěji nedodržení termínu, překročení ceny či chybějící funkčnost. Už se ví, že staré metodiky postaveném na vodopádovém modelu vůbec nefungují. Také je všeobecně známo, že je nezbytně nutné zahrnout budoucí uživatele do testování během vývoje. Je potřeba od nich získávat zpětnou vazbu a s ní dále pracovat.
Dříve jsem si myslel, že toho dosáhnu striktním oddělením požadavků (otázka CO to má umět) od návrhu (otázka JAK daný požadavek splnit). To funguje, ale velký problém je právě zjišťování a přesnost oněch požadavků. Existují samozřejmě různé způsoby, jak z klientů dostat, co vlastně vůbec potřebují. Problém je však v tom, že to často ani oni sami nevědí, a tak když podrobně zmapuji jednu část a uděláme ji, o měsíc později můžu zjistit, že vlastně danou věc potřebují udělat úplně jinak, což si uvědomí až tehdy, když poprvé nějaký výstup uvidí.
Tohle se dá různými způsoby minimalizovat. Třeba prototypováním. Zjistím, co vlastně klient chce a v nějakém šikovném programu podle toho navrhnu obrazovky UI, které pak konzultuji a měním. Prototypování tímto způsobem ale nemám rád z několika důvodů. Jednak že výsledná aplikace stejně pak často vypadá úplně jinak, protože mnoho požadavků přijde až s tím, jak si klient s appkou začne hrát, ale třeba také proto, že je to práce, která se poté zahodí a špatně se účtuje. A hlavně prototypování množství požadavků na změnu sice minimalizuje, ale definitivně nevyloučí.
Zkrátka neexistuje způsob, jak z klienta dostat všechny požadavky hned na začátku a dosáhnout toho, aby již žádné požadavky nepřichzely. To je útopie. Proto je pro mě klíčové dosáhnout minimálních nákladů na změny. Potřebuji, abych mohl aplikaci ukázat klientovi a když bude požadovat změnu, dokážu ji zahrnout třeba s 1/20 nákladů při klasickém způsobu vývoje. Místo mnoha hodin strávených nad návrhem raději něco vytvořím a okamžitě získám zpětnou vazbu (třeba i v denních iteracích) od těch, co to pak budou používat, zda to takto odpovídá jejich představám. Když chtějí změnu, hned ji provedu a opět se celé kolečko opakuje, dokud nejsou spokojeni všichni. Podstatné ale je, abych ukazoval reálnou aplikaci a ne pouze prototyp. Tím dosáhnu toho, že klient skutečně dostane to, s čím je 100% spokojen.
Podle mých zkušeností nejvíce času stojí změny, které jsou vynuceny úpravami databáze, nejhůře pak celé její struktury. Jak se tomu vyhnout je popsáno dále.
Druhý faktor úspěchu: respektování priority požadavků
Nerespektování priority požadavků je podle mě největší problém u drtivé většiny aplikací. Není-li stanovena priorita požadavků, programátoři budou dělat to, co je baví nejvíce (nejsem výjimka). Běžně se aplikace dělá tak, že se nejprve programuje administrace číselníků (jednoduché tabulky) a až na konci se dělá to, co je z těch číselníků sestaveno. Třeba v e-shopu nejspíš může někdo začít sekcí administrace druhů dopravy a platby, bude pokračovat parametry, definicí záručních dob atd., jako poslední nejspíš udělá sekci objednávek a pak začne dělat až uživatelskou část, kde jako poslední udělá objednávkový proces, protože ten spojuje všechno ostatní dohromady.
Tohle je ale úplně špatně. To nejdůležitější z celého e-shopu se tak dělá až úplně na konci. Tedy v době, kdy je často po deadline a je potřeba projekt bleskově dokončit, což zrovna kvalitě nepřidá. A ještě horší je, je-li stanoven pevný termín, kdy projekt musí být hotový (třeba je připravena reklamní kampaň na nějaké datum, stává se to). Když e-shop nemá objednávkový proces, je úplně k ničemu. Když však stihnu vše, ale některé části ještě v administraci nelze spravovat, dokážu alespoň zajistit brigádníky, kteří do do databáze data nasypou přes nějaký program. A až po spuštění projektu postupně dodělám v administraci ty části, které ještě nejsou. E-shop ale bude fungovat a vydělávat peníze.
Potřebuji tedy dělat ty nejdůležitější části co nejdříve a ty méně důležité až později. Způsob vývoje, který si vyberu, musí tyto dva požadavky respektovat. Jak tedy na to?
Single-page aplikace a AngularJS
Nejraději mám single-page aplikace (SPA), tedy většina aplikace je přesunuta do prohlížeče. Nejznámější (a možná i první) implementace tohoto vzoru je Gmail. Z velkého množství klientských MV* frameworků mi vyhovuje nejvíce AngularJS, který umožňuje drasticky snížit množství kódu, které je potřeba napsat. Díky parádní podpoře dependency injection umožňuje vytvářet znovupoužitelné, samostatné a výborně testovatelné komponenty.
REST API
Tento typ aplikací obsahují tedy logiku na straně klienta a se serverem komunikují pomocí REST API. Existují dohodnuté best practice, jak mají URL a GET/POST/PUT/DELETE požadavky vypadat. Pokud chci tedy třeba získat detail objednávky s ID 123, bude na adrese GET /orders/123, když budu chtít objednávku smazat, zavolám DELETE /orders/123 atd.
Všechny požadavky jdou přes jeden centrální bod. Např. chci pracovat se seznamem objednávek. Na jednom místě chci všechny objednávky, tak zavolám URL GET /orders. Na jiném místě chci prvních 50 objednávek uživatelů s cenou objednávky vyšší než 1000 Kč, tak zavolám URL GET /orders?filter=priceHigherThan:1000&limit=50. Parametr priceHigherThan není v databázi, je to nějaké pravidlo, které mám univerzálně definováno a když pro něj přijde požadavek, tak ho inicializuji (po automatickém ověření práv). Správu jednoho zdroje mám pak na jednom místě pro mnoho různých částí (tedy nikoliv x metod, které vybírají z databáze pokaždé trochu jiná data).
Apiary
Velký rozdíl oproti klasickému způsobu tvorby aplikací je zapojení Apiary. Zde si nadefinuji, jak má REST API vypadat a uvedu nějaké příklady. Z toho získám jednak skvělou dokumentaci, ale také testovací data. Především však Apiary umí definici REST API vložit do souboru apiary.apib a ten pak synchronizovat s repozitářem na Githubu. Když tedy udělám novou úpravu v Apiary, mám aktuální pravidla na Githubu. Když pak chci poslat git push do repozitáře, Git mě upozorní, že došlo k změně v REST API. Stáhnu si pomocí git pull daný soubor k sobě, ten se přeloží do klasického JavaScriptu pomocí nástroje Grunt a pravidla pro URL se načtou při vývoji přímo do aplikace. Díky tomu pak AngularJS neposílá požadavky přímo na server, ale místo toho pracuje pouze s mock daty. Klíčové je, že aplikace se chová úplně normálně, jako kdyby komunikovala opravdu se serverem.
Nejprve UI, databáze až na konec
To mi přináší jednu úžasnou výhodu. Můžu vyvíjet celou aplikaci pouze s AngularJS bez toho, abych napsal jediný řádek kódu na serveru. Všechny změny dělám jen na straně klienta a v Apiary definují nová pravidla nebo upravuji ty stávající. To drasticky zvyšuje rychlost vývoje. Když klient řekne, že chce takové a takové parametry u produktu v e-shopu, tak je nadefinuji jen jako JSON response u Apiary a s těmito daty pak připravím celou klientskou část. Později zjistí, že vlastně ty parametry mají být jinak a ještě později třeba přijde na to, že vlastně vůbec parametry nepotřebuje. V tom případě změním nebo smažu definici z Apiary a upravím jejich vykreslování v detailu produktu a je to.
Díky tomu můžu začít těmi nejdůležitějšími částmi, třeba správou objednávek a objednávkovým procesem, protože nepracuji s databází, ale pravidla nadefinuji přímo v Apiary. Z toho pohledu je úplně jedno, kterou sekcí začnu, je to pro mě všude stejně jednoduché. U klasického způsobu, kdy nejprve navrhuji databázi je to jinak, tam se ten objekt bude skládat z dat z mnoha a mnoha tabulek, které musí obsahovat testovací data.
Celou aplikaci pak vývíjím v Twitter Bootstrapu (+ LESS) a dokážu v podstatě od druhého dne hned zapojit do uživatelského testování lidi, kteří ji pak budou používat. Funguje to skoro stejně rychle jako klasické prototypování. Ovšem s tím rozdílem, že zatímco prototyp se zahodí, tato aplikace je reálná a to také uživatele dostanou (jen s vylepšeným, unikátním designem). Udělám malou část a okamžitě chci zpětnou vazbu. Zobrazují se tato data správně? Je potřeba zobrazit ještě něco dalšího? Je to dostatečně intuitivní? Vše jde nesmírně rychle.
Jakmile celou aplikaci vyvinu s mock daty, s Apiary, v AngularJS a v Twitter Bootstrapu, mám již přesně specifikovánou strukturu dat, kterou opravdu potřebuji. Už vím, jak bude vypadat REST API. V tu chvíli pak předám požadavky na grafiku, protože už přesně vím, co a kde se má zobrazovat. Nestane se, že překrásný grafický návrh po implementaci vypadá příšerně. A začnu také dělat serverovou část, což je v podstatě jen překlopení HTTP požadavků na databázi. A vlastně až tady definuji strukturu databáze. A můžu se až tady rozhodnout, jakou databázi použiji, zda to zvládnu s NoSQL a nebo musím použít nějakou SQL databázi. To je přesně opačný způsob než ten, který mi třeba vnucovali na vysoké škole.
Node.js a TypeScript
Na straně serveru jednoznačně preferuji Node.js. Výhoda je třeba ve sdílení kódu mezi klientem a serverem (viz některé příklady v seriálu na Zdrojáku). Zásadní je ale výkon aplikace, což je u Node.js všeobecně známo (třeba příklad s LinkedIn). Minimální nároky na paměť a rychlost zpracování požadavku je pro single-page aplikaci důležitý faktor, protože nepoužiji-li nějakou fasádu, ze SPA budu posílat požadavky na server častěji (dotazuji se na různé zdroje). To je důvod, proč si myslím, že je pro tyto aplikace PHP zcela nevhodné, protože při každém požadavku budu muset neustále dokola načítat všechno znova, což stojí čas (a peníze). V případě Node.js je to pochopitelně jinak.
Protože v čistém JavaScriptu se neprogramuje zrovna jednoduše, používám rád různé jazyky, které se do JavaScriptu kompilují. Dříve jsem měl rád CoffeeScript, ale momentálně mi vyhovuje TypeScript. Kromě kontroly typů vypadá kód také velmi hezky a přehledně. Nicméně je hodně znát, že je to mladý projekt a třeba definice rozhraní v DefinitelyTyped jsou často chybové, i tak ale preferuji raději TypeScript nad CoffeeScriptem či jiným dialektem.
Další výhody
Výše uvedený způsob vývoje má řadu dalších výhod. Např. kešování v případě dotazování na jeden zdroj přes API je mnohem snazší než u klasické aplikace. Třeba onen e-shop, který se vytváří v rámci seriálu na Zdrojáku, bude při dotazech na API (z klientské části) dostávat kešované JSON soubory (budou-li k dispozici), což znamená, že požadavek nedojde ani k Node.js a do databáze už vůbec ne. Vlastně to bude pro drtivou většinu času statický HTML web.
Výborná je také týmová spolupráce, kdy programátor serverové části a klientské části komunikují pomocí Apiary. My máme někdy klienskou i serverovou část v samostatných repozitářích (na serveru se občas místo Node.js použije PHP se špičkovým frameworkem Symfony).
Nevýhody
Tento způsob vývoje se hodí především pro webové aplikace, pro jednoduché webové stránky typu firemní web vhodný není.
O něco složitější je indexace pro vyhledávače. Obvykle se to řeší tak, že v případě příchodu robota na web se pošle vyrenderovaný obsah stránky pomocí nástrojů typu PhantomJS. Single-page aplikace tedy pro vyhledávače přístupné jsou, ale je potřeba podniknout kroky navíc (existují NPM balíčky, které tohle řeší, takže implementace těžká není). Značná část aplikací ale má části, které indexovatelné být nemusí (nemají) a zde se programátor vůbec indexací zabývat nemusí. O klasických administracích, který má každý web, ani nemluvě. A kdyby to stále nevyhovovalo, je možné vytvořit pro vyhledávače pro důležitou část řešení, kdy se ještě na serveru dotazuji na API a výsledek pak pošlu jako kompletní HTML.
Další problém mohou představovat starší prohlížeče. Výše uvedený postup se obvykle praktikuje pro prohlížeče IE8+, podpora starších prohlížečů se nevyplatí.
Pro někoho může být také problém závislost na JavaScriptu. To podle mě ale již dávno problém není, JavaScriptové aplikace nepředstavují handicap a jsou stejně přístupné jako klasické weby.
A tak zbývají pouze uživatelé s úplně vypnutým JavaScriptem. To jsou ovšem uživatelé, kteří ho vypínají vědomě a budou mít problémy na mnoha dalších webech.
Často slyším názor, že aplikace, které nefungují bez JavaScriptu, jsou problematické. Pak následuje argument, že jestliže mám e-shop, tak budu raději, aby fungoval i pro ty, kteří nemají JavaScript, protože si zde pak mohou také nakoupit. S tím však nesouhlasím, protože zbylým 99% uživatelů nabídnu díky SPA mnohem vyšší komfort, rychlejší aplikaci, dosáhnu nižších nákladů na provoz i vývoj atd, což také povede k tomu, že si budou vybírat zboží u mě a nikoliv tam, kde budou na vykreslení stránky čekat několik vteřin.

