Play! 2

Když zavítáme na web Play! Frameworku do očí nás hned udeří celá kanonáda buzzwordů: MVC web framework, lightweight, stateless, web-friendly, minimal resource consumption, highly-scalable, reactive, Iteratee IO, for Scala and Java. Co to všechno znamená a proč právě tyto vlastnosti potřebujeme, vysvětlím na následujících řádcích.

Jednou z hlavních vlastností Play frameworku je jeho kompletní bezstavovost. Díky ní mohou naše aplikace bez problémů horizontálně škálovat – stačí jenom přidávat další servery, stav aplikace je uchováván někde jinde, na místě, které si s ním poradí mnohem lépe. Pro uchování dat mezi HTTP požadavky je k dispozici jednoduchá session. Všechna data, která do ní uložíme se přenášejí v cookies HTTP požadavků. Z toho důvodu může jít jenom o řetězce, které mají nejvýš 4KB, ale to nás nijak zásadně nelimituje. Typicky v cookies přenášíme token nebo ID a všechna data pro danou session jsou uložena někde jinde v distribuované databázi nebo cache.

Další pilíř na kterém Play stojí a který ho odlišuje od mnoha jiných (například servletových) frameworků je kompletní a dokonalá asynchronost a fakt, že nikdy neprovádí blokující operace. HTTP dotaz a následná odpověď nejsou pevně svázány s jedním vláknem. Všechny IO operace se provádějí reaktivně, bez blokování, průběžně jak jsou data k dispozici. V tomto prostředí si vystačíme s velice malým poolem vláken – typicky jedním threadem na jedno procesorové jádro. Nedochází tak k plýtvání prostředků, které by byly jinak obsazeny čekajícími vlákny. Tento přístup je ideální pro servery obsluhující tisíce klientů naráz, real-time aplikace a dlouhotrvající dotazy – věci, které se s nástupem HTML5 a WebSockets stanou běžné.

Asynchronní programování není vůbec jednoduché, ale Play nám dává dvě silné zbraně: na jedné straně samotný jazyk Scala, který je velice expresivní a kompaktní a na druhé straně futures a iteratees.

Future reprezentuje hodnotu, která bude dostupná až někdy v budoucnu. Může jít o výsledek databázového dotazu, volání webové služby, typicky nějaké IO operace. Na future se nikdy nemusí čekat, systém založený na frameworku Akka reaktivně obslouží Future až ve chvíli, kdy je výsledek operace dostupný. Iteratees pak v určitém ohledu zobecňují futures. Iteratee si můžeme představit jako kolekci jejíž jednotlivé elementy budou postupně k dispozici někdy v budoucnu a můžeme je reaktivně zpracovávat jeden po druhém opět bez blokování a čekání.

Play integruje velice mocný framework Akka, jehož systém aktorů, futures a transakční paměti můžeme použit pro asynchronní zpracování, koordinaci a plánování práce na pozadí, rozložení náročných úloh na mnoho serverů a zajištění vysoké dostupnosti aplikace.

Dekonstrukce Play aplikace

Play patří mezi MVC frameworky. Není založen na servletech ani na komponentách (i když ty můžeme do značné míry emulovat), ale na akcích a request/response cyklu. Částečně se tedy podobá například Spring MVC.

Srdcem každé aplikace je routovací tabulka definovaná interním DSL, která slouží k překladu HTTP požadavku na příslušnou akci a naopak. Nemusíme se pak zdržovat s url, která se mohou měnit, ale s logickými akcemi, které jsou mapovány na metody kontrolerů.

Akce jsou místa, kde se teprve začíná dít něco zajímavého. Právě tady se začne vykonávat systémová logika a načítat a zpracovávat data z databází. Akce je v principu obyčejná funkce transformující HTTP dotaz na HTTP odpověď, která může být asynchronní. V takovém případě se využije výše zmíněný mechanismus futures, kdy se odpověď odešle až v okamžiku, kdy jsou všechna potřebná data k dispozici nebo iteratees, která můžou data streamovat přes WebSockets.

Další částí MVC je view neboli šablony. Šablona je opět v jádru obyčejná funkce která transformuje argumenty na vyrenderovanou stránku. Z toho důvodu je testování šablon (stejně jako testování akcí) naprosto triviální. Šabloně stačí předat testovací argumenty a pak sledovat jaký je obsah vyrenderované stránky. Výchozí šablonovací systém je typově bezpečný a je postaven na syntax Scaly. Ale díky tomu, že mají šablony funkcionální povahu, je možné velice jednoduše použít vlastní šablonovací systém.

Stejně přímočarou povahu mají i formuláře, které slouží k transformaci a verifikaci dat přijatých HTTP dotazem na doménové objekty a na zpět.

Hot-reloading

Play se po všech stránkách soustředí na zvýšení produktivity vývojářů. Jednou z největších překážek produktivity je dlouhá doba mezi okamžikem, kdy vývojář provede změnu v kódu nebo v šabloně a kdy uvidí její výsledek. Právě proto Play framework při reloadu stránky provádí automatickou rekompilaci všech změněných souborů (interně jsme tomu začali říkat F5 driven development). A nejde jenom o soubory se Scala a Java kódem (sbt neboli simple build tool hravě zvládá smíšené projekty), ale i definice rout a soubory s šablonami (díky tomu jsou šablony a routy typově bezpečné a kompilátor nás upozorní, když v nich máme chybu). Ale to není všechno. Při reloadu se Coffee Script zkompiluje na Javascript, LESS na CSS a JavaScriptový kód se zkontroluje a minifikuje Google Closure Compilerem.

Batteries included

Play framework obsahuje nástroje pro všechno, co by mohlo být použito při vývoji typické aplikace: anorm pro práci s relačními databázemi, MongoDB driver, cache helpery, funkce pro asynchronní komunikaci s webovými službami. Bohužel klasické JDBC drivery pro SQL databáze jsou z principu blokující, stejně jako přiložený Mongo driver. Naštěstí existují asynchronní drivery pro MySQL, PgSQL, MongoDB, Redis a objevují se další.

K frameworku jsou přibaleny testovací frameworky Specs2 a Selenium, ale je možné použít libovolný jiný testovací nástroj. Unit testy šablon a akcí jsou díky jejich funkcionální povaze velice jednoduché.

Deployment

Pro deployment Play aplikací není potřeba kontejner, protože framework má v sobě zabudovaný server postavený nad Netty. Existuje několik způsobů jak takovou aplikaci nasadit. Nejpraktičtější je pravděpodobně příkaz, který vytvoří archiv s aplikací, serverem, všemi závislostmi a skriptem spouštějícím aplikaci. K nasazení pak stačí jenom archiv zkopírovat, rozbalit a spustit skript. Případně můžeme využít sbt pluginy assemble nebo proguard, které celou aplikaci, server a všechny závislosti zabalí do jednoho spustitelného jar archivu.

Proč právě Play?

Ve frameworku Play můžeme napsat zcela obyčejnou aplikaci, kterou bychom vytvořili v jakémkoli jiném nástroji a jazyku. Ale Play v kombinaci s jazykem Scala má silné stránky, ve kterých exceluje a kde má smysl jej použít: realtime aplikace a škálovatelné aplikace obsluhující miriády klientů. Důkazem toho může být Klout nebo LinkedIn, kteří se s takovými problémy potýkali a rozhodli se použít právě Play.

Článek obsahuje 2 komentáře

  • v6ak

    1
    Pokud se nemýlím, tak při deploymentu přes WAR nejsou některé asynchronní featury, například WebSockets. Ale možná to už změnili.
  • Vlastimil Menčík

    2
    Play 2 už WAR deployment nepodporuje out-of-the box. Existuje na to plugin (https://github.com/dlecan/play2-war-plugin#features). Je tam pěkně vidět, které vlastnosti Play jsou podporované v konkrétní verzi servletové specifikace. S webscokets budete muset počkat na kontejner implementující Servlet spec 3.1, protože autorovi pluginu se určitě nechtělo používat proprietární implementace jednotlivých kontejnerů, ale psal to vůči (vznikajícímu) standardu.