úterý 25. prosince 2012

Bilancování

Blíží se konec roku, a to je většinou čas k přemýšlení nejenom o tom, co jsme udělali, ale i o tom co nás čeká rok následující. Já bych s dovolením začal malým ohlédnutím. Je tomu skoro na den deset let, kdy jsem tento blog zakládal. Četnost příspěvků oscilovala stejně jako jejich náplň a žel bohu i kvalita. Blog jsem začal tvořit z potřeby vypsat si vlastní názory a myšlenky a mnohdy si je jenom utříbit. Nebo se mi to alespoň retrospektivně zdá. Procházel jsem různými fázemi tvorby, od té kdy mě stresovalo, že jsem dlouho nepřidal žádný další článek, až po tu, kdy jsem si na blog ani nevzpomněl. Velmi dlouhou dobu se mě držela touha sledovat čtenost blogu, podle mého mylného názoru, jediného atributu ukazujícího vlastní úspěch či neúspěch. Zžíraly mě kritické komentáře a kritiky obecně, stejně jako snahy být konzistentní mezi tím co píšu a co se snažím sám dělat. Chtěl bych jenom říci, že psaní blogu není jenom zábava. Pokud vlastní myšlenky a názory prezentujete veřejně, musíte počítat s tím, že kromě souhlasných či nesouhlasných názorů, bude existovat skupina lidí, kteří vás budou chytat za slova, vytrhávat věty z kontextu a vůbec tropit si z vás legraci. Každý kdo jde s kůži veřejně na trh, musí počítat s tím, že je v první řadě velmi snadný cíl. Letošní rok jsem si dával cíle, jak napsat tolik a tolik článků. Zpětně vidím, že to byl nesmysl, protože bych chtěl do dalšího roku odbourat všechny ty vnitřní omezení a bariéry, která jsem si v hlavě vytvořil. Do dalšího roku je mým cílem být více svobodnější v tom co říkám a píšu.

V letošním roce mi dělala radost práce na CZ Podcastu. Podařilo se nám s Filemonem vyzpovídat celou řadu zajímavých hostů a vždy jsem měl pocit, že jsem si z natáčení odnesl nějakou velmi cenou informaci. Občas mám pocit, že jsme jako Šimek s Bubílkovou svého času. Já pracně nadhazuji míčky a Filemon je odpaluje s velkým nadhledem a lehkostí. Asi proto nám to tak klape. Vždycky si říkáme, že nás natáčení musí hlavně bavit. Do dalšího roku si přeji ať nám to vydrží co nejdéle.

Největší letošní inspirací pro mne byla kniha Černá labuť o následcích vysoce nepravděpodobných událostí. Nechci se o ní rozepisovat, protože jsem o ní mluvil v podcastech, a tento sloupek na to ani není příliš vhodný. Zmiňují ji z jiného důvodu. Utvrdila mne v přesvědčení, že pokud chceme někde hledat inspiraci, mělo by to být mimo technologie. S tím se pojí historka z posledního setkání Czech Java User Group. Jeden kamarád mi po setkání, jehož náplní byly sedmiminutové prezentace na různá témata, vyprávěl, jak ho překvapilo velké zastoupení soft skills témat. Zdá se mi, že celý náš obor snažíme vnímat přísně technickýma očima a zapomínáme, že se v 80% případů neliší od ostatních oborů, neboť je v jeho centru pouze a jenom člověk se všemi svými omyly a chybami. Jak se liší dobře či špatně řízený vojenský nebo stavební projekt od toho v IT? Jak se liší dobrý nebo špatný konstrukční návrh budovy od toho softwarového? Proč lidé v určitých situacích dělají určitá rozhodnutí? Inspirace je všude kolem nás, někdy stačí jenom náš mozek přepnout do jiného režimu a vymanit se ze zajetí technologií. Já začnu následující rok s knihou Daniela Kahemana Myšlení rychlé a pomalé.

Czech Java User Group je tu s námi šest let a já mám pocit, že jí trochu šidím nebo jinak, že její potenciál je daleko větší. Vždycky jsem chtěl, aby byla škála témat pestrobarevná. Mít různé názorové proudy a témata, ne nutně související s Javou, ze kterých by si mohli lidé vybrat. Trochu mě mrzí, že nemáme moc odvahu vystupovat s tématy, do kterých jsme úplně nepronikli. Vidím to sám na sobě, už nějaký ten pátek sbírám odvahu udělat prezentaci o tom, co jsem se dozvěděl z kmihy Pragmatic thinking and learning. Budu rád, pokud se mi to podaří.

Jsouce poučen výše uvedenou knihou Černá labuť nehodlám se dopouštět chyby v podobě předpovědi budoucnosti technologií a vývoje na základě minulosti. Jak pravil její autor Nassim Nicholas Taleb "budoucnost nebude taková, jak si jí představujeme dnešníma očima". Musím se smát všem těm technologickým předpovědím, které jsem tu kdy činil. Bylo zábavou je vytvářet, ale chybou se jimi řídit. Berte proto prosím z rezervou jakýkoliv článek, který se vám bude snažit sdělit budoucnost formou "Deset XYZ, které budete potřebovat, jinak vaše kariéra skončí troskách a popelu". Do dalšího roku, sobě i vám, ctěným čtenářům, přeji hlavně otevřenou mysl.

sobota 8. prosince 2012

Proč se špatně rozhodujeme a čím je naše rozhodování ovlivněné

Zkusili jste si někdy položit otázky, proč děláme špatné odhady, proč situace posuzujeme jinak, když se týkají nás samotných a jinak pokud někoho jiného. Náš mozek má - počítačovou terminologií řečeno - určité bugy nebo vlastnosti (záleží jestli je ctihodný čtenář z oddělení kvality nebo vývoje). Jednou ze zajímavých vlastností našeho mozku, která ovlivňuje naše rozhodování a úsudek, jsou takzvané cognitive biases.

Začneme jednoduchou otázkou

Pálka a míček stojí dohromady 1.10 Kč,-. Pálka je o 1 korunu dražší než míček. Kolik stojí míček?

Pokud jste odpověděli 0.10, odpověděli jste špatně (správná odpověď je 0.05), ale nic si z toho nedělejte . Autor knihy Thinking Fast and Slow a laureát Nobelovy ceny Daniel Kahneman pokládal stejnou otázku studentům amerických prestižních univerzit jako Harvard, Princeton a MIT a více než 50% jich odpovědělo špatně. Pokud jste odpověděli bez velkého přemýšlení 0.10, stali jste se obětí Anchoringu. Anchoring patří do rodiny cognitive biases a popisuje kladení důrazu na první část informace při procesu rozhodování. Když vám řeknu, že Václav Havel umřel po šedesátce a pak se zeptám, kolik mu bylo podle vás let, budete tipovat právě kolem šedesátky - šedesáttří, šedesátpět atd. První částí jsem vás k ní totiž ukotvil.

Podle Kahemana náš mozek při rozhodování používá dva systémy , které pojmenoval System 1 a System 2. Každý z nich má jinou charakteristiku a používáme ho jiným způsobem. System 1 nabízí velmi rychlé odpovědi, které mohou být ovšem špatné. Používáme jej podvědomě na takzvané "myšlení bez myšlení". Právě jeho schopnost rychle reagovat na podněty, které mu posíláme, je jeho hlavní výhodou. Systém 2 oproti tomu používáme pro řešení složitějších problému a i výsledky, které dává, jsou mnohem přesnější. Na druhou stranu nedává výsledky ihned a jeho provoz něco stojí. K rozhodování potřebujeme oba dva systémy a používáme je v závislosti na podnětech a situaci, ve které se zrovna nacházíme. Pokud jsme postaveni před rozhodnutí k novému problému, zapojí se System 2, pokud jsme problému již čelili, je rozhodnutí řízené Systemem 1.

Většina chyb při rozhodování pochází právě ze Systému 1, na který působí cognitive biases. Jaké další biasy (předsudky, předpojatosti) ovlivňují naše rozhodování. Vybral jsem pár uvedených v knize Pragmatic Thinking and Learning: Refactor Your Wetware a pár dalších, které mě zaujaly.

Self-serving bias
Tendence asociovat osobní přičinění k úspěchu a naopak neúspěch asociovat s externími faktory. Pokud jsem dobře zvládl zkoušku, přičítám to vlastní inteligenci nebo hodinám stráveným studiem. Pokud jsem zkoušku nezvládnul, přičítám to předpojatosti učitele, jeho neschopnosti mi danou látku vysvětlit a nebo smůle při výběru otázky. Tento mechanismus slouží jako ochrana a posílení vlastní hrdosti (ocenění sebe sama).
Need for closure
Touha odstranit nejistoty nebo pochyby vztahující se k nějakému problému. To nás vede k tomu, že se snažíme všechny pochyby a nejistoty vyřešit.
Confirmation bias
Tendence upřednostňovat informace, které podporují naše vlastní hypotézy a názory. To se vztahuje nejen na to jak získáváme informace, uchováváme, ale i interpretujeme. Špatná rozhodnutí ovlivněná tímto předsudkem byly nalezena například ve vojenství nebo politice.
Mere-exposure effect
Tendence preferovat věci jenom a pouze na základě toho, že jste s nimi dobře obeznámeni. V 60. letech udělal Robert Zajonc pokus, kdy dvěma skupinám lidí nejdříve ukázal různé nesmyslné čínské znaky. Potom jim vysvětlil, že každý z těch znaků má pozitivní a nebo negativní konotaci. A požádal je, aby u každého znaku označili, jestli se jedná o negativní a nebo pozitivní. Lidé měli tendenci označit znaky, které před tím viděli, jako ty s pozitivní konotací a naopak.
False memory
Záměna událostí nebo jejich detailů, mezi tím jak se staly a tím jak si je pamatujeme. Kolikrát se vám stalo, že jste si s kamarády vyprávěli jednu a tu samou historku, kterou jste společně prožili, jako by to byl úplně jiný příběh. Každý z vás měl úplně jinou verzi, přestože jste všichni zažili totéž.
Planning fallacy
Tendence podceňovat (podhodnocovat), jak dlouho nám zabere dokončit daný úkol, a to bez ohledu na zkušenost s podobnými úkoly. Tato tendence se vztahuje na úkoly z jakéhokoliv odvětví. Tohoto podcenění dopouštíme, protože se příliš fixujeme na optimistický scénář, a nebo to prostě chceme v té době dokončit.
Gambler's fallacy
Tendence si myslet, že pravděpodobnost se mění na základě události, ke kterým došlo, ačkoliv ve skutečnosti zůstává stejná. Pokud pětkrát hodím mincí, a pětkrát mi padne orel, mám tendenci si myslet, že po šesté už musí padnout panna. Přitom pravděpodobnost je pořád stejná.
Hindsight bias
Tendence vidět události, které již nastaly, jako více pravděpodobné než se na začátku zdálo. Někdy se tento bias nazývá knew-it-all-along effect (celou dobu mi jsem si to myslel/věděl). Je pravděpodobně způsobený zkreslením informací uložených v paměti, které vede právě k chybnému vyhodnocení.
Fundamental attribution error
Posuzujeme chování konkrétních lidí spíše podle jejich osobnosti (charakteru) a nezohledňujeme situaci a kontext, ve kterém k chování došlo. Především se to projevuje při posuzování chování dalších lidí. Při posuzování vlastního chování si naopak přičítáme výsledek na úkor externích vlivů.

Uvedl jsem jich opravdu jenom pár, ale i z toho malého vzorku je jasné, že náše rozhodování může být velmi zkreslené aniž bychom si toho byli vědomi. Jednou z možností, jak těmto zkreslením čelit je zapojit System 2. Každému z cognitive biases se dá čelit jiným způsobem, ale musíme si to uvědomit. Začněme například s tím, že se naučíme pracovat s určitou mírou neurčitosti (Need for closure), to nám umožní nedělat určitá rozhodnutí předčasně. Pokud se rozhodujeme pro programovací jazyk/nástroj/metodiku a jeden konkrétní vybereme, je dobré najít si někoho, kdo bude v opozici a poskytne nám oponenturu (Confirmation bias). Pokud něco selže, nehledáme příčinu jenom někde jinde a nepřisuzujeme jí externím vlivům, ale snažíme se vidět vlastní podíl, případně vnímat celý kontext.

Pokud vás toto téma zaujalo, pak bych kromě již odkazovaných zdrojů, doporučuji následující články a prezentace.

čtvrtek 22. listopadu 2012

CZ Podcast 72 - Jiří Knesl o GTD, školení, Scrum, PHP a RoR

Do dalšího dílu jsme si pozvali Jiřího Knesla, se kterým jsme si prošli přes různá témata jako Getting Things Done, školení, Scrum a nebo přechod z PHP na Ruby on Rails. Jo a připojte se k nám na CZ Podcast oficiální Facebook stránce.

pátek 16. listopadu 2012

Shluky chyb - charakteristika a dopad

Před nedávnem jsem strávil den lovením chyby, která se projevovala následujícím záhadným způsobem. Odhlášení z GoodData se provádí HTTP požadavkem s metodou DELETE na resource reprezentující uživatelskou session. Na Internet Exploreru verze 10 docházelo k tomu, že prohlížeč zůstal viset přesně minutu při čekání na odpověď, aby vždy nakonec obdržel vnitřní chybu serveru.

Prvním krokem bývá zkontrolovat logy. Z logu na první pohled vyplývalo, že frontend server čekal minutu na odpověď z backend serveru a protože se nedostavila, odpověděl klientovi vnitřní chybou serveru. Zároveň bylo z logu vidět, že backend server přibližně ve stejný okamžik požadavek nakonec správně odbavil. Vlastní zpracování požadavku nikde nevázlo. První myšlenka, která mě napadla, byla že se jedná o deadlock na fronted serveru, který se uvolní po jedné minutě. Přes JMX konzoli jsem osolil logování klíčových komponent ve fronted serveru. Z detailních logů bylo patrné, že se požadavek nikde na frontendu nebrzdí. Na backend serveru detailní logování ukázalo, že minutové čekání není v žádných místech, kde by to člověk očekával, jako například databáze. Na řadu přišly dobře řízené výpisy stavu zpracování požadavku. Po hodině experimentování se podařilo izolovat místo čekání na řádek čtení těla HTTP uvnitř REST frameworku v backend serveru.

Kolegu napadlo, že by příčinou mohl být zmršený HTTP požadavek. K řeči přišla černá magie v podobě TCP dumpu na portu backednového serveru. Na první i druhý a dokonce třetí pohled se mi zdálo vše v pořádku. Nakonec jsme objevili, že požadavek obsahuje HTTP hlavičku Content-length s hodnotou 9 bajtů, ale požadavek už neobsahoval vlastní tělo. Příčina čekání bylo tedy v tom, že backend server čekal na tělo požadavku, které nikdy nedorazilo. Stále ovšem zbývalo vyřešit, kde k poškození požadavku dojde.

Nejdříve jsme podezřívali prohlížeč, u Internet Exploreru je ostražitost vždy na míste, ale ten posílal požadavek včetně jeho těla. Další na řadě byl load balancer atd. Nakonec se zdálo, že tělo požadavku zahodí frontend server resp. HTTP klient uvnitř, který požadavek přeposílal. Což mě logicky přivedlo k otázce, proč to HTTP klient dělá. Stávalo se to totiž jenom pro jeden konkrétní požadavek v konkrétním prohlížeči a v konkrétní verzi. Nakonec jsem skončil u kódu, který kopíroval HTTP požadavek. V něm vše vypadalo v pořádku až na jeden drobný detail.

//Vytvoreni HTTP metody
HttpMethodBase method;
if ("GET".equals(request.getMethod())) {
    method = new GetMethod(uri);
} else if ("POST".equals(request.getMethod())) {
    method = new PostMethod(uri);
    setRequestBody((PostMethod) method, request);
} else if ("PUT".equals(request.getMethod())) {
    method = new PutMethod(uri);
    setRequestBody((PutMethod) method, request);
} else if ("DELETE".equals(request.getMethod())) {
    method = new DeleteMethod(uri);
} else if ("HEAD".equals(request.getMethod())) {
    method = new HeadMethod(uri);
} else {
    ...
}

//Kopirovani HTTP hlavicek
for (Enumeration headerNames = request.getHeaderNames(); headerNames.hasMoreElements();) {
    method.setRequestHeader(headerName, request.getHeader(headerName));
}

Kód pro kopírování HTTP požadavku z abstrakce serveletu do abstrakce Apache Jakarta Commons HTTP client totiž kopíroval všechny HTTP hlavičky včetně Content-length, ale vlastní tělo požadavku se kopírovalo jenom pro POST metodu. Pak už to bylo jasné, protože abstrakce pro DELETE metodu nemá možnost nastavit tělo požadavku. Fix byl velice přímočarý, ignorovat originální Content-length hlavičku. Po něm vše začalo fungovat.

Shluky chyb

Na tomhle příběhu je pěkně ilustrovaná charakteristika chyb. Ty mají totiž tendenci se projevit pouze pokud se jich shlukne několik (mnohdy záleží i na pořadí). Zřídkakdy způsobí kolaps jedna jediná chyba, vždycky to musí být shluk několika chyb. Málokdy ten chlápek, co vám vytrhne server ze zásuvky, má v té serverovně oprávnění něco dělat. Velmi podobné je to i v reálném světě, pokud jste někdy sledovali například dokumenty na téma leteckých katastrof a nebo slyšeli o Černobylská havárii. Nikdy za tím nebyla jedna jediná chyba, ale jejich shluk.

Pokud se vrátíme k našemu příkladu, pak při podrobné analýze přijdeme na to, že při vynechání jakékoliv chyby, by nedošlo k takovému zřetězení, které by ve výsledku způsobilo to minutové čekání. Jinými slovy každá jedna izolovaná chyba by se neprojevila takto fatálně. A naopak pouze určitý shluk chyb vede k určitému selhání. Když to vezmeme na tomto konkrétním shluku.

    Vágní specifikace
    HTTP specifikace nikde explicitně neříká, že by DELETE metoda nemohla nebo nesměla poslat tělo požadavku. Je tedy na libovůli daného HTTP klienta, jak se k tomu postaví. Internet Explorer, u jiných prohlížečů jsem to nezkoumal, si specifikaci vykládá benevolentním způsobem. Zcela jinak si to ovšem vykládá použitý HTTP klient.
    Chyba klientské části aplikaci
    Při podrobném zkoumání se ukázalo, že obsah těla HTTP požadavku, poslaný prohlížečem, je pouze řetězec undefined. Čili to vypadá na klientskou chybu v JavaScript kódu aplikace, která se projeví pouze v Internet Exploreru.
    Chyba v serverové části aplikace
    Pokud by se hlavičky ve výše uvedeném kódu kopírovaly správně, opět by k problému nedošlo. Ale k projevení špatného kopírování dojde jenom pokud dojde k chybě předchozí a navíc server nebude Content-length hlavičku ignorovat pro DELETE mtodu.

Chyby které se projeví pouze ve shluku je velmi složité odhalit. V případě testů musíte mít velmi dobré pokrytí integračními testy, protože jednotkové testy vycházejí z vašich předpokladů, jak se bude chovat okolí testovaného subjektu, ať již ve vztahu ke vstupu a nebo výstupu. Pravděpodobnost, že tam dojde ke shluku, je velmi malá. Právě ve shluku a jeho unikátnosti je skrytá nebezpečnost těchto chyb.

pátek 2. listopadu 2012

CZ Podcast 71 - Energy management a koučink

Další podcast, při kterém jsme se dost dobře bavili, je vám vážení posluchači k dispozici. Hostem byl Jan Patrman a tématem Energy management a koučink. Zůstat s námi ve spojení můžete nově na fanouškovské stránce CZ Podcastu.

úterý 30. října 2012

Instapaper aneb jak jsem opět začal číst články

V určité době jsem úplně rezignoval na čtení článků přes RSS agregátory typu Google Reader. Nebyl to technický problém, ale sociální. V čtečce mi přibýval jeden článek za druhým rychlostí monopostu Formule 1, což bylo velmi frustrující, protože jsem je neměl čas procházet. Podobnou situaci jsem zažil i na Twitter účtu. S tím malým rozdílem, že mi opravdu kvalitní články někdo z lidí, které sleduji, doporučí. Velkou výhodou Twitteru je, že lze pohodlně konzumovat z mobilního telefonu, počítače nebo tabletu. Pokud mě nějaký tweet s odkazem na článek zaujal, prostě jsem na něj kliknul, a on se ihned zobrazil. Přesto to nebylo úplně ono. Často se mi stalo, že mě článek odvedl od nějaké rozdělané práce. Navíc pokud mě opravdu něco zaujalo, měl jsem tendence pročítat další odkazované zdroje, protože jsem věděl, že se k nim už nedostanu a nebo na ně zapomenu.

Neměl jsem z toho dobrý pocit. Buďto jsem si něco přečetl a pak měl výčitky, že mě to odvedlo od rozdělané práce nebo jsem se do ní složitě vpravoval. Pokud jsem si něco nepřečetl, tak jsem na to dříve nebo později zapomněl, a užitečné informace mě míjely. V tomhle stavu, číst-nečíst utíkat neutíkat od rozdělané práce, jsem vydržel pár let. Mojí situaci trochu vylepšil chytrý telefon, díky kterému jsem mohl Twitter a články konzumovat i v čase, kde mě to neodvádělo od práce a nekonzumovalo omezené mentální zdroje. Čtení článků na mobilním telefonu má svá úskalí. Webové stránky nebývají vždy optimalizované pro mobilní telefon. To se týká velikosti zobrazení a objemu dat, no schválně si zkuste načíst TheServerSide při přestupu na Můstku. Navíc přetrvával problém s články, které bych si rád přečetl později, abych nemusel odbíhat od rozdělané práce. Z tohoto stavu mě nakonec vysvobodila úžasná služba Instapaper, která se zdá být efektivním nástrojem.

Instapaper

Instapaper je webová aplikace, do které si můžete jednoduše poslat článek a ten si později přečíst přímo z této aplikace. Celé kouzlo je v tom, že Instapaper dokáže článek stáhnout, naformátovat a poslat ve vhodném formátu pro zařízení, na kterém si jej zrovna chcete přečíst. Na laptopu si můžete článek zobrazit v originální podobě a nebo v optimalizované podobě (nemá reklamy, jednotný font). Do mobilního telefonu se články automaticky stahují v optimalizované podobě. Je to velmi rychlé, protože se přenáší v podstatě jenom čistý text. Navíc velikost textu a formátování respektuje, že se jedná o mobilní zařízení. Články si můžete nechat doručovat do Kindlu. Při vlastním čtení článku v Instapaper funguje skvěle práce s hypertextovými odkazy. Aplikace se vás zeptá, jestli chcete odkaz následovat, případně jestli chcete odkazovaný článek rovnou poslat do Instapaper. Každý účet na Instapaper má svojí unikátní emailovou adresu, na kterou můžete posílat emaily, které se zpracují úplně stejným způsobem jako články. Instapaper vám umožňuje s články dále pracovat. Můžete je sdílet na sociálních sítích, kategorizovat a archivovat, pokud se k nim budete chtít později vrátit.

Zatím jsem objevil pár omezení, které by bylo pěkné vylepšit. Instapaper neumí zpracovat PDF. Pokud byste si tam chtěli poslat váš oblíbený paper v PDF, máte smůli. Z pochopitelných důvodů není Instapaper schopen zpracovat články vyžadující autentizaci (OAuth podpory jsem si nevšiml) (update: z bookmarkletu v browseru to funguje). Další věc není možná ani omezení. Pro iPhone je totiž aplikace placená. Osobně mi to vůbec nevadí, provoz a vývoj podobné služby stojí nemalé peníze, a těch pár dolarů (3,99$) za aplikaci se mi bohatě vyplatilo.

Klady, jistoty a sociální pozitiva aplikace Instapaper

  • odpadá přepínání kontextu mezi prací a čtením článků, případně odskakování z rozečtených článků na odkazované zdroje
  • články jsou k dispozici v optimalizované formě pro mobilní zařízení
  • funguje pro emaily
  • možnost kategorizace článků a jejich sdíleni

pondělí 29. října 2012

sobota 13. října 2012

Jak si (ne)zruinovat životopis


Mám trochu podezření, že v honbě za zaškatulkováním jednotlivých kandidátů, dovedly personální agentury a celá HR mašinerie psaní životopisů ad absurdum. Většinou se vám dostanou do rukou alespoň čtyři hustě popsané stránky se všemi zkratkami, které jste kdy slyšeli. Nadto většina kandidátů ovládá alespoň čtyři programovací jazyky, tři databáze, dva operační systémy a o osmnácti frameworcích ani nemluvě. Impresivní sbírka těchto znalostí bývá okořeněna špetkou školení a webových seminářů. Podle těchto životopisů, musí člověk neznalý poměrů nabýt dojmu, že po pohovorech chodí samí nadlidé. Teď bych se nechtěl někoho dotknout, sám jsem si párkrát vlastní životopis náležitým způsobem vyšperkoval. Ač by se to nemuselo podle předchozích řádků zdát, životopis má stále svojí cenu, která je vyšší než cena papíru A4, na kterém je vytištěný. Z vlastní zkušenosti bych se při psaní životopisu držel několika jednoduchých postupů.

Pokud si do životopisu uvedete nějaký jazyk, framework nebo technologii, dá se předpokládat, že se vás na ní u pohovoru mohou zeptat. Hranice mezi tím, jestli danou technologii opravdu znáte a tím jestli jste si jí uvedli v životopisu jenom pro vylepšení profilu, bývá jedna jediná otázka. Věru vtipně znějí výmluvy typu: používal jsem to krátce, zkoušel jsem si v tom doma něco napsat, četl jsem si o tom. Drobným vylepšením může být uvedení vašeho vlastního odhadu, jak technologii ovládáte. Nicméně úplně nejlepší mi přijde mít v životopise sekci "Zajímám se", kde můžete vypsat vše co vás zajímá.

Pokud vám bude někdo tvrdit, že důležitý je počet technologií, které v životopise uvedete, mějte se na pozoru. Pestrobarevnost vašeho životopisu hraje roli, ale nijak bych jí nepřeceňoval. Stejného efektu se dá dosáhnout i jiným způsobem. Je s podivem, jak málo lidí uvádí ve svém životopise odborné knihy, které je nějakým způsobem zaujaly. Obecně zdroje, z kterých člověk čerpá nové informace a podněty. Pokud mi někdo, kdo se považuje za java programátora, není schopen říci ani jeden zdroj informací (servery, podcasty, blogy atd.), ze kterého čerpá, je na něm něco zvláštního. Jedním z faktorů, který je pro mě během pohovoru klíčový a dávám mu větší váhu než samotné znalosti technologie, je ochota člověka učit se novým věcem. Něco co bych poeticky označil za otevřenou mysl. Obzvláště v něčem, tak dynamicky se měnícím, jako je IT.

Rád se uchazečů ptám, co naposledy četli nebo jaká technologie či myšlenka je zaujala. To mi o nich napoví mnohem více než zhusta popsaný životopis. Navíc to při pohovoru nepůsobí jako výslech, ale více jako dialog, když se o dané věci bavíme. Nemám rád pohovory, které probíhají ve stylu zkoušky ve škole. Bohužel přesně k těmhle typům pohovorů vedou životopisy orientované na co největší množství zkratek a technologií.

Další často podceňovaná část životopisu bývá o zájmech a zálibách. Pokud se někdo hlásí na pozici programátora, nebude mě asi moc zajímat, jestli má řidičský průkaz typu B. Není to vodítko, ale pokud někdo dělá nějaký kolektivní sport, zřejmě nebude mít problém vycházet s lidmi. Pokud je někdo sportovec nebo se věnuje jiné aktivitě, bude zřejmě schopen snášet útrapy, které sebou sportování nese. To všechno jsou maličké střípky do mozaiky, které si o tom člověku skládám. Nepodceňujte detaily, abych to zabalil do jedné rady.

Samozřejmě podobně psaný životopis negarantuje úspěch. Pak je ale otázka, jestli se vůbec ztrácet čas s firmami a personálními agenturami, kde upřednostňují kvantitu v podobě zkratek a strojově psaných životopisů.

pondělí 8. října 2012

CZ Podcast 69 - Continuous Delivery

Minulý týden jsme nahráli další díl podcastu, ve kterém se můžete dozvědět něco více o úsilí jménem Continuous Delivery. Zase jsme za to se staroušem Filemonem vzali a doufáme, že se vám to bude líbit.

sobota 6. října 2012

Zámky a budíček ve dvě hodiny ráno

Pokaždé, když vám zazvoní telefon ve dvě hodiny ráno, je to průšvih. V podstatě vám může volat jenom zhrzená milenka a nebo se vám něco vysypalo na produkci. Průšvih je o to větší, pokud má přímý dopad na zákazníky a obzvlášte na ty v zámoří, kteří trpí přímo v hlavním vysílacím čase. Nedávno se mi to stalo a přestože problém je specifický, lze se z něj dobře poučit a vzít si pár obecných ponaučení. Uvědomil jsem si to při čtení článku Synchronized Drowning, kde došlo k něčemu podobnému.

Napsal jsem kód, který sloužil k načítání veřejného klíče pro kontrolu podpisu. Protože se klíč rotoval po několika hodinách, navíc z distribuovaného souborového systému GlusterFS, přišlo mi vhodné, aby se nečetl pro každý jednotlivý požadavek. Kód vypadal přibližně následovně.

        private Key key;
        
        Key getKey(){
            Lock readLock = readWriteLock.readLock();
            try {
                readLock.lock();
                return key;
            } finally {
                readLock.unlock();
            }
        }

        void loadKey() {
            Lock writeLock = readWriteLock.writeLock();
            try {
                writeLock.lock();
                //load
                BufferedReader br = new BufferedReader(new FileReader(new File(keyFile))));
                ....
            } finally {
                writeLock.unlock();
            }
        }

Díky použití read/write locku se vlákna při čtení klíče neblokovala. Pokud byl detekován nový klíč, zavolala se metoda loadKey. V ní se získal write zámek a všechna vlákna vyjma jednoho byla blokována dokud se klíč nenačetl.

Všechno fungovalo až do okamžiku, kdy vlákno, které četlo obsah souboru, zamrzlo na věčné časy někde hluboko uvnitř operačního systému při čekání na disk a jediné co pomohlo byl umount disku a restart JVM. Držení write zámku v uvozovkách nekonečně dlouho mělo za následek, že všechna další vlákna čekala na jeho uvolnění. Obecně se z mých chyb můžeme poučit následujícím způsobem.

  • Vždycky když voláte externí systém, obzvláště přes síťové rozhraní, počítejte s tím, že se ten systém může neočekávaně zpomalit. Pravidlo číslo jedna, mějte správně nastavené timeouty na všech úrovních - OS, JVM aplikace.
  • Vždy pokud využíváte služeb Lock, a jeho implementace to umožňuje, preferujte metodu tryLock, která se snaží získat zámek do daného timeoutu.
  • Počítejte s tím, že jediné s čím můžete počítat je, že technologie které používáte selžou. Vždycky je dobré si položit otázku: "co se stane když". Kdybych si jí v tomhle případě položil a uvědomil si všechny důsledky, rozhodně bych použil timeouty a rozhodně bych zámek nepoužil v tak širokém rozsahu. Úplně by stačilo, kdyby byl použit jenom pro přístup k instanční proměnné klíče.
  • Neblokujte vlákna určená pro obsluhu HTTP komunikace tj. nezavlékejte je to blokujících IO operací. Všechny IO operace řešte přes API s podporou neblokujícího přístupu.

středa 3. října 2012

CZ Podcast 68 - OpenShift

Další díl CZPodcastu je tu. V tomto díle najdete informace k Platform As A Service platformě OpenShift, které ochotně poskytnul Marek Jelen. V tomto díle je soutěž o vstupenku na konferenci RUPY 2012. Vaše ohlasy, dotazy, náměty, podněty směřujte na naší emailovou adresu czpodcast zavináč gmail.com.

čtvrtek 13. září 2012

CZ Podcast 67 - BigData, BI

Další díl našeho vašeho podcastu je tady. V tomto díle jsme vyzpovídali Petra Olmera. Tématem byly BigData a BI nad nimi. Petr zavzpomínal na legendu mainframu Petera Harrise, s kterým měl pár vtipných setkání. Vaše ohlasy, dotazy, náměty, podněty směřujte na naší emailovou adresu czpodcast zavináč gmail.com.

středa 5. září 2012

CZ Podcast 66 - WebExpo

Další díl našeho dílka je tu. Zvuk špička, náš výkon odpovída tomu, že jsme po prázdninách, ale zase kupa zajímavých informací o konfeře WebExpo. Doufam, že se vám bude líbit. Jo a tajná informace, je tam slevový kód na vstupenky.

neděle 2. září 2012

Cesta ke Continuous Delivery I. - Mainline vývoj

Rád bych se u jedné z našich komponent posunul z módu Feature branch (větev per funkcionalita) do módu Mainline (hlavní větev) vývoje. Při Feature branch má vývojář vlastní větev, ve které si kutí změny, jednou za čas si přimerguje změny z hlavní větve, a když si myslí, že je vše připravené a má zelenou od oddělení kvality, kód zamerguje do hlavní větve. Oproti tomu vývoj v Mainline znamená, že až na pár výjimek neexistují větve a vývojáři všechny změny provádějí rovnou do hlavní větve a to alespoň jednou denně. Oba dva přístupy mají své pro a proti.

Feature branch

Tento přístup má hlavní výhodu v tom, že se kód může mnohokrát změnit, než je vývojář s jeho podobu spokojený. Skvěle to podporuje i režim, ve kterém se provádí code review, a do hlavní větve se nedostane něco, s čím by nebyl seznámen alespoň jeden další pár očí. Nevýhodou Feature branch je fakt, že k integraci s hlavní vývojovou větví dochází velmi sporadicky. Úplnou jistotu, že nedošlo k integračním problémům, máte jenom ve chvíli kdy proběhnou všechny integrační testy se zbytkem systému.

Mainline

Tento přístup má hlavní výhodu v tom, že případné problémy se objeví, tak rychle, jak jen to je možné. Nedochází k tomu, že si vývojáři něco suší u sebe ve větvi a k integračním problémům dojde ve chvíli code drop, kdy všichni zamergují své změny do hlavní vývojové větve. Nevýhoda tohoto přístupu je v tom, že klade daleko větší nároky vývojáře. Změny se musí promyslet a dělat po menších krocích, vývojář komituje změny minimálně jednou denně. Dělat code review je velmi obtížné, protože nemáte k dispozici celý obrázek o tom, jak bude vypadat výsledný celek.

Protože na komponentě, o které se bavíme, pracují maximálně tři vývojáři na ráz (současný stav, do budoucna jich může být více), nedochází k problémům při mergování změn do hlavní vývojové větve. To je jistě jeden z hlavních argumentů pro to dále využívat Feature branch. Naopak proti hovoří fakt, že komponenta plní zásadní roli v celé platformě a případné chyby mohou mít vážné následky. Navíc jakákoliv změna se efektivně projeví až po code drop zbytku komponent, které na ní závisejí. To sebou přináší minimálně týden stabilizace a řešení problémů vzniklých integrací.Přechod na Mainline by nám přinesl právě odstranění problémů s odloženou integrací. Zároveň díky infrastruktuře kolem Java platformy budeme velice rychle schopni implementovat požadavky, které sebou vývoj v Mainline přináší.

Mainline vývoj předpokládá, že z cesty odvalíme několik technických a řekněme sociologických překážek. Začneme s těmi sociologickými, protože ty implikují technické. Vývojáři mají obavy z následujících dopadů Mainline vývoje.

  • Vývoj ve Feature branch mi umožňuje vývoj, kdy na začátku nemám úplně přesnou představu o tom, jak bude vypadat konečný výsledek. Znám přibližně kam bych se chtěl dostat, ale ještě nevím, jak to bude nejlepší. Dělám velkou spoustu změn v kódu než jsem spokojen. Nechtěl bych, aby tyhle změny byly v hlavní vývojové větvi.
  • Nejsem zvyklý plánovat změny, tak abych je mohl začlenit do hlavní vývojové větve.
  • Není mi jasné jakým způsobem mi bude někdo dělat code review. Budeme se vzájemně neustále vyrušovat. Navíc změny nebude možné posoudit v kontextu celé funkcionality.

Na první pohled se zdá, že to je sám o sobě docela slušný seznam důvodů k tomu, abychom odpískali Mainline vývoj. Ano skutečně je, ovšem za předpokladu, že nepřehodnotíme naše vnímání hlavní vývojové větve. Mainline totiž vyžaduje úplně jiný přístup. Zkusím tento přístup popsat změnou charakteristikou hlavní vývojové větve.

Před
Hlavní vývojová větev obsahuje kód, který prošel code review a nemělo by se na něm nic zásadního měnit pokud nedojde k požadavků na změnu chování a nebo k opravě chyby. Provedené změny odrážejí koncový stav dané funkcionality.
Po
Hlavní vývojová větev obsahuje kód, o kterém víme, že je kompilovatelný, a prošel přes automatické kontroly kvality - testy, měření pokrytí testy, analýza závislosti. Změny v hlavní vývojové větvi mohou být většího rozsahu. Rozhraní mez jednotlivými částmi zůstává pokud možno stabilní, mění se implementace a to často.

Velký otazník visí nad tím, jak dělat code review. Můj původní názor byl nechat code review jako dobrovolnou položku. Další možností bylo používat systém pull requests. Tedy uděláte změnu, vygenerujete pull request, ten někdo zkontroluje a zamerguje. Dále se nabízí různé hybridy např. opravy chyb mergovat automaticky nové vlastnosti přes pull request. Ani jedna z těch možností se mi moc nezamlouvá, protože se tím opět prodlužuje doba začlenění do hlavní vývojové větve a tím pádem doba kdy dojde k integraci se zbytkem systému.

Řešení spatřuji v odložení code review až na okamžik, kdy bude v hlavní vývojové větvi celá funkcionalita. Požadavky z code review lze provádět inkrementálně v hlavní vývojové větvi. Funkcionalita zůstává zakryta dokud nejsme všichni spokojeni s výslednou kvalitou. U opravy chyb bychom měli být schopni udělat jednoduše odstranění změny (revert commit) pokud se nám něco nebude zdát (postupujeme podle changelogu).

Když nad tím přemýšlím, pak při Mainline se kvalita zajišťuje zpětně, až po provedení změny dochází k procesu, který by měl zaručit její kvalitu. U Feature branch se naopak kvalitu snažíme zajistit dopředně, tedy změny nejdříve projdou procesem, který by měl zaručit jejich kvalitu. Ve výsledku nám oba přístupy umožňují velice snadné odstranění změny.

Technické předpoklady pro Mainline vývoj

Vývoj do hlavní vývojové větve předpokládá rychlou a kvalitní zpětnou vazbu o výsledku změn, které jsme provedli. Na řadu přichází něco, čemu se říká commit stage. Commit stage je v podstatě část buildu, kterou musí úspěšné projít každá změna a výsledkem by měly být binární artefakty, které se použijí v dalších fázích (integrační testy, manuální testy). Pokud neprojde, mělo by dojít k její opravě a nebo odstranění (revertu) v co nejkratším možném času. V Commit stage by měla být minimálně kompilace, unit testy a produkování binárních artefaktů. K tomu můžeme přidat například analýzu závislostí u Maven modulů a nebo měření pokrytí testy.

Závěr

V tomto článku jsem se pokusil nastínit problematiku Mainline vývoje, který malým krůčkem je Continuous Delivery. Zároveň bych se s vámi v sérii dalších článků rád podělil o dalším směřování tohoto úsilí.

čtvrtek 30. srpna 2012

Půl království za kreativní přístup

Po nějaké době od návratu ze služební cesty ze San Francisca jsem si uvědomil, jak propastný rozdíl je mezi námi a Američany. Můžete si myslet o Američanech cokoliv, ale nemůžete jim upřít optimismus, kreativitu a nadšení pro danou věc. My Češi jsme národ věčně remcající jehož nejčastější věta zní přibližně: "to nepůjde" případně "to v žádném případě nepůjde" a nebo "vy jste se úplně zbláznili". Jsme prostě zvyklí říkat ono pověstné A a zapomeneme dodat to B, které je neméně důležité. Zatímco Čech, čest všem padlým výjimkám, kouká na většinu komplikací jako na nepřekonatelný problém, Američan tam možná ty problémy vidí rovněž, ale bere je jako výzvu a snaží se najít cestu k jejich překonání. Skoro bych řekl, že Čech většinou problémy nafukuje, zatímco Američan se je snaží řešit. Jinak řečeno, Američané jsou mnohem konstruktivnější při řešení problémů než my Češi. Asi za to může těch zpropadených čtyřicet let komunismu, díky kterým jsme tu živořili v šedivém marastu a nebo prostě jenom fakt, že nás ve škole nikdy nevedli k bůhví jaké kreativitě (snad kromě psaní taháků a podvádění při testech - nebyl jsem výjimka). Ať tak či onak je to k naší škodě, protože tím neustálým kverulantstvím vypadáme, že se nám spíš nechce pracovat, než že bychom si s daným problémem nedokázali poradit. Berte tuhle poznámku jako malé popošťouchnutí k vetší kreativitě.

čtvrtek 26. července 2012

Self testy

Pokud konfigurace vaší aplikace přesáhne jednu jedinou možnost nastavení, pak zřejmě řešíte problém, jak zkontrolovat, jestli je aplikace po instalaci/releasu správně nakonfigurovaná a tím pádem nic nebrání jejímu provozu. To oceníte v případech, kdy aplikace běží v různých prostředích v různém nastavení, například produkční cluster, testovací a vývojové prostředí. Kontrola se nemusí týkat jenom vaší aplikace, ale i prostředí, ve kterém je nasazena. Celý cluster GoodData platformy je konfigurován pomocí nástroje Puppet. Může se stát, že některé skripty respektive jejich části mohou selhat. Proto jsme si vyvinuli jednoduchý framework, pomocí kterého píšeme testy, které ověří správnou konfiguraci aplikace a jejího prostředí.

Co testovat

V každé webové aplikaci existuje několik oblastí, které se vyplatí otestovat. Můžeme je rozdělit na externí a interní.

Interní

Konfigurační properties
Testy konfiguračních properties se skládají z obyčejné validace, že hodnota je jiná než defaultní. Defaultní hodnoty jsou nastavené s respektem k lokálnímu prostředí. Na produkci by se nemělo například používat stejné heslo jako na lokálním prostředí, proto zkontrolujeme hodnotu konfigurační proměnné, která ho nastavuje. Většinou tedy testujeme změnu proti defaultu, případně rozsahy hodnot. Například počet vláken určených pro obsluhu HTTP požadavků by měl být větší než 100.
Komponenty a jejich nastavení
Testy, které kontrolují nastavení jednotlivých komponent. Jedná se především o komponenty, které mají rozdílné chování v různých prostředích. Komponenta dokáže fungovat s defaultem, ale potřebujeme například ověřit, že v produkčním nasazení se bude komponenta chovat jinak. Jako příklad bych uvedl naší komponenty pro Single Sign On (zkráceně SSO) a nebo cache. Je potřeba ověřit, že SSO má k dispozici keystore a dokáže se dostat ke klíčům . U cache je potřeba ověřit, že bude fungovat replikace tj. hosty a porty uvedené pro replikaci jsou přístupné.

Externí

HTTP enpointy, Messagingingové enpointy
Každá aplikace používá externí služby a je dobré ověřit, že jsou skutečně k dispozici. Stačí jednoduchý test dostupnosti služby zasláním požadavku. Pokud to není možné díky charakteru služby např. není možné ověřit doručení, kontrolujeme dostupnost hostu a portu.
Databáze
V databázi, v našem případě MongoDB, kontrolujeme její dostupnost tím, že listujeme dostupné kolekce. Pokročilejší test může kontrolovat verzi aplikace proti verzi databáze, abychom předešli například nekonzistentním datům.
Běhové prostředí
Těmito testy si kontrolujeme nastavení JVM a Tomcatu. Jestli má JVM minimální velikost heapu a perm space oblasti, kterou očekáváme. Jestli se používá skutečně verze Tomcat, na které jsme testovali nebo jestli je nastavený security manager atd.

Jakým způsobem testovat

Jedním z kritérií, které jsme si při vývoji kladli, bylo izolovat vlastní test od toho jakým způsobem budou jeho výsledky reprezentovány. Zároveň jsme chtěli umožnit jednoduché přidávání testů bez nutnosti zásahů (registrace) do jádra systému. První problém jsme vyřešili použitím standardního logovacího objektů (org.slf4j.Logger), pod kterým jsme si implementovali zpracování výsledků.


Rozhraní

/**
 * Interface representing self test of java components of GDC platform.
 */
public interface ISelfTest {

  public static final String LOGGER_PREFIX = "SelfTest: ";

  /**
   * Tests desired functionality and logs results into logger property (of type {@link Logger}).
   * The pattern is that problems are logged as ERROR, ok messages as INFO.
   */
   public void test(Logger logger);

}

Test ověřující JVM typ

Poznámka: některé části AWT/Swing se velmi lišily fork od forku OpenJDK. Proto byl potřeba tento test, abychom si byli jistí, že je použitá správná JVM

/**
 * {@link ISelfTest} checking whether the active JVM comes from Oracle or Sun.
 */
public class SunJVMSelfTest extends SelfTest {

  @Override
  public void test(Logger result) {
    String vendor = System.getProperty("java.vm.vendor");
    String version = System.getProperty("java.version");

    if (vendor != null && (vendor.toLowerCase().contains("oracle") 
      || vendor.toLowerCase().contains("sun"))) {
      result.info(LOGGER_PREFIX + "Java vendor='{}', version='{}'.", vendor, version);
    } else {
      result.error(LOGGER_PREFIX + "Java vendor='{}', version='{}'.", vendor, version);
    }
  }
}

Aby nemusely jednotlivé komponenty registrovat testy někam do jádra systému, stačilo využít vlastností Inversion of Control frameworku, který dokáže vrátit všechny komponenty daného typu viz Automatický "sběr" objektů daného typu pomocí Springu. Komponenty načítáme dynamicky proto není potřeba žádný zásah do existující konfigurace jádra.

Spouštění testů a reprezentace výsledků

Mechanismus spouštění testů je nezávislý na vlastních testech. Testy jsme schopni teoreticky spustit přes JMX či message do RabbitMQ, ale prakticky máme implementované spuštění přes HTTP. Máme speciální servlet, který se stará o spuštění testů. Výsledky testů vracíme jako JSON v odpovědi na HTTP požadavek a zároveň jej logujeme. Tím pádem je nám online k dispozici pro případnou analýzu.

Ukázka výstupu

{
   "selfTestResult":{
      "testsCount":13,
      "errorsCount":3,
      "warningsCount":0,
      "infosCount":16,
      "errors":[
         "c.g.s.t.a.ApplicationCodeSelfTest: SelfTest: Master password is not changed.",
         "c.g.s.t.a.ApplicationCodeSelfTest: SelfTest: Pool size is set to default value.",
         "c.g.s.t.jvm.MemorySelfTest: SelfTest: 'Maximal memory (-Xmx)' is below desired bounds (current='516947968' desired='1073741824')."
      ],
      "warnings":[

      ],
      "infos":[
         "c.g.s.t.jvm.MemorySelfTest: SelfTest: 'Init memory (-Xms)' is within desired bounds (current='536870912' desired='268435456').",
         "c.g.s.t.jvm.MemorySelfTest: SelfTest: 'PermGen space' is within desired bounds (current='1073741824' desired='268435456').",
         "c.g.s.t.jvm.MemorySelfTest: SelfTest: Used memory '337501408'.",
         "c.g.s.t.jvm.SunJVMSelfTest: SelfTest: Java vendor='Oracle Corporation', version='1.7.0_02'.",
         "c.g.s.t.jvm.TmpPathSelfTest: SelfTest: Temp path='/mnt/tmp'.",
         "c.g.s.t.s.ApacheSelfTest: SelfTest: Project templates are accessible on uri='/projectTemplates'.",
         "c.g.s.t.s.C3SelfTest: SelfTest: C3 service is listening on host='localhost' and port='667'.",
         "c.g.s.t.s.C3SelfTest: SelfTest: C3 service FoodMart demo is accessible on uri='/gdc/c3/project/FoodMartDemo'.",
         "c.g.s.t.s.ConnectorsSelfTest: SelfTest: Connectors for FoodMart demo are accessible on uri='/gdc/projects/FoodMartDemo/connectors'.",
         "c.g.s.t.s.JBossCacheSelfTest: SelfTest: JBossCache works ok.",
         "c.g.s.t.s.MetadataSelfTest: SelfTest: Metadata for FoodMart demo are accessible on uri='/gdc/md/FoodMartDemo'.",
         "c.g.s.t.s.MongoSelfTest: SelfTest: Connection to mongo host='127.0.0.1' port='27017' ok. Available databases='[gdc, local]'.",
         "c.g.s.t.s.MongoSelfTest: SelfTest: Connection to mongo host='127.0.0.1' port='27017' database='gdc' ok. Available collections='[xxxx]'.",
         "c.g.s.t.s.RabbitSelfTest: SelfTest: Rabbit MQ service is listening (host='localhost', port='5672').",
         "c.g.s.t.s.StageDirectorySelfTest: SelfTest: Stage directory='/var/gdc/users' is accessible and writeable.",
         "c.g.s.t.tomcat.TomcatSelfTest: SelfTest: Tomcat major version is ok. ServerInfo='Apache Tomcat/7.0.23'."
      ],
      "includedTests":[
         "ApplicationCodeSelfTest",
         "MemorySelfTest",
         "SunJVMSelfTest",
         "TmpPathSelfTest",
         "ApacheSelfTest",
         "C3SelfTest",
         "ConnectorsSelfTest",
         "JBossCacheSelfTest",
         "MetadataSelfTest",
         "MongoSelfTest",
         "RabbitSelfTest",
         "StageDirectorySelfTest",
         "TomcatSelfTest"
      ]
   }
}

Další rozvoj

Možnosti rozšíření se nabízejí ve dvou oblastech. Jednak psaní nových testů a rozšiřování těch existujících, což je nikdy nekončící boj. Další oblastí je komplexnější testování clusterového deploymentu. Mám na mysli například orchestrace testů s dalšími službami, abychom ověřili, že nejenom naše služby, ale i celý cluster funguje. Na druhou stranu je to už trošku jiný typ úlohy.

Self test nám pomáhá odhalit problémy, které mohou vzniknout během releasu, který je zatím pro většinu komponent platformy čtrnáctidenní, ale existují i komponenty, které se releasují i několikrát týdně. Dlouhodobým cílem je dostat s ke continuous delivery a ten už si fungování bez podobného nástroje nedokážu představit.

pondělí 18. června 2012

Pár tipů na lepší logy

Naučit se správně logovat je skoro stejně složité, jako naučit se programovat. Po hříchu není nikde moc článků o tom, jak to správně dělat a proto naše logy vypadají, tak jak vypadají. Někdy logujeme moc, někdy málo, někdy vůbec a to velmi znesnadňuje řešení potíží na produkci. V GoodData používáme pro čtení logu nástroj Splunk, který nám umožňuje dělat dotazy nad stovkami gigabajtů logu, který denně produkujeme. Bohužel i s tímto skvostným nástrojem jste nahraní, pokud vám daná informace v logu chybí a nebo ji nejste schopní vykoukat z kontextu dalších logovaných událostí. Kouzlo správného logování není logovat všechny události, ale logovat ty důležité se správnou úrovní (závažností), zaznamenat kontext, ze kterého bude možné zjistit další detaily, a v neposlední řadě logování neustále zlepšovat, protože málokdy se podaří trefit logování na první pokus.

Úroveň logování

Úroveň a nebo závažnost logované informace vychází z několika úrovní TRACE, DEBUG, INFO, WARN, ERROR. Narýsovat mezi nimi rozdíl je první problém, se kterým se člověk potýká. Většina logovacího kódu používá buďto úroveň příliš nízkou v podobě DEBUG. Druhým extrémem je naopak použití úrovně ERROR, pro události ne zcela zásadního charakteru, která by naopak měla efektivně znamenat, že vás kvůli ní vzbudí ve dvě hodiny ráno. Pokud nebudete dostatečně důslední při rozlišování úrovně, nebudete moci efektivně váš systém monitorovat. Základní rozdělení událostí podle úrovně logování jsem našel v článku Logging levels - Logback - rule-of-thumb to assign log levels. Volně zkusím přeformulovat

ERROR
Používáme pro zásadní událostí, které přímo ohrožují chod systému. Přímý dopad na zákazníka/uživatele. Je nutný lidský zásah k odstranění příčiny. Jedná se o problém, kvůli kterému by vás měli vytáhnout ve dvě hodiny ráno z postele. Pokud se do vašeho systému nemůže někdo zalogovat, protože se nemůžete připojit do databáze, pak je to určitě ERROR.
WARN
Události, které nemají přímý dopad na zákazníka, nicméně jsou natolik závažné, že by se jim měl někdo ihned věnovat. Minimálně by pro ně měl existovat záznam v systému pro sledování incidentů, a mělo by dojít k jeho vyhodnocení. WARN používám například při kontrole konfigurace aplikace. Pokud se na produkci používají nastavení, které jsou určené primárně pro vývoj, určitě by to mělo vyvolat zdvižený prst. Události na WARN úrovni by měly znamenat, že chod systému může být ohrožen. Jako příklad uvedu nefungující cache, funkce systému není přímo ohrožena, nicméně může dojít k přetížení jiných komponent systému.
INFO
Běžné události v systému, ze kterých bychom měli být schopni poznat, co se dělo. Jedná se o události z pohledu vlastní infrastruktury (komponenta nastartovala, zastavena), ale i události z pohledu aplikační logiky (uživatel se úspěšně přihlásil, změna hesla, email byl odeslán atd.). Na této úrovni rozhodně nelogujeme události neočekávané, ty patří o úroveň výše.
DEBUG
Tato úroveň slouží pro zachycení velmi detailních událostí, podle kterých se dá velmi zrekonstruovat stav programu. Jedná se například o rozhodnutí (decision points), která proběhla, nebo měření času, který se kde strávilo. Tato úroveň bývá hodně ukecaná. Oproti předchozí úrovni zde logujeme události očekávané, ke kterým dochází zcela běžně např. získané databázové připojení, uživatel má tato oprávnění apod.
TRACE
Nejjemnější úroveň, která slouží v podstatě k debugování. Vypisují se stavy proměnných, volání metod apod. Tahle úroveň se používá jenom ve výjimečných případech, většina programů si bez ní vystačí. Rozdíl oproti DEBUG úrovni je v tom, že zatímco ta vám dává skoro přesný obraz, TRACE vám dává úplně přesný obraz.

Pokud by člověk logy analyzoval sám, pak by bylo skoro jedno, jakou úroveň logování by použil. Pokud z logu ovšem analyzuje více lidí, pak je pochopitelné, že bez správných úrovní budou pravděpodobně ztraceni. Dalším dobrým důvodem pro správné použití úrovní je monitorování a automatické poplachy pokud dojde k nějakému ERRORu nebo WARNu. Standardní úroveň zapnutá v produkčních systémech je INFO. Úroveň DEBUG se zapíná podle potřeby, protože logování na této úrovni může produkovat velké množství dat a systém zatěžovat.

Pár rad

Pokud nevíte jestli by měla být událost logována na DEBUG nebo INFO úroveň, zkuste se zamyslet nad tím, jestli se jedná o událost očekávanou z pohledu systému (DEBUG) a nebo výjimečnou (INFO).

//user session validity
if(System.currentTimeMillis() > userSession.getValidity()) {
    log.debug("User session has expired already");
    return false;
}

V tomto případě byla zvolena DEBUG úroveň, protože session vypršela a nejedná se o nic výjimečného.

if(userSession.cookie.id != userSession.httpParam.id) {
  log.info("User session id in cookie dosn't match with  session id in HTTP request param");
  return false;
}        

V tomto případě jsme zvolili INFO, protože došlo k situaci, kterou pokládáme za neočekávanou. Nemělo by k ní normálně docházet, pokud je vše v pořádku. Nicméně k ní může dojít a my se o tom chceme dovědět.

V některých případech používám DEBUG událost namísto vloženého komentáře v kódu. Původní funkce vysvětlit kontext zůstala zachována a navíc je jí možné použít pro popis toho co se v systému děje.


if(!shoppingCart.isEmpty()) {
    //Creates a new order based on the shopping cart
    return new Order(shoppingCart);
}
if(!shoppingCart.isEmpty()) {
    logger.debug(Creating a new order based on the shopping cart {} ", shoppingCart);
    return new Order(shoppingCart);
}

Vetšina logovacích knihoven (používáme SLF4J) dneska umožňuje používat parametry, díky tomu nemusíte sčítat řetězce. To není problém z hlediska výkonnosti, protože to za vás zoptimalizuje kompilátor, ale z hlediska čitelnosti vlastního kódu.

logger.debug("User " + user + " with login " + login + " updated profile ");
logger.debug("User {} with login {} updated profile", user, login);

Pokud máte události, které se budou strojově zpracovávat, je dobré tomu jít naproti. Například Splunk rozeznává a indexuje parametry. Parametr je cokoliv oddělené přes znak rovná se. Díky tomu jsem schopen dělat dotazy a analyzovat je.

log.info("action=request_processing_request status=end uri={} method={} time={} size={} httpStatus={}",...);


Poměrně často máme tendence logovat stacktrace, ačkoliv to není úplně potřeba. Stacktrace a výjimka by se měla logovat obecně ve chvíli kdy nevíme co s ní a nastala neočekávaně a nebyla ošetřena, případně si nejsme jisti příčinou. Potom nám totiž stacktrace pomůže hledat příčinu. Pokud víme k čemu došlo, výjimka resp. její stacktrace znepřehledňuje log.

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    ...
} catch (FileNotFoundException e) {
    log.error(e);
}

V tomhle případě, kdy známe důvod selhání, nemá cenu výjimku logovat. Namísto toho bychom měli zalogovat lidsky srozumitelně to k čemu došlo.

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    ...
} catch (FileNotFoundException e) {
    log.error("The  key file '{}' for signature verification doesn't exist");
}

Vždy bychom měli rozlišovat, jestli daná událost bude spíše určena člověku a nebo stroji k zpracování. Pokud logujeme události a bude je analyzovat člověk např, proto aby zjistil co se stalo, bude lepší použít mnohem obšírnější způsob s uvedením kontextu. Pokud máme události určené k strojovému zpracování, zvolíme formát tomu odpovídající. V aplikaci máme většinou zastoupeny oba dva typy událostí.

Závěr

Logování je běh na dlouhou trať. V tomhle článku jsem se snažil dát k dobru pár tipů a postupů, které používám a zdají se mi celkem užitečné. Samozřejmě můžete mít své vlastní postřehy. Nebojte se je sdílet v diskuzi pod tímhle článkem.

čtvrtek 14. června 2012

CZ Podcast 65 - Kryptografie, hacking, šifrování a další hrátky

Doslova s otevřenou hubou jsme si s pantátou Filemonem vyslechli předního kryptoanalytika Tomáše Rosu a připravili pro vás další díl podcastu. V tomhle podcastu skoro vůbec nemluvíme a jenom posloucháme Tomášovo záživné povídání o různých aspektech bezpečnosti, agentech NSA a expolitech iOS.

úterý 5. června 2012

Koncept hybridního jazyku

Pojem hybridní jazyk jsem zavedl sám pro sebe jako označení pro jazyky, které umožňují vytvářet klientskou i serverovou část aplikace jedním a tím samým dialektem. Schválně používám slovo dialekt, protože jazyk v tomto kontextu dalece přesahuje to co si pod tímto slovem představujeme. Hybridní jazyk je pro mě dialekt (popis chování programu) kompilátor/interpretr, který umožňuje adaptování dialektu na dané běhové prostředí představované serverem, mobilním telefonem, tabletem či webovým prohlížečem. Budoucnost vývoje může patřit právě jednomu z hybridních jazyků, které vznikají a nebo vzniknou. Proč by budoucnost měla patřit právě hybridním jazykům? Pokud se rozhlédneme kolem, pak v nově vznikajících jazycích, určených pro vývoj vícevrstvých aplikací, hraje zásadní roli právě fakt, jednoho dialektu, který se používá pro serverovou i klientskou část aplikace. Tato snaha je velmi akcelerovaná nástupem mobilních zařízení. Zároveň se nejedná o úlohu, která by byla jednoduchá. Tvůrci hybridních jazyků se musí srovnat s několika zásadními překážkami

Neprogramujeme ve vzduchoprázdnu.

Kód který vytváříme a navrhujeme vychází z konkrétních předpokladů o běhovém prostředí. Pokud budete mít kód napsaný v jazyku Java a budete mít k dispozici hybridní jazyk, kde bude Java jako jazyk jeho dialektem. Pak by měl být tento kód přenositelný na server i klienta. Díky specifikům jednotlivých zařízení a omezením běhových prostředí to už nebude tak jednoduché. Prvním problémem bude konkurenční přístup. Pokud kód vznikal v klientském prostředí, nebude pravděpodobně úplně připravený na běh ve vysoce konkurenčním prostředí serveru. V tomhle případě by musel hybridní jazyk, zřejmě jeho runtime, zařídit bezpečnou exekuci ve smyslu různých race conditions.

Stejně jako musí být respektován kontext z pohledu běhu programu, musí být respektovány prostředky, které cílové zařízení nabízí. Odstrašujícím příkladem byla technologie Swing, která selhala mimo jiné z toho důvodu, že nevypadala nikdy a ani se nechovala jako nativní aplikace. Hybridní jazyk bude muset podporovat chytré rozhraní, přes které půjdou využívat nativní funkce. Alespoň ze začátku by přes to samé rozhraní měla být možná práce s existujícími knihovnami. Klíčová bude integrace s knihovnami poskytujícími grafické rozhraní.

Dynamický mix

Dlouhou dobu jsem si myslel, že tím hybridním jazykem bude JavaScript. Stále více indícií mě vede k tomu, že to JavaScript být nemůže. Hlavním a zásadním nedostatkem je udržovatelnost kódu a zde mám obavy, že se to bude týkat jakéhokoliv dynamického jazyku. Na druhou stranu může být tím vhodným běhovým prostředím, do kterého se bude kompilovat či interpretovat hybridní jazyk. To mě přivádí k myšlence, že onen dialekt hybridního jazyka by měl mít rysy dynamických i staticky typovaných jazyků. Pro práci s daty se totiž hodí daleko více dynamický přístup. Mimochodem je to oblast, kde staticky typované jazyky selhávají viz úskalí jakékoliv mapování mezi reprezentací dat (XML, JSON, RDBMS) a jejich objektovou reprezentací.

Zrod odspodu

Hybridní jazyk se zřejmě zrodí, a nebo se již zrodil a my jsme to jenom nezaregistrovali, za úplně jiným účelem a k jeho adopci dojde mimoděk. Trochu mi to připomíná vznik a rozšíření Javy, která byla původně navržena a určena pro interaktivní ovládání spotřební elektroniky a až mnohem později se svezla s nástupem internetu. Nemyslím si, že může nastat situace kdy někdo přijde a řekne: mám hybridní jazyk a ten se stane průmyslovým standardem. To v současném vysoce fragmentovaném prostředí různých prohlížečů, zařízení a serverových technologií nelze. Spíše se bude jednat o postupnou evoluci. Moc nevěřím tomu, ale zároveň nevylučuji, že by to mohla být technologie, kterou prosadí někdo z velkých softwarových gigantů (Google, Microsoft, Oracle, IBM). Vede mě k tomu fakt, že ty jsou mezi sebou zaklíněni v různých patentových sporech a předsudcích a právních válkách. Jako příklad ilustrující tento klinč, řečeno boxerskou terminologií, by nám mohl posloužit jazyk Dart z dílny Google. Ony se samozřejmě na vlně hybridních jazyků svezou a přispějí k ní.

Alternativy

Mohou zde být alternativy k hybridnímu jazyku? Ano mohou za předpokladu, že stávají fragmentace při vývoji nebude nadále růst. Pak by mohlo dojít pouze k částečné transformaci současných technologií. Tahle evoluce má svoje limity, které mohou být právě s rostoucí fragmentací koncových zařízení a klientů rychle dosaženy.

Závěr

V tomto článku jsem se pokusil shrnout několik myšlenek, které mě vedou k přesvědčení, že vznikne a nebo již vzniknul hybridní jazyk. Zároveň jsem se snažil pojmenovat atributy jeho vzniku a základní charakteristiku. Prosím neberte tento článek jako projekci věcí budoucích, ale spíše jako myšlenkový experiment založený na aktuálních poznatcích.

pondělí 28. května 2012

Pět a jeden absurdní důvod proč nemáme v JDK podporu JSON

Pokaždé když pracuji v Jave s JSON mám pocit, že jsme stopadesát let za opicemi. Většinou sice používám skvělou knihovnu Jackson (pozor nejedná se o pohrobka ikony pop music Michaela Jacksona), ale i její použití je jako jíti s kanonem na vrabce. Mám úplně jednoduchou strukturu {"l":"0","u":"1","v":1338207547}, kterou bych rád deserializoval do mapy. Opravdu nerozumím tomu proč už v standardním JDK Javy neexistuje stupidní jednoduché API, které mi to umožní. Napadá mě několik vysvětlení.
  • Někoho rajcuje představa 100MB WARu k jehož dosáhnutí není potřeba vytvářet složitou aplikaci, ale vývojář si vystačí s pár základními problémy.
  • Tvůrci Apache Jakarta Commons nevědí co dělají. Nicméně to nebrání většině aplikací používat právě jejich knihovny.
  • JCP proces pro rozšiřování Javy je úplně k ničemu, neboť přidávání nových a potřebných API nefunguje. Mimochodem jak dlouho už čekáme na nové API pro práci s datumy? 
  • Nevylučuji ani možnost, že moje požadavky na něco čemu se říká JDK, tedy standardní vývojový kit,  jsou značně přemrštěné a všichni si posledních deset let vystačíme přibližně s jedněmi a těmi samými prostředky.
  • Práce na JSON je pro mě z nepochopitelných důvodů vázaná na Java EE. Touto logikou by ovšem v JDK nemohl skončit například HTTP server a nebo JAXB. O nesmyslech typu embedované databáze ani nemluvě.
  • JSON je technologie, o které nikdo v Oracle neslyšel. Případně si jí spojuje s konkurencí v podobě JavaScriptu.
Opravdu tomu nerozumím. Přidání nových API a rozšíření JDK je totiž oproti změnám syntaxe jazyka věcí zpětně kompatibilní. Můžeme se zde točit na faktu, že i nafouknuté JDK by bylo problém, ale z toho důvodu přece voláme po jeho modularitě.  Vlastně je to takový deadlock a teď se pomalu čeká na to kde to vyhnije.

Tam kde je možné Javu inovovat za cenu menšího rizika se to neděje. Namísto toho se její autoři pouští to riskantních podniků změny syntaxe.

pátek 25. května 2012

Pozor na minor updaty Javy

Do Javy 7u6 (update 6) a Javy 8 se chystá změna hashovacího algoritmu pro stringové klíče do všech standardních implementací java.util.Map (HashMap, Hashtable, LinkedHashMap, WeakHashMap, ConcurrentHashMap). Tvůrci si slibují, že díky těmto změnám sníží riziko kolizí a tím pádem nebude docházet ke zpomalení. Více si můžete ostatně přečíst v oznámení této změny. To co je na celé téhle záplatě zajímave je následující poznámka.

The iteration order of keys, values and entries for hash-based maps where the new algorithm has been invoked will vary for each HashMap instance. While the Java SE Map documentation makes no promises that iteration order of items returned from Maps will be consistent, developers should check if their applications have incorrectly created a dependency on the iteration order of Map entries, keys or values.

Přestože to je explicitně zmíněné v kontraktu Mapy, stejně bude existovat, a to bych se klidně vsadil, hromada kódu který třeba i nepřímo závisí na pořadí, v jakém se budou klíče vracet. Z mého pohledu je tohle zpětně nekompatibilní změna, ačkoliv skrytá a efektivní pokud dojde k naplnění určité podmínky (možná o to hůře protože to neodhalí standardní testy), a neměla jít rozhodně do updatu Javy 7. Osobně už jsem několikrát nepěkně sedl na lep vlastní slepé víře v to, že změny v updatech Javy jsou kompatibilní a nehrozí žádné riziko, a dal svolení k provedení updatu, protože nám přece nic nehrozí... Zvedám proto v tomhle případě varovný prst. Pozor na tenhle update, chyby v kódu se mohou projevit za velmi specifických podmínek a tedy velmi zákeřně.

neděle 13. května 2012

Spring framework tréninkové materiály

Tréninkové materiály k mému školeni Spring framework, jsou k dispozici na GitHubu. Prezentace k jednotlivým částem jsou odlinkované přímo z README.md a najdete je i na mém SlideShare profilu.

středa 9. května 2012

CZ Podcast 64 - iOS, iPhone, iPad

S tím zvukem to zase není úplně ono, ale jinak se nám s panem velkostatkářem Filem povedl dost luxusní podcast s týpkama z Inmite o vývoji pro iOS. Poslechněte si to a dejte nám vědět. Příště se bude točit buďto o hrůzostrašných historkách z korporací, abychom zase najeli na méně vážnou notu. Nebo budeme mít, a teď pozor, low level téma a podiváme se na zoubek hackování mobilních a webových aplikací. Slovy klasika: jsme otevřeni všem možnostem přátelé.

čtvrtek 3. května 2012

MongoDB pro Java vývojáře

Na včerejším setkání JBoss User Group v Brně jsem měl prezentaci na téma MongoDB. Slajdy najdete o kousek níže, rád bych ještě vypíchnul pár myšlenek, které zazněly, ale ze slajdů nemusí být úplně patrné.

  • NoSQL není jenom o velkých data. Speciálně MongoDB výrazně redukuje složitost persistentí vrstvy. Rozdíl mezi světem dokumentů a modelu tříd je mnohem menší než je to v případě relačních databází. Pro většinu aplikací, které v uvozovkách vezmou data a pošlou je na výstup, nepřináší relační databáze žádný benefit (kromě toho, že jste s ní pracovali posledních deset let ;-)
  • Při použití MongoDB a obecně NoSQL řešíte jiný typy problému, než které jste zvyklí řešit v relačním světě. Na druhou stranu vám odpadají problémy, které souvisí s managementem persistentního kontextu.
  • MongoDB není náhrada relačních databází, je to vhodný doplněk nebo alternativa chceteli. Relační databáze dávají perfektní smysl pro určité typy úkolů.
  • Smiřte se s tím, že občas povede návrh dokumentů k tomu, že budete mít redundantní data. Jinými slovy rovnou zapomeňte na nějakou normalizaci.

neděle 22. dubna 2012

CZ Podcast 63 - Mezinárodní spolupráce

V tomto díle jsme se rozhodli v trochu uvolněné atmosféře probrat téma mezinárodní spolupráce. Přece jenom v IT dochází k tomu, že se práce v mezinárodním prostředí stává normou. Jaké jsou jednotlivé národy, ke komu máme my čechoslováci blíž a ke komu naopak dále. Hostem tohoto dílu byl Jan Tajzich ze společnosti Vendavo CZ.

neděle 8. dubna 2012

Technologie a netechnická kritéria

Když jsem v předchozím článku podle některých totálně sepsul Javu, nezazněla od nikoho poznámka na téma komunita a nabídka pracovního trhu, doba nutná k zapracování nových vývojářů. Troufám si tvrdit, že na vývojářskou pozici v Jave jsme schopni do měsíce najít kvalitního člověka a za další měsíc jej efektivně zapracovat. To sice nic nevypovídá o tom, že Java je technologicky na špičce, ale vypovídá to cosi o tom, že existuje obecně akceptovaný způsob vývoje. To velmi usnadňuje spolupráci všech vývojářů neboť máme postupy, které se jenom mírně liší firmu od firmy.

Pokud pracujete s velmi novými a neprozkoumanými technologieme a nebo jdete až na dřeň (náš případ použití JavaScript - tlustý klient MVC, vlastní grafová knihovna), rovnou počítejte s tím, že obtížné bude jenom ty vývojáře najít. Neexistující a nebo malá komunita vám nenabídne skoro žádné možnosti ty vývojáře oslovit, případně si budovat pozici. Platí li teze Joela Spolskeho:... nejlepší lidé práci mají a rozhodně nechodí po pohovorech, pak si můžete rovnou najmout Sherlocka Holmese, aby vám je našel.

Samozřejmě vždycky se můžete pokusit vychovat si vývojáře z nováčků. To má ovšem zásadní nevýhodu v tom, že se to projeví v produktivitě celého týmu, a navíc nikdy nemáte jistotu, že se to povede. Jedná se o klasický kompromis mezi krátkodobým a dlouhodobým přínosem.

Na technologie můžete nahlížet několika různými pohledy a tyto netechnická kritéria mají skoro stejnou váhu jako ta technická.

p.s. Kdybych si měl vybrat technologii, pomocí které budu dělat klasické podnikové aplikace, šáhnul bych bez váhání po Jave. A to jenom z toho důvodu, že velmi snadno najmu lidi.

úterý 3. dubna 2012

CZ Podcast 62 - Nette framework

V díle 62. jsme vyzpovídali nestora české PHP scény a autora webového frameworku Nette Davida Grudla. Kromě technických aspektů jsme se bavili o tom jak Nette vznikalo, kdo ho používá, jak se David dostal k programování, no prostě klasické czpodcastí interview. Tímto bychom vás chtěli zároveň pozvat na natáčení dalšího dílu s pracovním označením Vývoj v multikulturním prostředí aka Asijská spolupráce, které proběhne 19.4.2012 od 18:30 ve firmě Vendavo CZ v Praze. Další detaily budou oznámeny na našem Twitter účtu. Pokud máte nějaké otázky, náměty, postřehy a komentáře sem s nimi do diskuze a nebo na náš email czpodcast zavinač gmail.com.

sobota 31. března 2012

Stavíme infrastrukturu kolem MongoDB - model

V poslední době jsem strávil nějaký čas psaním a vymýšlením konceptu persistentní vrstvy, nástrojů a jejich implementace, který nám umožní ukládat JSON dokumenty do NoSQL databáze MongoDB. Dokumenty i kolekce nemají žádné schéma. To má za následek, nebo alespoň u nás mělo, a divil bych se kdyby to někdo začal používat nějak sofistikovaněji, že moc nepřemýšlíte o struktuře dokumentů a prostě je ukládáte jak se vám zrovna hodí. To je velice příjemné a nějaký čas s tím vydržíte. Problém nastane ve chvíli kdy potřebujete ty dokumenty začít zpracovávat automaticky, například chcete udělat zálohu dokumentů vztahujících se k určité entitě v systému a nebo potřebujete zjistit, že odkazované dokumenty existují. Jinými slovy bez modelu popisujícího dokumenty, kolekce a jejich vztahy se neobejdete. Samozřejmě pokud si to nechcete dělat ručně v kódu pro každý typ dokumentu.

My jsme si data uložená v MongoDB popsali jednoduchým modelem reprezentovaným JSON dokumentem, který je sám v MongoDB uložený. Tento model slouží jednak pro nástroje, které dělají servisní operace, jako zálohy a jejich obnovu, validaci dat, čištění pohrobků apod.m a zároveň jím chceme řídit (zatím není implementováno) vlastní persistentní vrstvu, kterou ukládáme dokumenty.





Struktura modelu vypadá následovně.





DocumentStorageModel reprezentuje vlastní model. Má verzi, která nám umožňuje otestovat kompatibilitu dat s ním asociovaných. Typickým příkladem je záloha, ze které se snažím obnovit data, a rád bych se přesvědčil, že aktuální data a tedy i runtime je kompatibilní, a nepotkají mě nepříjemnosti po jejich obnovení. Verzí se zároveň řídí například migrace dat.

DocumentStorageModel obsahuje seznam kolekcí Collection. Každá kolekce má jméno, pod kterým existuje v MongoDB. Zároveň má dokumentaci Documentation. Ta obsahuje lidský srozumitelný popis toho, jaký typ dokumentu je v ní uložený. Dále release, ve kterém vznikla a URI template, pod kterým je vystavený na REST API. Záróveň může mít kolekce asociovaný ToolHints. Ten umožňuje popsat kolekci z pohledu nástrojů pro vytváření a validaci její definice přímo v MongoDB. Například dočasná data se vkládají do takzvané Capped collection, která automaticky odmazává nejstarší vložené dokumenty. Díky těmto hintům je možné ověřit, že je kolekce skutečně tímhle způsobem zkonfigurovaná.

Dokumenty a jejich struktura je popsaná v DataDefinition. Pro jejich validaci je možné definovat RelaxNG schéma (více o tom psal Lukáš Křečan v článku Converting JSON to XML). To se dá použít jednak v persistentni vrstvě pro validaci při změnách/zápisu a zároveň i pro verifikaci například po migraci dat.

Samostatnou kapitolou jsou relace. Šťastnější pojmenování by bylo reference v tomhle případě, aby to v člověku nevyvolávalo pocit, že se snažíme modelovat svět relačních databází. Dokumenty mezi sebou odkazujeme pomocí URI referencí. Máme celkem tři druhy relací: sama na sebe (SelfDocumentRelation), interní na jiný dokument v MongoDB (InternalDocumentRelation) a externí na dokumenty/entity uložené mimo náš systém (ExternalDocumentRelation). Každá relace má u sebe dva atributy cestu k fieldu, ve kterém je v dokumentu uložena a URI template, pomocí které je jí možné rozložit na jednotlivé segmenty. To se používá ve chvíli kdy potřebujeme zjistit příslušnost dokumentu k projektu nebo uživateli. Jednoduchým rozpársováním pomocí URI template víme konkrétního uživatele nebo projekt, ke kterému se dokument vztahuje.

Ukázka modelu

{
       "documentStorageModel":{
          "collections":[
             {
                "collection":{
                   "name":"subscriptions",
                   "affiliation":"PROJECT",
                   "resourceUriTemplate":"/gdc/projects/{project}/users/{user}/subscriptions/{subscription}",
                   "documentation":{
                      "description":"Contains notification subscriptions for given user in given project",
                      "releaseVersion":"R59"
                   },
                   "dataDefinition":{
                      "self":{
                         "selfDocumentRelation":{
                            "path":"subscription.meta.uri",
                            "uriTemplate":"/gdc/projects/{project}/users/{user}/subscriptions/{subscription}"
                         }
                      }
                   }
                }
             }
             ... další kolekce
             ],
             "version":"1.0.0"
        }
    }

Ukázka dokumentu popsaného modelem

{
     "subscription" : {
      "channels" : [
       "/gdc/account/profile/xxx/channelConfigurations/4f4b7e5ce4b0413360a0c4d5"
      ],
      "meta" : {
       "title" : "Test subscription",
       "author" : "/gdc/account/profile/xxx",
       "category" : "subscription",
       "updated" : "2012-02-27 14:00:12",
       "created" : "2012-02-27 14:00:12",
       "uri" : "/gdc/projects/FoodMartDemo/users/xxx/subscriptions/4f4b7e5ce4b0413360a0c4d7"
      },
      "message" : {
       "template" : {
        "expression" : "Hello World"
       }
      },
     }
    }

Z modelu je vidět, že v dokumentu by měl být field na cestě subscription.meta.uri a jeho hodnota by měla odpovídat URI template /gdc/projects/{project}/users/{user}/subscriptions/{subscription}. Z instance dokumentu je vidět, že tomu jak je viz /gdc/projects/FoodMartDemo/users/xxx/subscriptions/4f4b7e5ce4b0413360a0c4d7. Jednoduchou introspekcí této URI reference vidíme, že náleží k projektu FoodMartDemo.

Závěr

Cílem tohoto článku bylo nechat vás trochu nahlédnout do toho kam se v GoodData ubírá naše práce s NoSQL databází MongoDB. Potřeba modelu popisujícího data se ukázala jako nutnost. Na druhou stranu to není specifikum NoSQL světa, protože k podobné řešení, jsme již používali v HP SOA Systinet klasickou relační databází. Pokud máte podobné zkušenosti, a nebo naopak používáte jiný způsob k popisu dat a řízení nástrojů pro práci s nimi, určitě se podělte v komentářích pod tímto článkem.

čtvrtek 29. března 2012

Java s prstem na tepu doby

Java a celý její ekosystém čelí zásadním a novým výzvám, které jsou způsobeny posunem v oblasti mobilních zařízení, objemu zpracovaných dat i uživatelů. Ruku v ruce s tím jde vzájemná integrace heterogeních aplikací. Klíčová otázka zní, jakým způsoben je platforma Java, schopna na tyto výzvy reagovat a zároveň si zachovat statut klíčové technologe. Tento článek nemůže a ani nemá ambice na tuto otázku odpovědět, ale pokusí se přiblížit hlavní výzvy a možnosti, kterými se Java může ubírat.


Úkrok stranou


Prvotní a správná otázka je: proč se to všechno děje. Jedna z odpovědí leží pro programátory těžko uchopitelné a o to více ignorované škatulce s nápisem Business. Je historicky prokazatelné, že pouze pár programátorů (nedá moc velkou námahu si domyslet jejich jména) toto pochopilo a dokázalo úspěšně propojit technologickou výhodu s úspěchem komerčním. To je zároveň důvod, proč v čele většiny technologických společností nestojí programátor, ale někdo kdo dokázal spojit oba světy. Každý člověk, bez ohledu na vzdělání, pracovní pozici či věk, má inovativní nápady. Ovšem pouze menší část lidí dokáže začít tyto nápady realizovat. Ještě menší část těchto lidí na nich dokáže kontinuálně pracovat a dále je rozvíjet. A ta nejmenší část lidí je dokáže přetavit v úspěch [1].


První klíčovou veličinou je čas, za který se podaří nápad uvést do stavu, který je možné zpeněžit [2], bez ohledu na fakt jestli se jedná o jednotlivce nebo firmu. Druhou klíčovou veličinou jsou náklady, které s tím jsou spojené, provozní i startovací. Jedním ze způsobů, kterým lze výrazně redukovat čas nutným pro uvedení na trh, představuje volba správné technologie a platformy. Náklady lze do jisté míry redukovat pronájmem bez ohledu na to jestli se jedná o svět virtuální a nebo ten fyzický.


Kromě faktoru času a nákladu hrají přímou roli i veličiny, které není možné ovlivnit. Podle statistik World Internet Usage používalo Internet na konci roku 2000 celkem 360 985 492 uživatelů, ke konci roku 2011 je to již uživatelů 2 095 006 005 [3]. Podle typu operací je možné si udělat celkový obrázek o celkovém objemu dat. Za rok 2010 například služba Flickr hostovala 5 000 000 000 obrázků. Za ten samý rok bylo na sociální síti Twitter poslánu 25 000 000 000 zpráv takzvaných tweetů [4]. Podle odhadů firmy Cisco bude v roce 2015 připojeno 15 000 000 000 zařízení [5]. Zjednodušeně řečeno, velké množství uživatelů používá velké množství zařízení a produkuje velké množství dat. Čísly těžko uchopitelný údaj představuje i změna používání webu. Od prohlížení statických stránek nastal výrazný posun k dynamickému chování a webovým aplikacím. Tato změna je označována jako Web 2.0.


Výše zmíněné údaje jsou ve velké míře příčinou, a následkem je zrod přístupů či technologií jako Cloud computing, NoSQL databází nebo HTML 5. Tyto technologie zpětně způsobily a způsobují částečnou změnu architektury aplikací, a v neposlední řadě přímo ovlivňují jakým způsobem se aplikace samotné vyvíjí. Jestliže v polovině devadesátých let převládala dvouvrstvá architektura s takzvaným tlustým klientem, na začátku nového století došlo k posunu k architektuře třívrstvé, díky které mimochodem vznikla Java EE, a konceptu takzvaného tenkého klienta [6]. V dnešní době se již dá těžko mluvit o tenkém klientovi. Požadavky z pohledu uživatelského rozhraní i interaktivity aplikace vedou k přesunu části logiky ze serveru zpět na klienta. Ačkoliv by se mohlo zdát, že střední vrstva a server by si mohl oddechnout, opak je pravdou. Server musí být schopen velmi efektivně škálovat vzrůstající počet HTTP požadavků.


Java ekosystém

Když se řekne Java, mnoho lidí si představí pouze jazyk, ale ve skutečnosti se jedná o celý ekosystém též nazývaný platforma. Ta se skládá z několika klíčových součástí: srdcem je Java Virtual Machine, kolem ní je jazyk, dále nástroje pro vývoj a monitorování, a v neposlední řadě i knihovny. Ty standardní umožňující práci například se souborovým systémem, a potom velké množství open source knihoven pokrývajících prakticky cokoliv co člověk potřebuje.


Jazyk

Jazyk je jednou z možností, kde se může Java inovovat. Pokud se bavíme o jazyku, jedná se především o změny a rozšíření jeho syntaxe. Ty lze označit buďto jako zásadní viz případ Lambda výrazů (closures) [7] a nebo jako syntaktických cukrátek v podobě Diamantového operátoru (přidaný již v Jave 7). Společný problém těchto změn je zvýšení komplexity syntaxe jazyka a tím pádem zhoršení udržovatelnosti zdrojového kódu. Právě jednoduchá syntaxe a jistá míra konzervativnosti stále za velkou oblibou Javy jako jazyku. Mnohem závažnějším problémem je zpětná kompatibilita. Skryté nebezpečí totiž představuje provázanost jazyka a standardních knihoven resp. jejich API. Zavedení Lambda výraz totiž dává smysl pouze se změnou API např. u standardních kolekcí (Mapa, Seznam atd.), se kterými dává jejich použití teprve smysl. Nekompatibilní změna v těchto API by ovšem vedla k nemožnosti přenést velké množství existujícího kódu. Podobně velká změna syntaxe tohoto ražení v podobě Generik v Jave 5 dopadla dosti tristním způsobem.

Z dalších možností inovace na úrovni jazyku přichází v úvahu zbrusu nový jazyk. Původní Java by zůstala nedotčena a vytvořil by se nový jazyk, říkejme mu Java 2.0. Problém s Java 2.0 je v tom, že nikdo nedokáže říci, jak by měl takový jazyk vypadat a jaká kritéria by měl splňovat, aby přežil a byl úspěšný minimálně jako Java. Bez ohledu na finální rozhodnutí je pro Java platformu štěstím, že nad ní vyrostlo celé množství dalších jazyků tu s větší (Groovy) tu s menší (Scala) či dokonce žádnou podobností (Clojure), které je možné použít pro řešení specifických úkolů.


Standardní knihovny

Jednou z motivací, která stojí za snahou změnit jazyk, je komplexnost psaní kódu, který bude dobře škálovat na víceprocesorovém hardware, který je dnes běžně k dispozici. Bohužel vlákna a paměťový model, synchronizační primitiva to je oblast v Jave, která je příliš složitá a její plné pochopení představuje těžko proniknutelnou bariéru pro většinu programátorů včetně autora těchto řádků. Jenom málo na tom mění balík java.util.concurrent, který byl představen v Jave 5. Z programovacího jazyku Erlang a dalších se ukazuje, že je potřeba ještě vyšší úroveň abstrakce, kterou nabízí Aktory [8], Dataflow proměnných [9] nebo Softwarová Transakční Paměť [10]. Tyto konstrukty mohou být poskytovány jako nové standardní knihovny. I další úpravy standardních knihoven se týkají zvýšení propustnosti, například v podobě asynchronní podpory k blokujícím API jako je JDBC nebo HTTP klient.


JVM

Úpravy JVM [11] se musí týkat podpory velkých dat. Jedná se například o efektivnější reprezentaci řetězců a dalších datových struktur [12]. Problémy představuje je i správa velkých heapu (>10GB) a chování garbage collectoru, kdy při Full GC dochází ke kompletnímu zastavení práce JVM v řádu desítek minut [13]. Kromě úpravy chování bude potřeba přidat i další vlastnosti, které se dnes drátují manipulací s byte kódem. Řeč je především continuations, zmrazení a obnovení aktuálního stack frame, které umožní efektivní psaní aplikací postavených na asynchroniích voláních.

Z pohledu nasazení JVM do Cloudu se jedná především o podporu modulárního systému pro nasazování aplikací. Současný deployment model neumožňuje definovat moduly a jejich verze, které bude aplikace potřebovat, a vede k nulovým možnostem poskytování knihoven cílovým systémem. Typická aplikace díky tomu vypadá jako obrovský chumel JAR archivů, kde není jasné co je a není opravdu potřeba. Výsledkem jsou zvýšené paměťové nároky a pomalý start aplikací, který se díky čtení souborů ze systému podobá spíše zátěžovému testu souborového systému.


Nejsme tu sami

Vývoj v oblasti Javy dlouho trpěl díky přehlížení okolních trendů. Díky tomu je Enterprise verze (Java EE) v podstatě odepsanou technologií pro vývoj webových aplikací. V prostředí veřejných public cloud poskytovatelů to platí dvojnásob. Použitím technologie Java EE se vystavujete obrovským problémům při vývoji i nasazení tohoto typu aplikací. K zásadním nedostatkům patří složitost vývoje a nasazení. Bohužel většina technologií z Java EE stacku je absolutně nevhodná. Kromě ryze technických problémů jsou tu problémy v návrhu jednotlivých technologií. Většina z nich je totiž navržena stavově a s ohledem na to, že vývojář je absolutně odstíněný od prostředí ve kterém aplikace běží. S množstvím dat a požadavcích jednoduchosti vývoje se mění i architektura aplikací. Kromě návratu tlustého klienta, o kterém již byla řeč, se jedná o využívání NoSQL databází jako alternativy k databázím relačním. Je to plíživá revoluce, podobná té kterou spustil kolem roku 2007 framework Ruby On Rails, která bude ovlivňovat vývoj, technologie a knihovny v Jave. Největší chybou pro Javu a celý ekosystém by bylo, stejně jako v roce 2007, tyto trendy podcenit a nebo úplně ignorovat.

Jednou z nejsilnějších a zároveň nejslabších stránek Javy je její fragmentace. Neexistují jeden postup a knihovny pro řešení určitých typů problémů, na druhou stranu to umožňuje dynamicky se přizpůsobit na měnící se podmínky a vybrat vždy tu nejlepší kombinaci. Doufejme tedy, že se Java bude dál "fragmentovat" pod různými vlivy, kdy ty překonané uvolní cestu těm adaptabilnějším, díky nímž budeme my vývojáři schopni přetavit inovativní myšlenky a nápady.

Post mortem dovětek

Vzhledem k záplavě reakcí, které jsem k tomutu článku dostal, jsem se rozhodl, že uvedu pár věcí na pravou míru. Nebylo cílem Javu jakkoliv hanit, ale podívat se na její současný stav v kontextu trendů, které se v architektuře a vývoji aplikací objevují. Pokud některým čtenářům přijde, že z tohoto pohledu Java vychází bídně, je to čistě jejich interpretace výše uvedených řádků. Přiznávám, že jedním z postraních úmyslů, které mě při psaní článku vedly, bylo rozbití kliše, že existuje jedna správná technologie a tou je Java. Tím důvodem nejsou mé pochybnosti o Jave, ale víra, že žádná taková technologie neexistuje a existovat nemůže. Jsem hluboce přesvědčen o tom, že jediná správná cesta pro Javu je inovace na základě okolního světa, a nikoliv přešlapování na místě a předstírání, že Java je středobod vývoje okolo kterého se vše točí.

Celý článek je rovněž k dispozici na ABC Linuxu. Článek tam byl vydán jako součást kampaně firmy GoodData, ve které pracuji jako Java architekt. Věřím, že laskavý čtenář některého z těch přibližně 850 článků na tomto blogu, chápe že vše co píši, vyjadřuje můj osobní pohled a názory, pod které se vždy mohou podepsat. Proto zde článek uvádím v plném rozsahu s tímto dovětkem a možností jej komentovat.


Odkazy

1.
Andy Hunt, Pragmatic Thinking and Learning strana 66 - Everone has good ideas.

2. Wikipedia definice Time To Market.

3. Statistiky používání internetu.

4. článek Internet 2010 in numbers.

5. BBC new Technology předpověd firmy Cisco ohledně počtu zařízení.

6. Wikipedia definice Client–server model.

7. Projekt Lambda JSR-335 dedikovaný Lambda výrazům.


8. Wikipedia definice Aktor model

9. Wikipedia definice Dataflow proměnné

10. Wikipedia definice Softwárová transakční paměť


11. Úpravy JVM zaštiťuje projekt the Da Vinci Machine.

12. Prezentace JVM goes big data vysvětluje některé z problémů velkých dat nad JVM.

13. Článek objasňuje použíti konceptu BigMemory a odstranění GC přerušení BigMemory Explained a bit...

pátek 24. února 2012

CZ Podcast 61 - Roumen se vrací

Skoro nás na natáčení dílu 61. do CA nepustili, ale nakonec to stálo za to. Super jsme si s Roumenem pokecali a myslim, že to bude zajímavé i pro vás.

neděle 29. ledna 2012

Otrávené API

Otrávené API představuje situaci, která je důvěrně známá každému programátorovi. Během vývoje uděláte nějaké rozhodnutí, které se promítne do návrhu, struktury, výkonnosti či vhodnosti použití. Postupem času se ovšem ukáže, že to nebylo rozhodnutí úplně šťastné. Najednou máme v aplikačním kódu nebo hůře v infrastrukturním kódu něco o čem jsme přesvědčeni, že je špatně. Vždycky mi drásá srdce někomu vysvětlovat, že má použít ztrouchnivělé API, o kterém vím, že by tam nemělo být a nebo by mělo vypadat jinak. Chtěl bych se zmínit jaké možnosti máme, pokud tento problém nastane.

Metoda vyhnívání

Jedná se trochu o alibistický přístup ve stylu něco tam je, funguje to, sice je to špatně navržené, ale dá se s tím žít. Je to následování pravidla Pokud něco funguje, nesahejte do toho. Osobně tuhle metodu volím jenom když není jiného zbytí. Pokud jste nespokojeni s relativně izolovanou částí nejlépe aplikačního kódu, která se nepoužívá nijak často, prostě to nechte být. V případě, že se jedná o exponovanou část vaší infrastruktury, rovnou na vyhnívání zapomeňte a řiďte se dalšími radami.

Obalující rozhraní

Obalíte novým API to původní otrávené. Bohužel tahle metoda není úplně vždy proveditelná, protože málokdy se vám podaří úplně odizolovat implementační detaily. Jinými slovy, jestliže máte otrávené API, budete mít s velkou pravděpodobností i otrávenou implementaci, a kolem té se bude špatně stavit nové čisté API. Tato metoda vám nezabere tolik času na implementaci a testování jako metoda Paralelního API, která je popsána dále.

Paralelní API

kud řešíte zpětnou kompatibilitu. Ne vždy znáte nebo můžete změnit všechny místa použití. Proto vytvoříte paralelní implementaci s rozhraním. Nové a Otrávené API žijí v míru vedle sebe. Otrávené API můžete označit jako deprecated. Bohužel použití Otráveného API vám tam stále straší. V určitou chvíli proto zavřete oči a použijete metodu vykostění.

Vykostění

Pokud se rozhodnete pro nejradikálnější řešení problémů s Otráveným API. Jedná se o úplného odstranění Otráveného API a jeho nahrazení novou verzí. Preferujte tuhle metodu vždy pokud máte vaší code base plně pod kontrolou a zpětná kompatibilita pro vás nepředstavuje závažný problém. Všechny tři předešlé metody totiž hřeší na to, že prohlubují technologický dluh. Rizikem tohoto přístupu je, že po nějakém čase nemusíte byt s výsledkem spokojeni, a budete opět stát ve výchozím bodě.

Závěrečné doporučení

Refaktor kódu a jeho čištění by mělo patřit k základům práce každého vývojáře. Je to mravenčí práce, kterou málokdo ocení a nebo vám na ní poskytne čas. Nicméně s ní musíte počítat pokud nechcete mít problémy s udržováním a dalším rozvojem vašeho kódu. Já osobně preferuji Vykostění Otrávéného API. Takřka vždy se mi totiž ukázalo, že problémy které způsobilo jeho prorůstání do zbytku code base, byly nesrovnatelné s tím, co by stálo jeho včasné odstranění.