20. prosince 2017

Spring Security, SAML & ADFS: Úvod

Posledních pár týdnů jsem se teď mordoval se Spring Security, abych v grandiózním finále doiteroval k autentikaci pomocí SAML vůči ADFS.

Mimochodem, přijde mi, že poslední dobou, je to se Springem, jako s jakoukoliv jinou (velkou) dominantní značkou - pokud se pohybujete uvnitř dané domény, na vyhrazeném dvorečku, všechno frčí, jak na drátkách. Jakmile to zkusíte zintegrovat s něčím ne-nativním, začnou probémy. A rozlousknout ty problémy chvilku trvá - zvlášť, když StackOverflow mlčí a oficiální dokumentace se k (technologickým) cizincům moc nezná.

Ale to jsem odbočil, zpátky k tématu. Tentokrát se nebudu věnovat ani aktuálnímu use casu, ani těm problémům, ale zaměřím se jen na to, jak Springovský SAML s ADFS funguje a jak to v aplikaci naimplementovat a celkově nakonfigurovat.

Nicméně, pokud jste se ještě stále nechytli, o čem to mluvím a přemýšlíte, jestli číst dál, tak to bude o: lehce komplikované autentikaci webové aplikace oproti Active Directory (takový Microsoftí LDAP).

SAML slovníček

Neuškodí si trochu prosvištět názvosloví. I když SAML nepřináší nic moc převratného, přeci jenom říká určitým věcem svým vlastním způsobem.
  • SAML - Security Assertion Markup Language
  • User Agent (UA) - software, skrz který uživatel komunikuje se zabezpečeným zdrojem, typicky browser.
  • Service Provider (SP) - systém, který poskytuje zabezpečený zdroj a akceptuje authentication assertions a poskytuje Single Sign-On (viz následující body).
  • Identity Provider (IdP) - systém, který vydává authentication assertions a podporuje Single Sign-On.
  • SAML Assertions - assertions jsou gró SAML zpráv, které lítají mezi SP a IdP. Obsahují bezpečnostní informaci/e trojího typu: authentication statements, attribute statements a authorization decision statements. Nás budou zajímat první dva typy: jestli je uživatel autentikovaný a do jakých Active Directory skupin patří.
  • Single Sign-On (SSO) - přihlášení uživatele do více systémů jedinou akcí.
  • Single Logout (SLO) - odhlášení uživatele z více systémů jedinou akcí.
  •  SAML Metadata - XML data formát pro popis specifického SAML deploymentu, tedy SP nebo IdP.

ADFS slovníček

I ADFS má vlastní okruh termínů:
  • ADFS - Active Directory Federation Services
  • Claims - prohlášení týkající se uživatelů, které se primárně používá pro autorizaci přístupu k aplikacím. Claims jsou to, co potřebujeme dostat do SAML assertions jako attribute statements.
  • Claims Provider - systém, který poskytuje claims.
  • Relying Party Trust - partnerský systém, který zpracovává claims a kterému ADFS důvěřuje.
  • Federation Metadata - XML data formát pro výměnu konfigurace mezi Claims Providerem a Relying Party Trust.

SAML Binding

Následující popis SSO a SLO je poměrně detailní (musím se pochválit, že podrobnější jsem nevygoogloval) a je zaměřený na jednu konkrétní technologickou integraci - Spring Security SAML a ADFS. To znamená, že pro jiné konstelace to může fungovat "trošku" jinak.

Rovněž stojí za zmínku, že SAML specifikace definuje tzv. binding, tj. jak jsou SAML requesty a responsy mapovány na standardní message a komunikační protokoly. Pro SSO v browseru se většinou společně používají HTTP Redirect Binding a HTTP POST Binding. V následujících diagramech byste je měli bez problémů identifikovat. Co je podstatné - u tohoto druhu bindingu teče veškerá komunikace přes User Agent (browser), takže tam např. není žádná komunikace na pozadí mezi SP a IdP.

SAML Single Sign-On

Na následujícím obrázku jsem si dal hodně záležet a věřím, že jeho vysvětlující a informační hodnota je enormní, podaná krystalicky čistým způsobem. Přesto si neodpustím kratičké shrnutí:
  1. Browser (UA) přistoupí na chráněný zdroj na Service Providerovi (SP), který přesměruje UA na svoje login URL.
  2. SP vygeneruje SAML request a přesměruje UA na Identity Providera (IdP), kterému je předán SAML request.
  3. IdP vrátí UA přihlašovací formulář (jméno, heslo).
  4. UA pošle IdP credentials uživatele, spolu se SAML requestem.
  5. IdP předá credentials Claims Providerovi (CP), který ověří uživatele a v případě úspěchu vrátí před-konfigurované claims.
  6. IdP přebalí claims do assertions, které obalí do SAML response a tu pak vloží do HTML formuláře, který pošle UA. Součástí formuláře je i JavaScript, který může formulář automaticky odeslat.
  7. UA automaticky odešle formulář se SAML response na SP. V případě, že je v UA vypnutý JavaScript, musí uživatel odeslat formulář klepnutím na tlačítko.
  8. SP ověří přijaté SAML assertions a pokud je všechno v pořádku, přesměruje UA na původně vyžádaný zdroj.

SAML Single Sign-On

Uvedené schéma zobrazuje komunikaci pro ne-autentikovaného uživatele. V případě, že je uživatel již přihlášen - ať už lokálně na daném SP, nebo díky SSO na jakémkoliv jiném SP (který je registrován u daného IdP) - tak se přeskočí posílání a odesílání ADFS login formuláře (a samozřejmě komunikace s CP) a UA rovnou obdrží SAML response.

IdP Discovery

Uvedený scénář se dá zpestřit ještě o jednu věc. Vztah mezi SP a IdP je m:n
  • jeden IdP může obsluhovat několik SP a stejně tak
  • jeden SP si může vybrat z několika IdP.
V prvním případě se nic zvláštního neděje, právě od toho tu je SSO. V druhém případě je to trochu komplikovanější - jak si UA/SP vybere, vůči kterému IdP se autentikovat?

Tenhle případ řeší IdP Discovery. Místo úvodního přesměrování na login URL aktuálního SP dojde k přesměrování na stránku se seznamem všech zaregistrovaných IdP, z nichž si uživatel explicitně vybere.

Nastavit IdP Discovery pomocí Spring Security SAML není nijak složité, nicméně pro tento a následující články s touto možností nepracuji.

SAML Single Logout

Když jsem se pustil do kreslení předešlého diagramu pro SSO, tak se mi výsledek tak zalíbil, že jsem si střihnul ještě jeden obrázek - pro Single Logout (SLO).

A aby to nebylo triviální, tak jsem si rozchodil dva SP, abych mohl zdokumentovat, jak probíhá odhlášení ze všech zaregistrovaných SP. Protože o tom SLO je: když se odhlásím na jednom SP, tak mě to automaticky odhlásí i ze všech ostatních SP.

SAML Single Logout

To be continued...

Abych udržel článek v rozumné čitelnosti, rozhodl jsem se téma rozdělit do krátkého mini-seriálku. Příště bych se podíval, jak vyměnit metadata mezi SP a IdP, plus jak nakonfigurovat ADFS.

V závěrečném díle bych probral konfiguraci Spring Security SAML. Můžete se těšit na popis Java configuration (ofiko dokumentace jede furt na XML) a samozřejmě to pofrčí na aktuálním Spring 5.

Související články


4. prosince 2017

Nešvary logování

Co se týká softwarového vývoje, logování je jedna z nejvíce zanedbávaných oblastí. Samozřejmě, pokud nejde o něco naprosto amatérského, tak je logování v každé aplikaci. Stejně tak, aby člověk pohledal vývojáře, který si během programování nevypisuje na konzoli potřebné runtime informace.

A bohužel, tak jako každý Javista má v CV napsaný Maven, i když umí jen naimportovat projekt do IDE a z příkazové řádky spustit mvn clean install; tak všichni o sto šest logují: chaoticky, nekonzistentně, bez vize, bez přemýšlení. A občas jsou ty logy dost odpudivé smetiště.

Tenhle pocit se ve mně hromadí léta letoucí. A jelikož jsem teď musel refaktorovat pár špatně designovaných a zanedbaných aplikací, rozhodl jsem se k tomu sepsat pár postřehů.

Obecný vývojářský přístup

To, jak se tým chová k logování se dá obvykle shrnout do tří axiomů:
  • Vývojáři si ad hoc logují to, co momentálně potřebují během vývoje aktuální feature. Co se jednou vloží do zdrojáků, to už tam na věky zůstane.
  • Operations/Support si stěžují, že v produkčním logu nejsou relevantní informace, zato spoustu balastu.
  • Kromě kavárenského stěžování si, s tím nikdo nic nedělá.

Situaci může drobně zlepšit, pokud má zákazník, nebo produktový tým definovanou nějakou explicitní logging policy. Daleko častější ale je, že politika logování je buď vágní, nebo žádná. Dá se to popsat i tak, že chybí vize a kontrola, jak logování provádět a používat.

Za dané situace, jsou největšími "viníky" vývojáři, protože jsou to právě oni, kdo do kódu logovací zprávy zanášejí, stejně tak jako je na jejich libovůli jakou severitu zprávám nastaví. Záleží na kontextu, ale někdy/často(?) existuje dokonce "logovací super-padouch"... technical leader, který tuto oblast buď zanedbává, nebo rovnou ignoruje. Je to nejspíš on, kdo by měl způsob logování definovat a kontrolovat.

Ponechme však stranou analýzu "kdo za to může" a pojďme se podívat, jak se špatné logování projevuje.

Špatný mindset

Již jsem naznačil, že za špatný stav logování můžou většinou vývojáři. To není nic překvapivého - jedním ze základních znaků echt vývojáře je, že trpí chronickým tunelovým viděním. U logování se to projevuje tak, že programátoři nepřemýšlí, co se s aplikací stane, jakmile opustí jejich vývojové prostředí.

Ačkoliv aplikace poběží roky na produkci, tak většina logování reflektuje relativně krátkou vývojovou fázi.

Chybějící konvence a postupy

Tohle je obecný problém, který se vyskytne kdykoli mají lidé volnost v zápisu textu zprávy. Kromě logování jsou to typicky commit komentáře. Číst historii je pak (masochistický) požitek, kdy člověk, jako archeolog, prozkoumává hranice lidské kreativity.

"Všechno je relativní", tak proč ne úrovně logování? Každý vývojář dokáže sám, subjektivně a správně posoudit, jaká má být pro danou zprávu severita logování. Trace/Debug/Info, vždyť se to na produkci odfiltruje, tak co?

Co takhle zmapovat flow nějaké entity, jak prochází procesem a systémem? Někdy jo, někdy ne, někdy tohle ID, jindy tamto. Stejně je to všechno "Request ID", bez ohledu na počet requestů, vrstev a systémů. Anebo radši "Session ID", co na tom, že je to bezstavový? "Korelační" je sprosté a zakázané slovo. A vůbec, aby to někdo pochopil, musí na tom pár týdnů/měsíců dělat, takže je jedno, jak se to bude jmenovat.

Nesmyslné logování v testech

Když spustíte testy, viděli byste na konzoli radši takovýhle výpis?
:clean
:compileJava
:processResources
:classes
:compileTestJava
:processTestResources
:testClasses
:test

BUILD SUCCESSFUL in 42s
6 actionable tasks: 6 executed

Nebo byste raději viděli 20 obrazovek balastu, který lítá z logů Hibernate a Spring testů? Předešlý výpis tam samozřejmě bude geniálně ukrytý jak hrst jehel v kupce sena.

Přitom pomoc je triviální - vypněte pro testy logování:


Výpisy na konzoli

Kdo by si čas od času nezahřešil starým dobrým:
System.out.println("Bla bla");
Výpisy na konzoli do logu nepatří. Ani když je to v testech. Samozřejmě, záleží na nastavení vašeho logovacího frameworku - někdy jsou výpisy na sdtout přešměrovaný do logu, někdy ne. Používat by se ale neměly (téměř) nikdy.

Jedinou výjimkou by mohlo být, pokud píšete CLI aplikaci. Ale i tam bych zvážil, jestli místo println nepoužívat logování s vhodným formátem a severitou zprávy. Minimálně to půjde vypnout v testech.

Dedikovaný logger z interního frameworku

Zažili jste někdy, že by si firma vyvíjela vlastní framework? Já už jsem si tím párkrát prošel. Možná jsem jen neměl štěstí... ale pokaždé to byl průser - tam kde vám to 1/3 práce ušetřilo, tam vám to později 2/3 práce přidalo. K internímu frameworku samozřejmě patří custom logger. Jinak by to nebylo ono.

Ona je to vlastně dobrá myšlenka - některé z výše zmíněných problémů by se daly takovým speciálním loggerem podchytit. Bohužel, v realitě to bylo stejně úspešný jak implementace Scrumu v kovaným enterprise-korporátním prostředí. No, možná jsem jen neměl štěstí.

Zapomeňte na custom/interní/proprietární loggery! Vykašlete se na to a použijte vanilla logování svého srdce.

Jak z toho ven?

Tak jako na dovolený poznáte na hned první pohled rozdíl mezi rozvinutou a rozvojovou zemí, tak u funkčních aplikací poznáte, jestli někdo přemýšlel i kousek za kompilaci kódů. Pročetli jste si někdy logovací zprávy když vám startuje čistý aplikační server, nebo rozumný buildovací nástroj (ne, Maven to není)?

Zkuste někdy taky psát takové pěkné logy. Chce to jenom:
  • Mít vizi, jak má logování vypadat.
  • Dělat code review.
  • Čas od času udělat na logování audit.

Jaký je váš oblíbený logovací nešvar?

13. listopadu 2017

vimdiff, nástroj drsňáků


Musím se vám k něčemu přiznat... Už patnáct let je Vim můj nejoblíbenější textový editor. A občas, čas od času, i hlavní nástroj na programování.

Umím si poeditovat vimrc, který po léta udržuju a vylepšuju. Dokonce jsem se i naučil trochu Vim script/VimL a napsal dva zanedbatelné a nedotažené pluginy (pro Gradle a WSDL).

Ale vždycky jsem se jako čert kříži vyhýbal jedné věci - používání vimdiff. Nicméně na každého jednou dojde. Z určitých (pro článek nepodstatných) důvodů jsem si nemohl pro nové vývojové prostředí nastavit P4Merge a tak jsem vstoupil do zapovězené komnaty.

Disclaimer: Tenhle článek píšu jako shrnutí toho, jak jsem práci s vimdiff pochopil. Pokud máte víc zkušeností, budu rád, když se podělíte v komentářích.

2-way merge

Nejjednodušší způsob, jak používat vimdiff - pokud pomineme, že umí dělat i "plain old" diff - je 2-way merge: máme vedle sebe dvě okna se zvýrazněnými rozdíly a chceme mezi nimi tyto změny propagovat.

vimdiff, 2-way merge

Stav na předešlém obrázku, který je výchozí pro merge, se dá dosáhnout několika způsoby:
  • Příkazem: vimdiff myFile.txt theirFile.txt
  • Příkazem: vim -d myFile.txt theirFile.txt
  • Kombinací příkazů:
    • vim myFile.txt
    • :diffsplit theirFile.txt
  • Kombinací příkazů
    • vim -O myFile.txt theirFile.txt (vsplit obou souborů)
    • :diffthis (zapne diff na aktuálním bufferu)
    • Ctrl-W Ctrl-W (skok do druhého bufferu)
    • :diffthis(zapne diff v druhém bufferu)

Základní příkazy

Tak, diff máme zobrazený, co s ním? První věc - je potřeba se v diffu umět pohybovat. Kromě toho, že můžete použít jakýkoli skok, který znáte z běžného Vimu, jsou tu dva příkazy, které umožňují skákat po jednotlivých rozdílech:
  • ]c skočí na následující diff
  • [c skočí na předcházející diff

Za druhé - chceme propagovat změny z/do aktuálního bufferu: skočíme na diff, který chceme upravit a:
  • do, nebo :diffget natáhne změny z "druhého" bufferu do toho aktuálního.
  • dp, nebo :diffput propaguje změny z aktuálního bufferu do "toho druhého".

Za třetí - změny uložíme. Kromě příkazů na standardní ukládání (:w, ZZ atd.) se může hodit:
  • :only zavře všechny ostatní buffery kromě toho aktuálního
  • :qall zavře všechny otevřené buffery
  • :only | wq zavře ostatní buffery + uloží stávající + ukončí Vim. Cool!

Eventuálně začtvrté - pokud věci nejdou hladce, může se šiknout:
  • :diffupdate znovu proskenuje a překreslí rozdíly (u komplikovanějších mergů nemusí Vim správně pochopit danou změnu)
  • :set wrap nastavení zalamování řádků (hodí se při velmi dlouhých řádcích, typicky některá XML)
  • zo/zc otevře/zavře skryté (folded) řádky

3-way merge

Nemusím vám říkat, že 2-way merge je pro školáky - profíci makaj v Gitu, či v Mercurialu a tam je dvoucestný merge nedostačující. Ke slovu přichází 3-way merge. Co to je?

Schéma 3-way merge

3-way merge není nic složitého. V podstatě jde o to, že máme dvě verze, které mají společného předka. V mergovacím nástroji pak vidíme všechny tři verze vedle sebe a většinou máme k dispozici ještě čtvrté okno s aktuálním výsledkem merge.

3-way merge v aplikaci


Nastavení Gitu

Nastavení spolupráce Gitu a vimdiff je jednoduché - stačí spustit z příkazové řádky následující sadu příkazů:
$ git config --global merge.tool vimdiff
$ git config --global merge.conflictstyle diff3
$ git config --global mergetool.prompt false
$ git config --global mergetool.keepBackup false

Pokud se podíváte do ~/.gitconfig, měli byste tam vidět:


Nastavení Mercurialu

Nastavení Mercurialu je podobně jednoduché. Otevřeme soubor ~/.hgrc příkazem
$ hg config --edit
a vložíme následující řádky


Sekce [extensions] a [extdiff] nejsou pro merge nutné, ale hodí se, pokud chceme vimdiff používat jako dodatečný externí diff nástroj. Sekundární diff spustíme příkazem hg vimdiff.

Základní příkazy

Základní příkazy jsou stejné jako v sekci 2-way merge, s výjimkou příkazů dp/do (:diffput/:diffget) - pokud bychom je nyní použili, vimdiff nám zahlásí chybu:
More than two buffers in diff mode, don't know which one to use
To je v pořádku: u 3-way merge se ve vimdiff otevřou 4 buffery, všechny v diff módu. Takže do té doby, než se vimdiff naučí komunikovat telepaticky, je potřeba mu říct, ze kterého bufferu chceme danou změnu natáhnout.

vimdiff, 3-way merge v Gitu

Klasické merge flow vypadá následovně:
  1. Začínáme v dolním "výsledkovém" bufferu.
  2. ]c (skočit na následující diff, který chceme mergovat)
  3. :diffget <identifikace-bufferu> získáme změnu z daného bufferu (viz dále)
  4. Opakujeme 2-3.
  5. :only | wq uložíme merge.

Obecně, identifikátor bufferu získáme příkazem :ls. To je ale dost nepraktické a nepřehledné. Další možnost je identifikovat buffer částečným názvem souboru. Tady přichází na pomoc jak Git, tak Mercurial, který přidávají k názvům souborů příhodný suffix.

Merge v Gitu

Git přidává do názvů mergovaných souborů následující suffixy, v pořadí zleva doprava: LOCAL (vlevo), BASE (uprostřed), REMOTE (vpravo). Pro natažení změny z (levého) bufferu LOCAL můžeme použít příkaz :diffg LO.

Výpis bufferů pro Git:
:ls
  1 #a   "./myFile_LOCAL_7424.txt"      line 1
  2  a   "./myFile_BASE_7424.txt"       line 0
  3  a   "./myFile_REMOTE_7424.txt"     line 0
  4 %a   "myFile.txt"                   line 12

Merge v Mercurialu


vimdiff, 3-way merge v Mercurialu

Mercurial přidává do názvů mergovaných souborů následující suffixy, v pořadí zleva doprava: orig (vlevo), base (uprostřed), other (vpravo). Pro natažení změny z (levého) bufferu orig můžeme použít příkaz :diffg orig.

Výpis bufferů pro Mercurial:
:ls
  1 %a   "myFile.txt"                   line 2
  2  a-  "myFile.txt.orig"              line 0
  3  a-  "/tmp/myFile.txt~base.iZwwuA"  line 0
  4  a-  "/tmp/myFile.txt~other.km9Itr" line 0

Co mi (zatím) schází?

Musím říct, že potom, co jsem si vimdiff osahal, pochopil jeho logiku a naučil se jeho příkazy, jsem si ho docela oblíbil.

Jediná výtka zatím jde za jeho neschopností skákat přímo po konfliktech - Git i Mercurial dělají výborně automatické merge a ty jsou samozřejmě vidět ve vimdiffu taky, jako pouhá změna bez konfliktu. Mít nějaký příkaz, který rozlišuje pouhý diff a konflikt, by bylo fajn.

Související články


1. listopadu 2017

Trampoty s JUnit 5

Poslední dobou jsem nepsal moc unit testy... v Javě. Jednak jsem posledního půl roku hodně prototypoval - a tam moc testů nenapíšete - a když už jsem testy psal, tak to bylo převážně ve Scale, nebo v Clojure.

Teď ale naše firma projevila sklony k evoluci, se snahou trochu více zautomatizovat vytváření prostředí a zakládání projektů. Sice to jde mimo mě, ale když jsem byl požádán, ať napíšu testovací projekty v Javě pro Gradle a Maven, chopil jsem se příležitosti a ponořil se do (povrchního) studia JUnit 5.

Vyznání

Obecně musím říct, že pro JUnit mám slabost - začal jsem ho používat na začátku své Java kariéry ve verzi 4.2 (pro pamětníky únor 2007) a tak vlastně celý můj Java-produktivní věk jsem strávil se čtyřkovou verzí. Naučilo mě to hodně - za to, že jsem dnes takový skvělý programátor (ha, ha, ha) vděčím tomu, že mě unit testy naučily psát dobrý design.

Samozřejmě jsem si k tomu občas něco přibral. Už v roce 2008 jsem si mistrně osvojil (tehdy progresivní) jMock 2 a naplno se oddával neřesti BDD. Taktéž TestNG jsem si na pár projektech zkusil. Ale gravitační síla tradičního JUnit a TDD mě vždy přivedla zpátky.

A teď zažívám něco jako déjà vu. Je to podobný, jako když přišla Java 5 - skoro všechny nástroje s tím mají menší nebo větší problém. Java komunita to ještě moc neadaptovala. Když narazíte na problém, StackOverflow často nepomůže. Atd.


Pár aktuálních problémů JUnit 5 se mi podařilo vyřešit ke své spokojenosti. Tady je máte na stříbrném podnose.

Zadání

Zadání, které jsem dostal, bylo triviální - napsat miniaturní Java projekt, buildovatelný Gradlem a Mavenem, který bude mít unit testy. Projekt se bude buildovat na Jenkinsu, potřebuje změřit pokrytí testy pomocí JaCoCo a projít statickou analýzou kódu na SonarQube.

Jak říkám, bylo by to triviální, kdybych si pro testy nevybral JUnit 5.

Gradle

Odpírači pokroku a milovníci XML se mnou nebudou souhlasit, ale já považuju Gradle za základ moderní automatizace na JVM. Včetně (a primárně) buildů. Jak tedy zkrotit Gradle, aby se kamarádil s JUnit 5?

Zatím jsem se v tom nějak moc nevrtal, pač nemám ambice se stát JUnit 5 guru, jen potřebuju běžící testy. Ale je dobré vědět, že:
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage (JUnit 5 User Guide)
JUnit Vintage je pro JUnit 4, což nás dnes nezajímá. Zbývá tedy JUnit Platform pro spouštění unit testů a JUnit Jupiter pro samotné psaní testů.

Protože JUnit 5 změnilo pravidla hry, nestačí do Gradlu jenom přidat závislosti - současný Gradle novým unit testům nerozumí a zůstaly by nepovšimnuty. Naštěstí je k dispozici je nový plugin, který přidá do build life-cyclu nový task junitPlatformTest a který umí testy spustit.

Bohužel, plugin ještě pořád není dostupný na Gradle Plugins Portal, ale jen v Maven Central. Tím pádem se zatím nedá použít Plugins DSL :-(

V následujícím minimalistickém Gradle skriptu si povšimněte různých konfigurací pro jednotlivé závislosti:
  • testCompile pro api
  • testRuntime pro engine.


Závislost apigurdian-api je optional a je tam jenom proto, aby se ve výstupu nevypisovalo varování:
warning: unknown enum constant Status.STABLE
    reason: class file for org.apiguardian.api.API$Status not found

Task juPlTe je "zahákovaný" na standardní test task, který se dá použít také.

Spuštění JUnit 5 testů Gradlem

Jedna z killer feature Gradlu je incremental build - pokud nešáhnete na produkční kód, nebo na testy, Gradle testy nespouští. Je prostě chytrej ;-)

Gradle incremental build přeskočí testy, pokukd se kód nezměnil


Maven

Tradicionalisti milují Maven a protože jsem shovívavý lidumil, podělím se i o toto nastavení. Pro Maven platí totéž, co pro Gradle:
  • nový plugin (přesněji Surfire provider)
  • závislost na api a engine v různém scopu


Velký rozdíl mezi Mavenem a Gradlem je, že Maven incremental build (moc dobře) neumí - tupě spouští testy, kdykoliv mu řeknete.

Spuštění JUnit 5 testů Gradlem


JaCoCo pokrytí testy

Zbuildovat a spustit JUnit 5 testy byla ta jednodušší část. S čím jsem se trochu potrápil a chvilku jsem to ladil, bylo pokrytí testy. Vybral jsem JaCoCo, protože mi vždycky přišlo progresivnější, než Cobertura (jen takový pocit, či preference).

Dále budu uvádět jen nastavení pro Gradle, protože Maven je hrozně ukecaný. Pokud vás ale Maven (ještě pořád) zajímá, podívejte se do pom.xml v projektové repository.

Zkrácená JaCoCo konfigurace vypadá takto:


V předešlém výpisu jsou podstatné tři věci: (1) generování JaCoCo destination file je svázáno s taskem junitPlatformTest. (2) Definujeme název destination file. Název může být libovolný, ale aby fungovalo generování JaCoCo reportů, je potřeba, aby se soubor jmenoval test.exec. A za (3), pokud chceme některé soubory z reportu exkludovat, dá se to udělat trochu obskurně přes life-cycle metodu afterEvaluate. (Tohle by chtělo ještě doladit.)

JaCoCo pokrytí testy


SonarQube statická analýza

Sonar vlastně s JUnit nesouvisí. Pokrytí testy už máme přece vyřešeno. No, uvádím to proto, že opět je potřeba jít tomu štěstíčku trochu naproti.

Zkrácená verze Sonar konfigurace je následující (Maven opět hledejte v repo):


Tady jsou důležité dvě věci: (1) říct Sonaru, kde má hledat coverage report (klíč sonar.jacoco.reportPath) a za (2) naznačit, co má Sonar z coverage ignorovat (sonar.coverage.exclusions) - bohužel, JaCoCo exkluduje jenom z reportu, v destination file je všechno a tak to Sonaru musíte říct ještě jednou.

SonarQube statická analýza


Má smysl migrovat?

Jak je vidět, popsal jsem spoustu papíru, není to úplně easy peasy. A tak se nabízí hamletovská otázka: má smysl upgradovat z JUnit 4 na verzi 5?


Výše už jsem zmínil velmi přesnou analogii s Javou 5. Tehdy šlo hlavně o anotace a generické kolekce. Můj povrchní dojem je, že u JUnit 5 může být tahákem Java 8 (na nižších verzích Javy to neběží), takže primárně lambdy a streamy.

Pokud máte stávající code base slušně pokrytou pomocí JUnit 4, tak se migrace nevyplatí. Protože ale JUnit 5 umí (pomocí JUnitPlatform runneru) spouštět obě verze simultánně, je možné na verzi 5 přecházet inkremenálně.

Projekt repository

Na Bitbucket jsem nahrál repozitory jednoduchého projektu, kde si můžete v Gradlu a v Mavenu spustit JUnit 5 testy, vygenerovat JaCoCo report a publikovat výsledek do SonarQube.

16. října 2017

1:1, nejdůležitější nástroj team leadera

Říká se tomu one-on-one. V psané podobě můžete narazit na zápis OoO, O-o-O, 1on1 a různé další. Já používám 1:1, ale kreativitě se meze nekladou.

Za ta léta, co dělám team leadera, jsem se setkal s širokou paletou lidí a jejich zkušeností s 1:1. Jsou tací, kteří 1:1 nikdy neměli a někdy o něm dokonce ani neslyšeli. Jsou lidi, pro které je to jenom takový "manažment folklór". A pak je menšina těch, kteří 1:1 očekávají a vyžadují.

Jak už jsem psal v minulém článku (Technical Leader, mytické stvoření), potřebuju uzavřít určité období a shrnout, co jsem se naučil. Tady je moje moudro:
"Hlavním nástrojem vývojáře je IDE. Hlavním nástrojem Technical Leadera je Issue Tracking System. A hlavním nástrojem Team Leadera je 1:1." ~ SoftWare Samuraj

Můj příběh

Když jsem před nějakými osmi lety začal zvolna aspirovat na roli team leadera (ano, bylo to ještě předtím, než jsem začal psát tenhle blog), šel jsem na to svou obvyklou cestou, která se dá shrnout do tří slov: internet, knihy, praxe.

Hodně mi pomohl Michael Lopp, píšící blog Rands in Repose. Jeho nejlepší články tehdy vyšly v inspirativní knížce Managing Humans, na kterou mě upozornil na svém blogu Lukáš Křečan (jak to ten chlap dělá, že je vždycky o pár kroků přede mnou?).

Já sám jsem do té doby nikdy žádné pravidelné 1:1 neměl, jen takové to klasické performance review. Proto mě šokovalo, že bych měl organizovat 1:1 na týdenní bázi - neuměl jsem si to představit.

V té době jsem v někdejší firmě převzal/zdědil Java kompetenci. V reálu to znamenalo, že všichni seniornější Javisti už z firmy odešli. Nebylo od koho se učit, tak jsem si roli definoval sám. Naplánoval jsem si s klukama semestrální 1:1 a protože byli rozeseti na projektech po celé Praze, chodil jsem tam za nima.

Dalším milníkem bylo angažmá, kde došlo k nepřátelskému převzetí projektu (lehce jsem se tématu dotknul v článku (Ne)funkční tým). Pořád ještě jako juniorní team leader jsem bojoval, jak to šlo, podle svých tehdejších schopností. Jedna z věcí, které jsem zkusil a která byla dobrým krokem, bylo zavedení 1:1. Scházeli jsme se jednou za 1/4 roku.

A pak přišel další projekt - dostal jsem v kulminaci nálož 16 lidí (naštěstí to rostlo postupně). Opět jsem sáhl po knize (článek Management za zavřenými dveřmi) a opět jsem zredukoval periodu - scházeli jsme se na 1:1 jednou za měsíc.

   

Ano, už to přijde. Pointa. Ale tentokrát bez knihy. Když jsem nastupoval do nové práce, měl jsem neobvyklý luxus - mohl jsem si postavit svůj vlastní tým, úplně od začátku. S tímhle novým týmem jsem začal dělat to, co se všude radí bez výjimky - týdenní 1:1. Dělám to tak už téměř pět let a můžu jen konstatovat, že 1:1 je ten nejdůležitější nástroj, který team leader má.

Vize, benefit, smysl

1:1 je nástroj. Je to nástroj používaný mezi dvěma entitatmi - mezi team leaderem a členem týmu, ev. mezi manažerem a reportujícím. Aspektů, které tento nástroj může přinést je mnoho, ale já bych vypíchnul čtyři, které považuji za nejhodnotnější.
  • 1:1 je silný nástroj pro vytváření vztahu mezi team leaderem a členem týmu.
  • 1:1 kritický nástroj pro budování důvěry.
  • 1:1 je také nástroj na vytváření a ovlivňování týmové kultury.
  • A 1:1 je prostor a čas, který team leader dedikuje svým lidem.

Nejkritičtějším elementem je budování důvěry - pokud ve vztahu chybí důvěra, je těch benefitů jenom polovina (a míň).

Pravidla

Každý si umí představit analogii s autem, které potřebuje pravidelný servis, aby dobře fungovalo. Pokud ho zanedbáte (nebo už se to nevyplatí), tak se to nějak promítne, nastřádá. O 1:1 to platí také. A možná i víc, protože lidi nejsou stroje. Tady je pár pravidel, která vám můžou pomoct udržet 1:1 v dobrém stavu.

Pravidelnost

Běháte? Chcete uměhnout maraton (5k, 10k, 1/2 maraton)? Je potřeba, abyste pravidelně trénovali. Učíte se cizí jazyk? Je potřeba, abyste ho pravidelně procvičovali. Učíte se nový programovací jazyk/framework/technologii? Je potřeba je pravidelně používat. Jinak to nemá moc smysl a přínos je malý.

S 1:1 je to stejný. Jak říkal soudruh Lenin: pravidelnost, pravidelnost, pravidelnost. Rytmus je benefitem i podpůrnou konstrukcí.

Nezrušitelnost

Nikdy 1:1 nerušte. Nastavte si to jako železné pravidlo - jestli jste team leader, 1:1 je důležitejší než jakýkoli projekt. Projekt skončí, lidi vám zůstanou.

Když říkám nikdy, jsem si vědom absolutnosti toho slova. Já sám se snažím pít vodu, když kážu víno. Snažím se tomu ideálu aspoň přiblížit. Osobně to mám nastavené tak, že 1:1 ruším jenom když jsem (a) nemocný, (b) na dovolený, (c) na služební cestě. Pokud se něco kritického vyskytne v práci, snažím se 1:1 místo zrušení aspoň přeplánovat.

Rušení 1:1 má ještě jeden důležitý aspekt, ke kterému se vrátím v sekci Doporučení.

Respekt a vychování

Ono to přímo vyplývá ze zmíněného axiomu, že 1:1 je nástroj na vytváření vztahu - chovejte se ke členům svého týmu s respektem. Kromě běžné sociální slušnosti, bych vypíchnul reakci na vyrušení.

Na 1:1 neberte nikomu telefon. Nekontrolujte zprávy. Zdvořile odražte osobní vyrušení. Pokud vaše žena nejede do porodnice, tak vás nic neomlouvá, že se nevěnujete na 100 % člověku, kterého máte před sebou.

Mě když volá žena během 1:1 schůzky... típnu jí telefon. A zavolám potom. Když mi během 1:1 volá šéf, nezvednu mu to. Když šéf během schůzky vpadne do místnosti, řeknu že mám 1:1 a zastavím se potom. Za prvý jsem v právu a za druhý, je to slušnost.

Naslouchejte

Lidé ve vedoucích rolích mají často nepříjemný zlozvyk: moc mluví. I já - jako introvert - tím dost trpím a musím si to neustále (už po léta) připomínat. Někdy se mi to i daří. Naslouchejte. Poslouchejte, co vám kolegové chtějí říct. Když už máte jejich důvěru, tak ji nezahoďte.

Technology free

Předpokládám, že tohle hodně lidí šmahem odmítne, ale stejně to řeknu. Na 1:1 choďte bez technologií. Poznámky si pište na papír. Psát si během 1:1 na počítači - s libovonými bohulibými úmysly - je nevychované a neosobní. Pamatujete? Respekt a budování vztahu.

Pokud opravdu potřebujete mít vaše poznámky archivované na počítači, je to jenom vaše pohodlnost, co snižuje kvalitu komunikace.

Samozřejmě, pokud potřebujete svému kolegovi něco na počítači ukázat, je to v pořádku. Pokud ale před ním frontálně sedíte s počítačem před sebou, je to chucpe.

Obsah

Lidé, kteří se setkávají s 1:1 poprvé, můžou váhat, co je obsahem. Samozřejmě, je to primárně pracovní záležitost. Ale je v pořádku probírat i osobní a rodiné záležitosti. Jak tedy obsah 1:1 definovat?

Ještě než se přesunu k lehce konkrétním bodům, zmíním dva stěžejní principy:
  1. Nechte své kolegy spolu-vytvářet obsah 1:1. Ono i když se podíváte na ten zápis - 1:1 - mělo by to evokovat fifty-fifty, či win-win. Jsou věci, o kterých nemáte ani tušení, že by je vaši členové týmu chtěli řešit.
  2. Přizpůsobte 1:1 každemu člověku. Lidé jsou různí - mají různé povahy, senioritu, externí a životní zkušenosti, sociální a rodinný status. Můžou pocházet z jiných kultur a světadílů. Respektujte to a reflektujte to.

Pracovní témata

Pracovním tématem číslo jedna jsou problémy. Technologické problémy, projektové problémy, problémy ve vztazích v práci. To je to, co vaše lidi nejvíc trápí. Externí záležitosti vyřešit nemůžete, ale můžete aspoň svého kolegu vyslechnout a nabídnout empatii.

Interní problémy jsou dvojího druhu - ty, které daný člověk může vyřešit sám. Možná mu k tomu chybí odvaha, možná neví jak, možná jen potřebuje cítit vaši podporu. A pak interní problémy, které on vyřešit nemůže, ale můžete je vyřešit vy... protože jste (jeho) team leader. Tohle výživné téma by vydalo nejméně na článek - klíčové slovo: coaching.

Tématem číslo dva jsou úšpěchy. I drobné. Co se vašemu kolegovi povedlo? V čem se zlepšil? Co se naučil? Není u toho potřeba používat vyprázdněné superlativy, méně je více. Ale nemělo by to zapadnout.

Téma číslo tři: rozvoj. Co dělá váš kolega navíc, nad rámec "daily job"? Čte knihy? Zajímavý článek na internetu? Osobní projekt? Samozřejmě sem spadají i školení a podobné věci, i když ty se neplánují každý týden.

Téma číslo čtyři (záměrně není v TOP 3): něco jako "mikro-status". Záleží na kontextu. Pokud kolegu potkáváte na denním standupu, asi to nebude tak podstatný, možná i zbytečný. Pokud dělá na jiném projektu, hodí se vědět, jak vypadá aktuální projektový/technologický "snaphot". Bacha na micro-management!

Osobní témata

Asi je jasný, co se tím míní. Rozsah a hloubka se budou lišit od kvality vztrahu a míry důvěry. Já si běžně se členy týmu povídám o sportu, dovolený, rodině, koníčkách apod. Jde hlavně o to, co jste ochotni prozradit vy. (Jenom to nepřežeňte.)
"The most important action that a leader must take to encourage the building of trust on a team is to demonstrate vulnerability first." ~ Patrick Lencioni

Doporučení

Na závěr ještě pár doporučení, která rozvíjejí témata, která už zazněla.

Pokud vše dobře půjde, budete mít 1:1 s daným člověkem léta. Jak váš vzájemný vztah, tak vaše 1:1 by se mělo vyvíjet. Neupadněte do rutiny. Adaptujte (se). Změňte vaše individualizované 1:1 tak, aby to stále byl oboustranně prospěšný nástroj.

Jak už jsem naťuknul - neřešte problémy vašich lidí za každou cenu. Buďte umírnění a nechte je vyřešit maximum problémů, které zvládnou sami. Podpořte je, když selžou. Bez chyb není učení.

Vyhraďte si na 1:1 poznámky dedikovaný sešit. Budete mít historii na jednom místě.

A zlaté doporučení. Pokud vaši lidé odcházejí (z firmy) - stává se to - nerušte jim 1:1, ale pokračujte s nimi až do konce. Ukážete jim, že vám na nich i tak pořád záleží. V opačném případě budou mít pocit, že jste je hodili přes palubu.

Mind Map



Související články


3. října 2017

Technical Leader, mytické stvoření

tl;dr Pokud vás téma zajímá, ale nechce se vám číst dlouhý článek, skočte na sekci Model. Nic jiného číst nepotřebujete ;-)

Into the woods

Jak už jsem letos párkrát zmiňoval, procházím určitým přelomovým obdobím, jehož vedlejším, či hlavním(?) důsledkem je, že opouštím vyšlapané cesty. Prostě jsem si koupil bare-foot boty a sešel z dlážděných cest na trávu a lesní pěšiny.

Není to ale žádné pálení mostů. Jsem za tu cestu, kterou jsem urazil, vděčný a hodně jsem se na ní naučil. A abych mohl tenhle úsek putování uzavřít, rád bych se podělil ještě o několik témat, která do budoucna opouštím. Můj náhled, co to je technical leader, je jedním z nich.

Obiter dictum

Jako formální i neformální technical leader jsem pracoval řadu posledních let - v různém prostředí, pro různé zaměstnavatele, s různými týmy. Také jsem o této doméně hodně četl. Byla to role, která mne neskutečně bavila a ve které jsem se chtěl kontinuálně zlepšovat. Snad se mi to i dařilo.

Zároveň jsem viděl, jak lidé v mém blízkém a občas i (velmi) vzdáleném okolí tápou. Co by mělo být obsahem té role? Jak se mám naučit potřebné věci?

A občas jsem také viděl, jak měli lidé ambici stát se formálním technical leaderem, aniž by tušili co to obnáší a hrnuli se do toho s pouhými romantickými představami a vidinou nově deklarovaného statusu a finančních benefitů.

Kromě toho, že jsem sám v této roli pracoval, jsem i pár technical leaderů vychoval. No, vychoval - řekněme, že jsem jim nestál v cestě (ale to už je jiný příběh).

Takže i když vím, že "tam venku" existují lepší technical leadeři, než jsem já, cítím se trochu povolaný sdílet pár informací a osobních názorů. Už proto, že o tom nikdo moc nepíše. (A pár jednorožců už jsem viděl.)

Model

K roli technical leadera můžete mířit z jakékoli jiné technické role. Pro potřebu tohoto článku budeme vycházet z pozice vývojáře, ale můžete si za něj dosadit "obecného" (či specifického) SW Engineera.

Výchozím bodem by měl být vývojář, který je "rozumně" seniorní. Co znamená ono rozumně, nechám na vašem zdravém rozumnu ;-) Povýšení juniorního člověka na technical leadera nedává moc smysl.

K tomu, aby se člověk stal technical leaderem, musí mít, kromě svého ústředního skillu, ještě nějaký přesah. Co jsem za ty roky vypozoroval, je to většinou přesah do jedné ze tří oblastí: architektura, project management a team leading. A podobně jako u technical leadingu, mohou být tyto oblasti formální i neformální.


tl;dr Pokud jste rychločtenáři, můžete nyní přeskočit na sekci Gotický svorník (model re-visited). Pak už je to opravdu všechno :-P

Developer

Jedním z méně častých, i když také možných typů technical leadedra, je vývojář, který sice nemá přesah do výše naznačených oblastí, ale který má velmi hluboké znalosti své technické domény. Je to ten tzv. guru (trošku devalvované slovo, což?). Ale nejenom to - je také problem-solver a mentor. Umí vyřešit nejen své technické problémy, ale i svých kolegů a zároveň jim dát do "své" technologie potřebný vhled.

Uvádím tenhle typ jen pro úplnost. Většinou je zde někdy tenká, někdy hodně široká a rozmazaná hranice mezi velmi seniorním člověkem a "opravdovým" technical leaderem. Osobně jsem takových moc nepotkal. Ale je to validní cesta, pokud se necítíte povoláni k ostatním typům přesahů.

Architekt

Přesah do architektury je s přibývající senioritou běžný. Jako seniorní vývojář chcete vystrčit hlavu z písku své technické domény a podívat se, co se děje u souseda na dvoře. Časem si možná uvědomíte že mezi vaším (vývojářským) a sousedovým dvorem (architektura) není žádný plot. Jsou to dvě plochy téhož tělesa.

Jako technical leader s přesahem do architektury je vhodné umět navrhnout architekturu a zároveň ji zvládnout kompletně naimplementovat. Nikdy byste neměli z pusy vypustit ohavnou větičku, že něco je "implementační detail". To nechte ivory-tower architektům.

Je vhodné vidět daný software v celosti jeho life-cyclu. Nemít klapky na očích a nesoustředit se jen na aktuální (a nejzajímavější) vývojovou fázi. Jak například vypadají vaše logy? Budou sloužit jen pár měsíců vývojářům, nebo budou supportu/operations pomáhat roky na produkci?

Ovšem, není to jen o vás - je potřeba umět vysvětlit vaše návrhy svým méně seniorním kolegům a také jim pomoci s úseky, které jsou nad jejich síly (technicky, designově, myšlenkově).

Projekt Manager

Často se setkávám s tím, že vývojáři vlastně neví, za co je platí. Že dostávají peníze za to, že (efektivně) vyřeší nějaký business problém. To je věc, kterou si velmi dobře uvědomuje project manager - zná finanční rozměr projektu a měl by mít plán, jak to zvládnout.

Jako technical leader s přesahem do project managementu je vhodné umět sestavit implementační plán (v libovolné vyhovující formě). Naplánovat iteraci. Prioritizovat. Zvážit smysluplnost investovaného úsilí. Seřadit a spravovat časové slouslednosti - aby si vývojáři s tunelovým viděním nestěžovali, že je "něco" blokuje.

A také umět předvídat, odhalovat a mitigovat rizika. Umět řešit a případně eskalovat problémy: chybějící lidi, externí závislosti, nečekané události. Navrhnout a řídit vývojovou metodologii a umět ji podle kontextu modifikovat a přizpůsobit.

Team Leader

Team leader a technical leader jsou často překrývající se, nebo zaměňované pojmy. Temínem team leader zde myslím toho, kdo pracuje s lidmi, vede tým a má za něj zodpovědnost.

Jako technical leader s přesahem do team leadingu je vhodné... vést lidi. Komunikovat se svým týmem. Řešit jeho problémy a objevovat příležitosti. Mít individuální přístup k jeho členům - každý z nich je originál. Vystupovat jako facilitátor.

A nejpodstatnější věc - mít vizi a udržovat týmovou kulturu. Působit preventivně proti bad apples. Vytvořit dobře promazaný stroj, který vyhraje softwarové play-off.

Budu k vám upřímný. Tenhle přesah je ze všech nejtěžší a nejvíc adeptů na něm ztroskotá. Jde o to, se nepoložit a pokračovat. Zkusit to znova, až to půjde. Ono to půjde.

Gotický svorník (model re-visited)

V předšlých sekcích jsme naznačili možné přesahy, které může technical leader mít, kromě svého core-skillu. Někdy má přesah jen do jedné z těchto oblastí, někdy do dvou. Nejcennější ale je, pokud má přesah do všech tří domén a působí tak jako svorník klenby, která z těchto pilířů vyrůstá.


V reálním světě měnících se potřeb a požadavků, se ty přesahy budou organicky měnit a přelévat, někdy i během krátké doby (jednoho projektu). I když ale daný skill není zrovna potřeba, pořád obohacuje všechny zbývající aspekty.

Technical... Leader

Většina adeptů na technical leadera se soustředí na to první slovo v názvu role. Ale to druhé slovo - leader - tam není náhodně. Osobně bych řekl, že tenhle aspekt je v celkovém přínosu a smyslu ten důležitější. Protože technical leader, který není leader je jenom seniorní vývojář.

Důvod, proč je tato druhá složka opomíjená, je celkem prostý - techničtí lidé z ní mají obavy. Jak se stanu leaderem? Všichni uvidí, že to neumím! A tak se soustředí na to, co už dobře znají... technologie. Komfortní bublina. A možná tak trochu čekají, že ty věci kolem leadershipu, tak nějak přijdou samy. Snesou se z modrého nebe jako vavřínový věnec nesený holubicemi...

Ale něco vám řeknu: vy už jste se jako seniorn vývojáři narodili? Že ne? Že to trvalo léta praxe a učení se? Jasně, jasně. Prozradím vám tajemství: nic jako "natural born leader" neexistuje! Vede k němu úplně ta samá cesta, jakou jste už sami ušli. Zadejte si do Googlu heslo natural born leader a budete vědět, na čem ještě potřebujete pracovat. Většinou je to práce na celý život. Ale někdy se začít musí.

Jediná cesta?

Samozřejmě, že role technical leadera má mnoho podob. Kdybychom chtěli pokračovat v naznačeném modelu, mohli bychom přidat jako další oblast přesahu například business analýzu. Nebo QA. Nebo... Anebo modelovat/definovat tuhle měňavou roli úplně jinak.

Podstatné je dát vaší roli technical leadera to, co váš kontext potřebuje. Cesty páně jsou nevyzpytatelné a matka příroda je flexibilní a přizpůsobivá. Nechť vás síla na vaší cestě technical leadera provází.

Doporučená literatura

Pokud jste dočetli až sem, tak jste možná opravdoví čtenáři. A ti čtou opravdové knihy. O technical leadingu už pár titulů napsáno bylo. Jestli můžu doporučit jeden z nich, je to kniha Becoming a Technical Leader od Geralda Weinberga (@JerryWeinberg), která je jako truhlice narvaná drahokamy. Některé nedoceníte hned. Jak říká Jerry:
"Becoming a technical leader is not something that happens to you, but something that you do."

Související články


Související externí články



19. září 2017

Střípky z prototypování II: WebSockets

V úvodním díle jsme se dívali na jednoduchý prototyp - jak spojit dvě etablované webové technologie: Wicket a Spring. Bylo to takové zahřívací kolo, ještě o nic nešlo. Spíše o to, připravit si prototypovací platformu, než vyřešit zapeklitý technický problém.

V dnešním díle se podíváme na prototyp, jehož negativním výsledkem mohla být výměna GUI technologie, což by vedlo k refaktoringu cca 1/3 aplikace.

Kontext

πάντα χωρεῖ καὶ οὐδὲν μένει ~ Ἡράκλειτος
Jak říká Hérakleitos z Efesu: "všechno se mění a nic nezůstává stejné". To se tak stane, že zákazníkovi prodáte určité řešení. Všude - v odpovědi na RFQ, v kontraktu, na workshopech se zákazníkem - prezentujete, že GUI určité aplikace bude "wizard-like".

Vyberete technologie, nastřelíte aplikační prototyp a začnete vyvíjet business features. Vývojáři studují a postupně si osvojují nové technologie. Svět je krásný...

A pak přijde UX designer a hodí vám do toho vidle. Řekne, že uživatelé milují skrolování a cool, že jsou Single Page Aplications (SPA). A vy si uvědomíte, že GUI technologie, kterou jste zodpovědně vybrali (možná i nějaká bezesná noc tam byla), se se změnou paradigmatu není schopná vyrovnat.

Use Case

Cíl tohoto prototypu byl přímočarý: zpropagovat data, která přijdou na server z bezstavové RESTové služby do prohlížeče konkrétního uživatele a překreslit určitou část obrazovky, aby se tato data zobrazila. S nadsázkou jsem tomu říkal: přidat "reactive-like" chování.

Podmínkou samozřejmě bylo, aby zůstaly zachovány stávající technologie (tedy Spring a Wicket). Pro úplnost dodám, že Wicketovské komponenty jsou vždy stavové.


Implementace

Implementaci jde rozdělit do dvou kroků:
  1. Zpracování RESTového volání a propagaci dat do Wicket komponenty na serveru.
  2. Push dat ze serveru do konkrétního prohlížeče.

Observable Cache

První bod můžeme realizovat pomocí Observer patternu - do řešení přidáme další element, který zatím budeme nazývat observable cache (a více si o něm povíme v příštím díle). Observable cache nám bude fungovat jako synchronizační mechanizsmus:
  1. Wicket komponent se zarigistruje jako observer do observable cache.
  2. REST kontroler vloží data do observable cache.
  3. Observable cache notifikuje zaregistrované observery (wicket komponenty).


Jelikož observable cache je pro nás zatím abstraktní komponent, jehož technologie/implementace bude vybrána později (a navíc pro nás momentálně není podstatná), vytvoříme si ji pro začátek jako jednoduchou observable HashMapu. Pro začátek budeme chtít notifikace pro metody put a remove.


Následně zaregistrujeme Wicket komponentu (Panel) jako observera. Potřebná WebSocket logika půjde do metody update(). Prozatím ji necháme prázdnou, než probereme, jak se Wicket staví k WebSocketům.


Wicket a WebSockety

Je to taková matrjoška. Existuje WebSocket specifikace. Ta je implementována Java API for WebSocket (JSR 356). A Java API je pak obaleno Wicktovskou implementací/rozšířením. Wicketovská dokumentace je popsaná v referenční příručce v kapitole Native WebSockets. Některá témata zde chybí, ale je to dobrý začátek.

To, co Wicket k WebSocketům přidává a co také využijeme pro náš případ (a co také chybí v dokumentaci), je "broadcastování" WebSocket zpráv. V základě to umožňuje poslat WebSocket událost všem komponentům, které mají definované WebSocketBehavior. Komponent pak může přijatou událost dále filtrovat a rozhodnout se, jestli na ni reagovat.

To, že náše aplikace bude WebSocket-ready, nám zajistí náhrada klasického WicketFiltru za JavaxWebSocketFilter:


Tady trochu odbočím od WebSocketů k servletům. Aby WebSockety fungovaly, musí je podporovat servlet kontejner, ve kterém aplikace poběží (všechny moderní kontejnery by to měly umět).

V rámci popisovaných prototypů probíhá deployment jako součást buildu, do embedovaného servlet kontejneru, který nám poskytuje výborný Gradle plugin Gretty (k dispozici jsou Jetty a Tomcat). Bohužel, našel jsem tady pravděpodobně bug - WebSockety nefungují v embedovaném Jetty, takže je potřeba používat embedovaný Tomcat. (Ve standalone Jetty funguje všechno jak má, takže to bude problém Gretty.)

Zpátky k WebSocketům a Wicketu. Nyní, po notifikaci z observable cache, chceme z metody update broadcastovat WebSocketEvent a opět ji odchytit ve Wicket panelu, který budeme chtít překreslit. Data pro model komponentu si vytáhneme přímo z cache.


Pokud se podíváme na tento proces z hlediska kódu, potřebujeme ve Wicket komponentu aktualizovat pár věcí:
  1. V konstruktoru přidat na komponentu WebSocketBehavior.
  2. Z metody update broadcastovat IWebSocketPushMessage.
  3. V metodě onEvent zprávu přefiltrovat.
  4. Nechat komponent (nebo jeho část) překreslit.
  5. V rámci překreslení dojde ke znovu-načtení modelu.


Prototype repozitory

Pokud si budete chtít prototyp spustit a trochu si s ním pohrát, naklonujte si následující Bitbucket repository. Součástí prototypu je SoapUI projekt, s připraveným REST requestem, kterým si můžete poslat data do prohlížeče.

Klíčové třídy:

Poučení

Občas se ukáže, že řešení, které jsme odkládali jako nejzažší možné, je nakonec to správné. Nebo jediné funkční. Je potřeba zvážit potenciální důsledky - např. přepisování GUI vrstvy versus pozdější perfomance problémy (kolik WebSocket spojení bude v produkci otevřených? Jaký bude objem broadcastovaných zpráv? apod.)

Zvolili jsme na počátku dostatečně flexibilní technologii, aby uspokojila i nároky v úvodu zmiňovaného Hérakleita z Efesu? (Eh, chtěl jsem říci šíleného UX designera.) Malý, rychlý prototyp může dát na tyto otázky odpověď. Nebo aspoň vyznačit cestu, kudy ne.

Příště

V pokračování střípků se podíváme na to, čím nahradit observable cache. Můžete se těšit na sebevražedný deathmatch Neo4j vs. Infinispan.

Repository všech prototypů


Související články