středa 29. prosince 2010

Moje soužití s distribuovaným verzovacím systémem Git

Téma distribuovaného verzovacího systému Git jsme s Filemonem nakousli v podcastu 44., ale protože jsem o tom chtěl napsat ještě před tím podcastem a navíc během toho natáčení člověka plno věcí nenapadne, rozhodl jsem se Gitu věnovat ještě pár řádek zde. Git používám posledních šest měsíců v GoodData a z toho asi polovinu hodně intenzivně a musím říci, že jsem z jeho možností úplně nadšený. Předesílám, že jsem byl velmi spokojený uživatel SVN a nic mi nechybělo, ale s použitím Gitu jsem dostal věci, které jsou opravdu velice užitečné.

Git dokáže pracovat decentralizovaně, to znamená, že může mít laptop úplně odpojený od sítě a vaše práce bude stále plnohodnotná. Git vám umožní dělat všechny operace nad repozitářem kromě pull a push, které jsou určené k synchronizaci se vzdáleným repositářem. Plnohodnotná práce znamená, že v offline módu můžete například přepínat mezi větvemi, dělat merge, cestovat historii vašich commitu (diff, blame, show atd.) a vůbec dělat další vylomeniny. Kdybych měl vypíchnout takové nejčastější operace, kterými mi Git zpříjemňuje život, pak to budou:

  • Stashovaní - máte rozdělanou práci a potřebujete se přepnout na jinou větev a nebo se vrátit obecně do určitého stavu repozitáře, ale nechcete o rozdělanou práci přijít. Přesně to stash umožňuje, je to zásobník na necommitnute věci, kam si je odložíte pro pozdější výbrání.
  • Squashování commitu - squash vám zjednodušeně řečeno umožňuje sloučení commitu do jednoho. Když pracuji na větším úkolu, kde dělám velké množství změn, tak v průběhu práce commituji průběžně. Když potom chci vypropagovat tyto změny do hlavní vývojové větvě (master), udělám to tak, že všechny commity sloučím do jednoho velkého commitu. Historie masteru, pak není tisíc a jeden commit, ale přehledný tok jednotlivých features a bugfixu. To umožňuje, aby se gatekeeper (správce repository) vyznal v tom co mu přibývá do větvě, které je považovaná v našem prostředí za stabilní a odladěnou.
  • Amend - umožňuje změnit poslední commit. Kromě toho, že múžu upravit například typo v commit message, může do commitu přidat další soubory atd.
  • Cherry pick - slouží k tomu, že můžete přenést jeden commit skrze několik větví. Klasickým případem jsou bugfixy, které je potřeba dostat jak do masteru, tak do větví z kterých buildujeme předprodukční a produkční mašiny.

Určitě jsem na něco zapomněl, napadá mě třeba možnost commitnout z daného souboru pouze jenom jeho část. Pokud Git používáte, máte možná svojí oblíbenou funkcionalitu, na kterou nedáte dopustit. To souvisí s tím jak Git používáte viz následující odstavce.

Git je dobrý sluha, ale špatný pán

Největší výhodou a nevýhodou Gitu je jeho flexibilita. Z SVN jsem byl zvyknutý na jistou šablonu používání - checkout, update, commit. V Git není jedna šablona používání, těch šablon je tolik, kolik vám nabídne Git možností a tím jak máte koncipovaný váš vývojový proces. Git rozhodně není nástroj, který vás povede za ručičku. Na druhou stranu můžete Git používat stejně jako jste používali SVN, ale potom je otázkou jestli vůbec na Git přecházet, pokud nemáte ani mentální ani technický problém.

Jak jsem již naznačil u squashování commitu náš vývojový proces orientován na masivní použití větví. Máme master větev (trunk), do které jdou odladěné věci. Na každou věc, kterou dělám, zakládám lokální větev, pokud potřebuji integrační testy a další vymoženosti, které poskytuje náš continuous integration systém, udělám tu větev i v centrální repository. Ve chvíli kdy jsem hotový, udělám merge do masteru.

Poznámka: osobně by se mi víc líbily separátní repository na větší komponenty s gatekeeperem, přes kterou by tekly všechny merge do masteru. Gatekeeper by pak udělal code review a v případě spokojenosti pusunul commit dál.

Na tomhle příkladu je vidět, že těch šablon jak používat Git je opravdu hodně a je jenom na vás najít si tu, která vám bude více vyhovovat. V podcastu jsme ještě naťukli konkurenční distribuovaný verzovací systém Mercurial. Podle ohlasů, které jsme dostali, je Mercurial v tomhle směru víc striktnější a proto možná jednoduší pro start do světa DVCS.

Nástroje

Z počátku mi dělalo velké problémy, že podpora Gitu do Eclipse je prachbídná. Nyní říkám díky za to. Problém nástrojů je v tom, že vás odstíní od toho jak Git pracuje a pokud to nepochopíte, budete mít později problém. Osobně si dokonce nedokážu představit jak dělám určité operace jenom z IDE. Díky tomu jsem se naučil používat Git z příkazové řádky a nenechám na to dopustit. Minimálně jsem se kromě Gitu naučil trochu ovládat i Vim. Pro uživatele Maca bych ještě doporučil GitX, který dokáže pěkně vizualizovat stav jednotlivých větví.

Chci se dozvědět víc

čtvrtek 23. prosince 2010

CZ Podcast 44 - Vánoce s Chuckem

Stahujte, sosejte a v klidu užívejte během svátků vánočních 44., protože to je ultimátni speciál.

čtvrtek 9. prosince 2010

Maven content check plugin - JARy pod kontrolou

V HP i GoodData jsme řešili problém s obsahem našich WARu, EARu a dalších distribučních balíčků, ve kterých se nám poměrně neřízeným procesem objevovaly nové JARy, což při použití tranzitivních závislostí v Mavenu není jev zas až tolik vzácný. To byl problém ze dvou důvodů.

  • problémy s některýmy OSS licencemi. Pokud do vašeho produktu zatáhnete nějakou knihovnu s virální licencí může to znamenat, že vlastní zdrojový kód musíte open sourcovat pod tou samou licencí. Jiné licence mají zase problém s tím, že se na ně váže IP, především patenty. Pokud použijete licenci, která má určitý výklad týkající se patentů, může se stát, že se tím automatický vzdáváte vámi držených patentů souvisejících s danou knihovnou.
  • problémy s tím, že někdo se rozhodně použít knihovnu XYZ a vy přitom ve zbytku produktu používáte knihovny jinou.

Tyto problémy se dají vyřešit poměrně jednoduchým způsobem. Máte autoritativní seznam souborů, který se může v daném archivu vyskytovat. Tento seznam kontroluje Maven Content Check Plugin a v případě, že archív obsahuje něco jiného, build selže s detailním výstupem, které konkrétní soubory nesedí. Konfigurace pluginu a formát autoritativního seznamu najdete v dokumentaci.

Plugin toho zatim moc neumí, za zmíňku stojí

  • dokáže ignorovat JARy, které produkujete vy a to podle obsahu jejich manifestu
  • dokáže reportovat i reverzní případ tedy že nějaké chybí

V dalších verzích pluginů se plánuje iniciální generování autoritativního seznamu podle obsahu archívu. Detekce typu licence pro daný JAR a její vypsání.

neděle 5. prosince 2010

Něco málo k testům

Byl jsem požádán, abych se podělil o zkušenosti s knihovnou JUnit 4 a zkušenosti obecně s psaním testů za použití této knihovny. Původně jsem to chtěl odbít jenom jednoduchou větou, že na jejím používání nic není, ale pak mě napadlo, že to není vůbec o té knihovně, ale o návycích, které jsem si vypěstoval při psaní testů. V tomto článku se kromě JUnitu zmíním o tom na co si dát pozor, jak psát testy a nebo třeba o skvělé knihovně Mockito, se kterou se testy píší snadněji. Doufam, že si každý v tomto článku najde to svoje.

JUnit

Předesílám, že jsem nikdy nepracoval s knihovnou TestNG a proto pokud vám v JUnit něco chybí, nevylučují že vám to tato knihovna neposkytne.

Když Kent Back psal JUnit verze čtyři, byly anotace už nějaký ten pátek součástí Javy. Zatímco v trojkové verzi JUnit jste museli dědit od třídy TestCase a vaše testovací metody musely obsahovat ve jménu slovo test, už si nejsem jistý, jestli na něj nemusely začínat, ve verzi čtyři stačilo použít anotaci @Test a označit metody, ve kterých byly vlastní testy.

Ve verzi čtyři přihodil JUnit další anotace a konstrukty, které jsem začal používat, ale k dokonalosti jim něco chybí. Anotace @BeforeClass a @AfterClass slouží k přípravě a úklidu před a po testech dané třídy. Určitě chválihodné, až na to, že mohou být použité pouze na statických metodách, což jejich použitelnost trochu degraduje. Rozumný důvod proč musí být statické jsem nenašel.

Chválihodné bylo zavedení čitelnější metody pro ověřování v podobě assertThat, v podstatě jiný typ assertu už ani nepoužívám.

import static org.hamcrest.CoreMatchers.is; 
Cart cart = new Cart();
cart.put("something"); 
assertThat("The method size returned wrong count of items in the cart.", cart.size(), is(1)); 

Problém s tímhle konstruktem je v tom, že jako druhý respektive třetí argument, pokud použijeme fail zprávu, bere org.hamcrest.Matcher a to je úplně jiná knihovna. To by nebylo až tak špatné, ba naopak, jenom kdyby se Kent Beck nerozhodl tenhle problém jiné knihovny vyřešit tím nejhorším možným způsobem. Prostě vzal část Hamcrest a zapekl jí včetně originálního balení do JUnitu.

To má samozřejmě za následek, že pokud chcete použít novější verzi Hamcrest tak máte smůlu. Novější verzi chcete většinou použít ve chvíli kdy si píšete vlastní Matcher a chcete, aby měl lepší fail message.

V jedné z pokročilejších verzí čtyřky se objevil i třída Assume s metodou assumeTrue(boolean). Přiznám se, že z počátku jsem z ní byl nadšený, ale postupem času mě to nadšení opustilo. Měla by se použít, že chcete před začátkem testu ověřit nějaký předpoklad bez jeho naplnění nemá smysl test pouštět. Problém s tímhle udělátkem je v tom, že jaksi nerozlišíte jestli test proběhl a nebo byl zaignorován. Takže to snižuje vypovídající hodnotu výsledku.

Obecné rady

Pište asserty se zprávou, která zasadí selhání testu do kontextu. Pokud takový test selže pomůže vám to pochopit jenom z výsledků testu co se kde pokazilo a nemusíte pak pracně dohledávat, který assert nedopadl a proč. To je zvláště užitečné pokud máte v metodě několik assertů. Zároveň to napomáhá i k čitelnosti a dokumentaci testu, kdy vidíme z jakého důvodu tam daný assert je.

assertThat("The method size returned wrong count of items in the cart.", cart.size(), is(1)); 

Používejte jména testovacích metod tak, aby vyjadřovala co testujete.

@Test 
public void testCartSize()....

Nekombinujte test jedné funkčnosti se všemi možnými asserty v jedné testovací metodě. Rozdělte asserty do testovacích metod a ty pojmenujte daným případem. Zlepšíte tím čitelnost a přehlednost testu.

@Test 
public void testCartSize() {
  Cart cart = new Cart(); 
  cart.put(new Item());  
  assertThat("The method size returned wrong count of items in the cart.", cart.size(), is(1)); 
  Cart cart = new Cart(); 
  assertThat("The method size returned wrong count of items in the new cart.", cart.size(), is(1));
} 

By mělo být

@Test 
public void testCartSize() {
  Cart cart = new Cart(); 
  cart.put(new Item());  
  assertThat("The method size returned wrong count of items in the cart.", cart.size(), is(1));
}

@Test 
public void testCartSizeOnNewInstance() {
  Cart cart = new Cart(); 
  assertThat("The method size returned wrong count of items for a new car  instance", cart.size(), is(1));
} 

Obecně čím jednoduší je kód testu a kratší tělo testovací metody tím lépe.

Vyhněte se testům, které spoléhají na jistou formu načasování. Nedávno jsem musel opravit test, který ověřoval, že hodnoty budou po určité době automatický odstraněné z cache.

 cache.put("Foo");
 assertTrue(cache.contains("Foo"));
 Thread.sleep(1000);
 assertFalse(cache.contains("Foo"));

Ten test někdy selhal a někdy prostě prošel a to ačkoliv se čekalo relativně dlouho. Problém byl totiž v tom prvním assertu. Pokud se totiž mezi provedením řádku 1 a 2 pustilo čistící vlákno cache, tak ten test jednoduše selhal. Odhlédněme od faktu, že v tomto případě, když už chceme otestovat nějaký předpoklad, tak by dávalo smysl použít asssumeTrue.

Především měla být konfigurace toho testu, kde se samozřejmě testoval i reversní případ s tím, že nějaké hodnoty se vrací z cache, nastavená tak, aby se čistící vlákno úplně vyřadilo ze hry. Pouze pro ten konkrétní případ se měl udělat setup kdy čistící vlákno bude aktivní, ale nebude se tam dělat ten první assert.

Obecné pravidlo, kterého je potřeba se držet zní: pokud není test spolehlivý, je lepší ho nemít. Doporučuji nemilosrdně přepsat testy, které vám někdy projdou a jindy ne, a vy nedokážete zjistit proč. V testech neexistuje něco jako 99.9 úspěch. Je pouze a jenom úspěch a nebo ne. Jiná interpretace typu ten test občas selže, to je ok, a to že jsem jí zažil, je jenom lhaní si do kapsy.

Důrazně bych doporučoval dodržet, aby testovací metody začínaly prefixem test, protože potom je pěkně přehledné, co je skutečná testovací metoda a co jsou nějaké helper metody. Zároveň je dobré pojmenovat test k dané třídě jménem třídy plus sufixem Test. Nic neudělá větší nepořádek, než když každý vývojář používá vlastní konvence.

V této souvislosti mi docela vadí, že IDE nekontroluje tuhle, řekl bych zaběhlou, konvenci. Mám tím na mysli, zapomenutou anotaci @Test na testovací metodě. Kolikrát jsem se radoval nad prošlými testy, abych pak nadával na to, že část se vůbec nepustila, protože jsem tam tu anotaci zapomněl vložit.

Jestli mají lidé odpor k psaní testu, tak je to většinou proto, že to je pro ně složité. Platí zlatá poučka, pokud se vám pro něco těžko píše test, pak v tom kódu něco smrdí. Pokud jde o složitý setup mohu jenom doporučit skvělou knihovnu Mockito.

Mockito

Mockito umí dělat mocky a stuby, tedy kromě toho, že něco vypadá jako kachna, tak to umí i jako kachna kvákat a umí to řící kolikrát to kváklo.

Item item = Mock.mock(Item.class);
Mockito.when(item.getPrice()).thenReturn(10); 
Cart cart = new Cart();
cart.put(item); 
assertThat(cart.getTotalSum(), is(10));
Mockito.verify(item).getPrice(); 

Jak je vidět práce s Mockitem je opravdu velice jednoduchá. Připravíme se stub Item, u kterého chceme, aby nám při volání metody pro získání ceny vrátil hodnotu deset.V tomto případě poslední verify, tedy že se na stubu něco stalo, není potřeba, a uvádím to zde pouze pro ukázku. Za použití Mockita nebo jiných podobných frameworku klesá komplexita psaní testů a to řádově. Já osobně jsem opravdu z Mockita nadšený, odpadlo mi totiž v testech tuna balastu, který byl potřeba pro úspěšný setup.

úterý 23. listopadu 2010

Proč použít Interface dohromady s abstraktní třídou

Hodně často se setkávám v kódu s tím, že vývojáři upřednostňují programování rozhraním. Především je to v případech kdy kód nabízí možnost rozšíření. Bohužel tohle není moc šťastný přístup a to z důvodů zpětně kompatibility. Ukážeme si to na následujícím příkladu.

public class Registry {
 public List<Plugin> plugins;
}
public interface Plugin {
 public void doSomehing();
}
public class PluginA implements Plugin {
 public void doSomehing();
}

Pokud tohle uděláte máte zaděláno na problém. Kdykoliv se v budoucnu rozhodnete přidat do rozhraní Plugin nějakou novou metodu automaticky tím rozbijete jakoukoliv třídu implementující toto rozhraní. V našem případě PluginA. Kolikrát tím rozbijete i kód, o kterém nemáte ani páru. V případě vlastního kódu je to problém rovnající se velikosti code base, ve které to dohledáváte.

Vždycky proto preferujte poskytnutí rozhraní s abstraktní třídou, která toto rozhraní implementuje.

public abstract AbstractPlugin implements Plugin {
 public void doSomehing(){}
}

Díky tomu můžete případné rozšíření jednoduše přidat do rozhraní a poskytnout defaultní implementaci. Pokud už je to opravdu zásadní zásah do rozhraní popřemýšlejte spíše o novém rozhraní, které bude odvozené z toho původního.

Pokud vás napadlo použít jenom abstraktní třídu namísto rozhraní, pak to není také moc šťastné řešení neboť je to příliš restriktivní. Případné rozšíření musí vždy dědit z vaší třídy. Rozhraní s abstraktní třídou proto nabízí nejlepší kombinaci.

středa 3. listopadu 2010

CZ Podcast 42 - dopisy, java, život a práce v Sillicon Valley

Tak se mi zdá, že v poslední době mám čas jenom na ty podcasty. Další díl naší talkshow jsme věnovali vašim dopisům, něco málo posledním problémům kolem javy, ale hlavně jsme měli hosta Huberta Palana a s ním jsme se bavili o tom jaké je to žít a podnikat v Sillicon Valley, což je pro našince téma hodně exotické. Nakonec se ukázalo, že pořekadlo "zlaté české ručičky", což jsem bral vždy jako klišé, platí i tam.

úterý 19. října 2010

CZ Podcast 41 - node.JS

Čtyřicátýprvní díl CZ Podcast je tu a s ním Dagi plus Filemon a host Jakub Nešetřil. Jakuba jsme si pozvali jako experta, evangelisty a nadšence do projektu node.JS, kterému jsme se v tomto díle věnovali. A že to bylo povídání zajímavé o tom není nejmenších pochyb.

pátek 1. října 2010

Hygiena kolem projektových souborů Mavenu

Když jsem si tu v předchozím příspěvku postěžoval na to, jak je složité znovu a znovu rozjíždět java projekty z pohledu setupu, měl jsem trochu pocit, že to jsou jenom brekot nad rozlitým mlékem. Abych se vykoupil, rozhodl jsem se dát k dobru praxí ověřená pravidla, týkající se hygieny kolem projektových souborů Mavenu. Samozřejmě pokud mě chcete doplnit vlastními tipy, rád si je poslechnu v komentářích.

Závislosti

Scope

První věc, o které přemýšlejte u každé závislosti je její scope. Hodně problémů projevujících se tím, že se divíte, kde se vám sakra bere tolik závislostí ve WARu je způsobeno tím, že u závislostí není správně scope. Sekundárním efektem je nabobtnalá konfigurace WAR případně Assembly pluginu, která maže tyto závislosti z výsledné binární distribuce.

Pro závislosti, na kterých máte runtime závislost a nepotřebujete je pro kompilaci použijte scope runtime. Pro závislosti potřebné pouze k testům použijte scope test a pro závislosti, které vám poskytuje běhové prostředí, např. Servlet API, použijte scope provided. Více informací o Dependency scope.

Centrální místo pro závislostí

Všechny závislosti a to včetně vašich vlastních definujte v dependencyManagement (neřiká nic o jejích použití) sekci vašeho centrálního POMu, ze kterého dědí všechny ostatní POMy. Pokud žádný takový nemáte, zaveďte si jej. Závislosti uvádějte vždy včetně defaultního scope. Tímto použitím získáte několik výhod. Především všechny závislosti máte na jednom místě.

V dceřiných POMech potom používáte závislosti identifikované jenom groupId a artifactId. Změna verze knihovny je potom zásah v jednom souboru. Další výhodou je právě určení verze knihovny. Díky tomuto použití určujete verzi pro všechny moduly a to včetně tranzitivních závislostí. Nestane se vám, že by se vám dostala jiná verze. Více informací o Dependency Managementu

<dependencyManagement>
 <dependencies>   
  <dependency>
   <groupId>cz.sweb.pichlik</groupId>
   <artifactId>example</artifactId>
   <version>0.1-SNAPSHOT</version>
  </dependency>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.1</version>
   <scope>test</scope>
  </dependency>
<dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
  </dependency>

  <dependency>
   <groupId>cz.sweb.pichlik</groupId>
   <artifactId>example</artifactId>
  </dependency>

Sdílené závislosti

Sdílené závislosti jsou ty, které nadefinujete v sekci dependencies rodičovského POMu. Doporučuji vám se jim obloukem vyhnout kromě třech výjimek - logování, testy a validaci vstupních argumentů. To je minimální průnik všech modulů.

Vyloučení závislostí

Pokud chcete nějakou závislost vyloučit, protože není potřeba, typicky tu zatažená nějakou špatně definovanou 3rd party závislostí, je nejlepším způsobem definovat tuto závislost v dependencyManagement se scopem provided. Samozřejmě tento trik aplikujte pouze za předpokladu, že nikdo tu závislost opravdu nepotřebuje.

 
<dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.1.1</version>
 <scope>provided</scope> 
</dependency>

Analýza závislostí

Pokud se chcete podívat na zoubek závislostem, například chcete zkontrolovat jaké závislosti má váš modul, použijte příkaz mvn dependency:tree. Tento příkaz zobrazí původ všech závislostí v textové podobě.

Pokud chcete naopak zjistit, jestli váš modul nějaké závislosti používá, ale nemá je deklarované (vedlejší efekt tranzitivních závislostí), případně naopak, nepoužívá, ale má nadeklarované, pak použijte příkaz mvn dependency:analyze -DignoreNonCompile. Tento příkaz analyzuje přímo byte kód, proto je potřeba, aby byla závislost v lokální Maven cache (prostě jenom mvn install -DskipTests).

Běžné věci

  • Poukud používáte name element v POMu, pak je dobré, aby měl stejnou hodnotu jako artifactId. Důvod je veskrze praktický, Maven vypisuje po každém příkazu summary provedení za jednotlivé moduly. Pokud příkaz pustíte v multimodule projektu a name necháte na lidové tvořivosti, bude se vám těžko dohledávat, o který modul vlastně šlo.
  • S tím souvisí dobrý návyk a to udržovat artifactId unikátní.
  • Nedávejte souboru specifické pro IDE do verzovacího systému. Většina IDE co stojí v Jave za zmínku totiž dokáže číst přímo POMy. Specifické soubory pro IDE jsou většinou nějak spjaté s konkrétním fyzickým umístěním a použitou verzí IDE a proto nepřenosné.
  • Pokud vznikají vazby mezi moduly, které nedávají smysl, což se většinou ještě projevuje rovněž tím, že někde vybublají nechtěné závislosti, je to tím, že vývojáři jsou líní nebo se bojí dělat specializované moduly. Typickým příkladem je modul, kterému pracovně říkám test-support. To je modul, do kterého dávám podporu pro testy jako například mock objekty, specializované předky apod. Tento modul má potom scope test, to znamená, že jeho závislosti nikam neprobublají.

středa 29. září 2010

Kdo s čím zachází, s tím také schází

Lukáš Křečan nedávno napsal o tom co ho štve na Jave. Já bych ho trošku podpořil, protože občas mám pocit, jako bych roztlačoval parní lokomotivu. V poslední době jsem rozcházel několik Java projektů pro pár vývojářů, kteří chtěli nastartovat webový vývoj a musel jsem se tedy hluboce stydět. Přestože mi Maven říká pane, tak rozběhnout plnohodnotný projekt včetně setupu IDE mi zabralo skoro půl dne.

Nevím proč, ale od jisté doby nabízí Maven snad stopadesát archetypu (kostra aplikace), bohužel skoro všechny jsou víceméně nepoužitelné. Stejně vždycky skončím u ručního tunnningu. Počínaje nastavením kompilátoru na Javu 1.6, přes upgrade jUNit na 4.8.1 a konče nastavením SLF4J závislostí pro logování a vyloučením Commons logging.

Další pohromou jsou vývojové nástroje. Rozběhnout Maven v Eclipse včetně WTP je magie a to nepodotýkám z toho důvodu, abych vám nabídl svoje služby. Navíc v týmu se najdou vždycky nějaké černé ovce, které používají NetBeans a nebo IntelliJ IDEA.

Když tuhle lokomotivu konečně roztlačíte, máte z toho nevýslovnou radost, ale zároveň jistou pachuť na jazyku. Čím dál tím víc jsem přesvědčený, že tahle fragmentace Javy a jejího ekosystému je ukrutná dvousečná zbraň. V Jave neexistuje ani na ty nejjednodušší otázky jediná odpověď. Chcete příklad, tak si položte otázky Jaké IDE, co na ukládání, jaký webový framework, jaký server, jaký buildovací nástroj. Na každou z nich může napsat v odpověď celý elaborát.

Na jednu stranu máte v rukách úžasnou volnost, ale na druhou nesmírně heterogenní prostředí, na kterém si můžete pěkně rozbít hubu. Jinými slovy nejsilnější zbraň Javy je zároveň její nejslabší stránkou.

středa 8. září 2010

Koncentrace v 25 minutách

Stává se vám, že po nějaké době v práci nejste schopní udržet koncentraci, což se projevuje většinou tím způsobem, že zkratkovitě brouzdáte poštou a interneten? Mě se to stávalo celkem často, navíc to mělo ještě jeden efekt, o kterém se zmíním později. V poslední době zkouším techniku Pomodoro, na kterou mě navedl @filemon a musím řici, že to opravdu pomáhá.

Pomodoro. Mimochodem název pochází z časovače, který se používá při vaření a má tvar rajče, v Česku jsem tedy spíš viděl vajíčko. Ačkoliv možné je cokoliv, protože moje kulinářské dovednosti končí u přípravy čaje. Takže Pomodoro se skládá z následující pěti kroků.

  • vezmete si úkol
  • nastavíte si časovač na 25 minut
  • pracujete na úkolu po dobu 25 minut
  • po 25 minutách si dáte 4 minuty pauzu
  • Po každých čtyřech Pomodorech (4x25) si dáváte 20 minut pauzu

Během těchto pěti kroků je nutné dbát několika pravidel, kdy jsou dvě zásadní. První pravidlo, po dobu 25 minut neodbíháte od daného úkolu. Pokud už opravdu musíte, například šéf po vás něco chce, někdo vás přijde otravovat, potřebujete na záchod, protože oběd v čínské restauraci se nepovedl apod. pak prostě Pomodoro zabalíte, tedy zresetujete časovač a po chvilce začnete znovu. Druhé pravidlo, skončením Pomodora po 25 minutách vám padá automaticky klávesnice z ruky a vy se čtyři minuty případně dvacet (delší přestávka) věnujete něčemu jinému.

Těch pravidel je trošku víc, stejně jako postupů jak ošetřit situace, kdy si například vzpomenete, že potřebujete honem ještě něco udělat mimo úkol, na kterém právě pracujete. Vřele doporučuji knihu (v PDF zdarma ke stažení) přímo od autora Pomodoro Francesca Cirillo.

Postřehy

Pokud se člověk naučí dodržovat to, že během přestávky děla opravdu jiné věci (čtu maily, sleduju twitter, začtu se do novin co mám na stole) a hlavně nemyslí na úkol, na kterém pracuje, pak se dostaví ahá efekt. Kolikrát se mi stalo, hlavně při programování, že mě napadlo "to je nesmysl, takhle to nemůžeš dělat" nebo "sakra ještě je potřeba tohle a tohle, tenhle úkol nebude tak snadný jak se mi zdálo".

Hodně často při finišování nějakého úkolu něco přehlédnu. I když mi teď zbývá k dokončení úkolu subjektivně minutka, pak to nikdy nedělám pokud právě skončilo Pomdoro. Prostě si dám přestávku a doklepnu to v tom dalším. Opravdu hodněkrát se mi stalo, že z té minutky bylo dalších celé Pomodoro, protože jsem někde něco přehlédnul.

Zkusil jsem několik Pomodoro prográmků a nakonec to pro Mac OS vyhrál Pomodoro Deskto díky tomu, že je to opravdu jenom časovač.

Vyzkoušení Pomodora je opravdu jednoduché, vyžadujete to jenom trochu disciplíny a hlavně funguje to. Subjektivně mám pocit, že se nedostavuje tak často pocit, kdy je potřeba úplně na hodinu vypnout mozek, protože jsem poslední čtyři hodiny úporně kódoval. Navíc dělám méně bot, protože focus/defocus módu vidím širší konsekvence.

středa 25. srpna 2010

Selži rychle, selži smysluplným typem

S tímhle problémem v uvozovkách si lámu hlavu pokaždé, když na něj narazím. Mám rád, nechci říci blbu vzdorný kód, ale kód který selže v případě chyby tak nejrychleji jak jen to půjde a zároveň s informací o tom co šlo špatně. Teď nemám na mysli zrovna chybu způsobenou uživatelem, ale třeba jiným programátorem včetně mě samotného. Jinými slovy můj kód je postaven na nějakých interních předpokladech. Otázka je, jakým správným typem výjimky reagovat na porušení těchto předpokladů.

Vezmeme si následující modelový příklad. Mějme třídu představující auto a jedním z jeho atributů je barva.

 
public class Car {
 public enum Color {RED, GREEN, BLUE};
 
 private final Color color;
 
 
 public  Color getColor() {
  return this.color;
 }
} 

Mějme API, které pracuje s touto třídou. Toto API je založené na předpokladu, že auto má vždycky nějakou barvu.

 
public boolean isWomanCar(Car car) {
 if(car == null) {
  throw new IllegalArgumentException("car must not be null"); 
 } 
 return car.getColor().equals(RED);
} 

Kód správně kontroluje vstupní argument, ale zároveň je založen na předpokladu, že barva nebude nikdy null (v rámci ilustrace pomineme fakt, že by šel přepsat na null safe v tomhle případě). Protože chci selhat rychle a né někde v hlubinách na NullPointerException upravím kód, tak abych můj předpoklad explicitně vyjádřil.

 
public boolean isWomanCar(Car car) {
 if(car == null) {
  throw new IllegalArgumentException("car must not be null"); 
 } 
 
 if(car.getColor() == null) {
     throw new ?????? 
 }
 return car.getColor().equals(RED);
} 

Předpoklad jsem zachytil, ale váhám jaký typ výjimky je proto vhodný. V podstatě jsem svůj výběr zúžil na IllegalArgumentExceotion, AssertionError a nějaký vlastní typ AssumptionException. Proti IllegalArgumentException hovoří to, že jí používám pro předpoklady vstupních argumentů. Na druhou stranu já v podstatě kontroluji předpoklad, který se týká vstupního předpokladu. Proti AssertionError zase, že by se neměla používat na cokoliv co souvisí se vstupem, ale na druhou stranu tohle použití se nejvíce blíží k čemu byla navržena. AssumptionException nechci protože zavádí nějaký můj vlastní typ, jehož významu rozumím já, ale těžko nějaký vývojář, který bude API používat.

Výše uvedený příklad je velice zjednodušený, aby se to něm pěkně ilustrovalo. Ale určitě i vy máte spoustu kódu, který na něco spoléhá. Já nakonec asi stejně skončím u IllegalArgumentException, protože mi přijde jako nejmenší zlo.

sobota 21. srpna 2010

CZ Podcast 40 - Java jako Cobol korporací

Další díl CZ Podcast je tu a s ním Dagi plus Filemon a host Pavel Vybíral. Původně měl být tento díl kontroverzní. Nakonec se nám z toho vylouplo povídání na téma proč je Java tolik silně zakořeněná v bankách a jestli tuto její pozici jen tak něco změní . Pohodlně se usaďte, dejte si svůj oblíbený nápoj, případně nandejte sluchátka pokud právě cestujete další podcast právě začíná. Jo a nezapomeňte nám napsat na czpodcast zavináč gmail.com

neděle 1. srpna 2010

Continuous Deployment

Už jsme to téma nakousli s Filemonem Obrienem99 v podcastu 39, ale stejně bych se mu věnoval speciálně. Od té doby co nejsem jenom korporátník vidím, že svět mimo enterprise (podnikové) aplikace nabízí hodně inspirativních témat. Již jsem psal o NoSQL databazích a nebo o JavaScriptu. V GoodData se hodně bavíme o Continuous Deploymentu, tedy jak co nejrychleji dostat kód kterému věříme do produkce. Kdy měřítkem rychlosti nejsou měsíce, týdny, dny a nebo hodiny, ale minuty.

Neděláme krabicový software, nemůžete si nás koupit jako jogurt a odnést domu a pak si nás vychutnat. Produkujeme službu, kterou naši uživatelé konzumují prostým klikáním ve webovém prohlížeči. To nám přináší tu výhodu, že naše náklady spojené s releasem nenese uživatel. Oproti krabicovému softwaru je ten posun v tom, že nemusíme například podporovat heterogenní prostředí, do kterých se aplikace nasazuje a s tím spojené problémy.

O čem je Continuous Deployment

V Continuous Deploymentu jde o to, že máte prostředky a infrastrukturu, která vám umožní nasadit každý důvěryhodný commit přímo do produkce v řádech minut. Opravdu to není bláhová myšlenka, jak by se možná zdálo na první pohled. Dělá to takhle celá řada internetových služeb jako třeba Facebook. Trochu netradičně dám teď uprostřed článku pár odkazů, které vedou na skvělé povídání o Continuous Deploymentu a pak zkusím připojit pár vlastních postřehů.

Testy

Sledujete občas rallye sport? To jsou ty blázni co se řítí v závodních speciálech po úzké šotolinové cestě v rychlostech kolem dvoustovky, nejlépe s třicetimetrovou strží po obouch stranách vozovky. Piloti jsou zde vydáni absolutně do rukou navigátor, který čte z itineráře rychlostní zkoušky charakteristiku tratě - jaká je další zatáčka, profil tratě, nebezpečná místa atd. Jedna chyba a končíte nohama v lepším případě vzhůru a v horším napřed.

V Continuous Deploymentu jsou vývojáři řidičem a testy jeho navigátorem. Pokud se nemůžete absolutně spolehnout na testy, končíte podobně jako v rallye. Spolehlivé testy, kterým věříte jsou alfou a omegou celého snažení. Kromě toho, že ty testy jsou spolehlivé, musí být samozřejmě rychlé. Vzpomínám si jak jsme ještě za dob Systinetu běhali integrační testy několik hodin a jak díky složitému deploymentu nebyly spolehlivé. Kdy spolehlivost v Continuous Deploymentu popisuje Timothy Fritz z INVU následovně.

When I say reliable, I don’t mean “they can fail once in a thousand test runs.” I mean “they must not fail more often than once in a million test runs.” We have around 15k test cases, and they’re run around 70 times a day. That’s a million test cases a day. Even with a literally one in a million chance of an intermittent failure per test case we would still expect to see an intermittent test failure every day. It may be hard to imagine writing rock solid one-in-a-million-or-better tests that drive Internet Explorer to click ajax frontend buttons executing backend apache, php, memcache, mysql, java and solr

Se znalostí Javy jsem přemýšlel, jak bylo možné dosáhnout rychlosti proběhnutí testů v řádech jednotek minut (testy se pouští pro každý commit). Neexistuje jednoduchý recept, musíme kombinovat od každého trochu: paralelní spuštění testů, "share nothing" mezi testy, mockování. S tím úzce souvisí i design a návrh architektury aplikace. Aby bylo možné takto vůbec testovat, nesmí být aplikace napsaná nebo nedej bože navržená jako zapečené italské těstoviny.

Infrastruktura

Druhým klíčovým aspektem Continuous Deploymentu je infrastruktura, která automatizuje celý proces - počínaje VCS hookem, přes monitoring a konče commitem či rollbackem změny v produkčním clusteru. Nenarazil jsem na nic standardizovaného, pokud to vůbec jde, a tak to vypadá, že si to každý stlouká doma na koleni krom continuous integration serveru.

Dobrá otázka, která mě napadá na závěr. Proč bych vůbec měl chtít, aby se moje změny dostaly co nejrychleji do produkce. Je to prostě a jednoduše konkurenční výhoda. Čím rychleji to dokážeme, tím rychleji stačíme reagovat na požadavky našeho businessu. Říká se tomu schopnost dělat rychlé obrátky. Další nespornou výhodou je, že už nemusíte mít nákladné oddělení kvality, protože klikání máte zautomatizované a lidi z QA se mohou věnovat opravdu kvalitě.

Kultura a lidé

Jestli o úspěšnosti nějaké metodologie rozhoduje kultura a lidé v týmu, pak u Continuous Deploymentu to platí dvakrát tolik. Continuous Deployment je nasaditelný pouze pokud máte lidi, kteří píší testy ne protože je k tomu vede nějaké nařízení, ale protože tomu opravdu věří. Mottoem může být parafráze názvu jedné knihy "Test je mým druhým pilotem".

2.8.2010 - Obrienovo pohled na věc:

sobota 31. července 2010

CZ Podcast 39 - Operations a Devops

Díl 39 se opravdu povedl, to protože Obrien99 má téma operations a devops zmáknuté a tak jsme vydrželi povídat, ja tedy spíš poslouchat skoro celou hodinu. Pokud vám ty termíny nic neříkaji, pak je tenhle podcast přesně pro vás a pokud ano, pak si ho stejně poslechněte, protože je vněm plno zajímavých informací i třeba o releasování.

sobota 24. července 2010

JavaScript vládne všem

Varování tento článek může budit velkou kontroverzi. Pokud se v něm mluví o minulosti, přítomnosti a budoucnosti, je tak činěno v kontextu internetových aplikací. Eneterprise (podnikové) aplikace mají vlastní svět s jinými zákonitostmi nicméně bylo by zarážející kdyby se jich níže napsané vůbec nedotklo.

Když člověk pracuje s partou lidí, kteří píšou aplikaci v určité technologii, jako se to stalo mě v GoodData, otevře mu to prostor k tomu, aby se dozvěděl plno nových informací a posunul svoje vnímání určité oblasti do širšího kontextu. Od dob kdy jsem psal v JavaScriptu já už uběhlo pěkných pár let. A upřimně už bych ten dnešní kód považoval za jiný jazyk. On ten jazyk ve skutečnosti zůstal v hodně rysech stejný, jenom se posunul způsob jak vypadá architektura klientských aplikací a to mělo pochopitelně za následek, že se začaly používat konstrukce a přístupy, které před tím nebyly potřeba.

Dříve bylo opravdu běžné, že JavaScript sloužil na straně klienta pouze k tomu, aby umožňoval připravit data k odeslání na server případně k manipulaci s UI prvky na stránce. Ta doba skončila ve chvíli, kdy se objevil koncept asynchronního dotazování serveru známý pod názvem AJAX a servery místo komplexních odpovědí začaly poskytovati i ty dílčí. Najednou se architektura aplikací posunula k něčemu co označujeme jako rich client.

Točíme se v kruhu

Se softwarovou architekturou, je to stejné jako s módou, historií, designem či čímkoliv jiným. Točíme se v kruzích, jenom s každou otáčkou maličko chytřejší, dlužno dodat doufejme. Stejně jako jsme utíkali od konceptu tlustých klientů, abychom mimo jiné ušetřili jejich omezené zdroje, se teď k těmhle klientům vracíme, protože zdroje serveru jsou ještě omezenější. Jisté koncepty fungují jinak v prostředí lokální sítě a jinak v prostředí Internetu.

Namísto toho, aby se JavaScript používal na straně klienta jako doplněk, přebírá roli tažného koně. Už to není server, kdo rozhoduje o posunu aplikace z jednoho stavu do druhého, ale je to klient. To sebou samozřejmě nese nároky na to kolik kódu je najednou na klientu. Najednou se i v JavaScriptu hledají způsoby jak psát klientský kód (část aplikační logiky) podle Model-View-Controller vzoru, aby byl kód udržovatelný a nebyla z něj koule špaget. Daleko není doba (možná už nastala), kdy vznikne i v klientských aplikacích silná poptávka po Inversion of Control k řešení problémů těsných vazeb.

Změna architektury klientských aplikací rovněž vedla k velké zátěži prohlížečů, především v oblasti výkonných a paměťově šetrných JavaScript podvozků. Takový V8 engine běhající v Google Chrome je natolik výkonný, že je nad ním postavený nodeJS server kompletně založený na JavaSciptu.

JavaScript jako dominantní jazyk "desktopu"

Jestliže se mění architektura aplikací je na místě ptát se proč se tomu děje. Odpověď je ukrytá v tom kam se posouvají naše data a služby, které používáme. Už to není desktop, lokální počítač, ale vzdálený počítač, a desktop respektive prohlížeč je pouze terminál (nevracíme se opět na začátek?). Budeli nějaký jazyk v budoucnosti dominovat desktopu, v našem smyslu chápání místo odkud používáme služby a data, bude to bez pochyby JavaScript jako jazyk platformy (prohlížeče), na které aplikace běží.

Pokud se mě zeptáte, jaký jazyk se učit s výhledem do budoucnosti, odpovím vám bez váhání JavaScript. Samozřejmě i celý ten ekosystém okolo jako je JSON, HTML 5.

A naopak je zbytečné se bavit o tom, který jazyk je budoucností pro server, protože to není vůbec podstatné z pohledu architektury, kterou mají a budou mít internetové aplikace.

čtvrtek 22. července 2010

Příběh jedné URL

Mohla to být úplně nezajímavá změna, něco co prostě přejdete mávnutím ruky, ale není. V maličkostech se skrývají podstatné rozdíly. Když Oracle "udělal" Sun, slyšeli jsme mnoho zpráv o tom, jak Oracle bere Javu vážně. Od doby permanentního připojení k internetu a schopností Google splnit mé nejtajnější přání nemám na disku Javadoc (dokumentace) k standardnímu API Javy. Prostě pokud se potřebuju na něco v API podívat, zásadně tak dělám přes Google. Prostě a jednoduše zadám jméno třídy, bum a voala tady je výsledek.

Protože Google indexuje a hledá tak jak hledá, někdy dostane člověk starší verzi Javadocu. Příklad dostanete URL http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html, vás zajímá verze 1.6, tak co uděláte, změníte číslo pět za šest, bum a voala tady je výsledek podle očekávání.

Pardon, nenechte se uvést v omyl, takhle to fungovalo, než se Sun stal součástí Oracle. Nastala migrace na IT infrastrukturu Oraclu. Místo těhle člověku pochopitelných URL vás teď čeká následující paskvil v podobě URL http://download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/api/java/lang/Object.html. Kromě toho, že URL je opravdu příšerné, tak změny verze záměnou čísel nefungují. Opravdu by mě zajímalo, co nebo kdo je E17476_01 a co znamená magické cd v URL. Perličkou pak je, že Oracle servery jsou opravdu příšerně pomalé. Ono to tedy spíš vypadá, že ten server bude jeden.

Někdy minulý týden jsem si na to stěžoval na Twitteru. Dneska jsem tam zaznamenal, že si toho všimli i další lidé. Oracle už s tím asi někdo pěkne vyplísnil protože: @oracletechnet: Yes, have noted javadoc URL issues and we are exploring solutions with IT right now. Please stand by..

Nejenom tahle událost (viz Mračna, sluníčko a nebo smrádek a teploučko nad Javou ) ve mě budí dojem, že se Java prostě dostala u Oraclu na druhou kolej. Neberu jakékoliv argumenty o přechodu na novou infrastrukturu. Jestliže beru Javu seriozně, jak můžu jednoduchost dostupnosti její dokumentace takhle zpriznit. Odpověď je, že jí asi moc seriozně neberu.

neděle 11. července 2010

Eventuálně konzistentní

V prvním článku zde na Dagblogu jsem se snažil zachytit základní myšlenky kolem NoSQL (Not Only SQL) databází. Převážně jsem mluvil o key/value databázích. Samozřejmě rodina NoSQL databází je mnohem širší, kromě key/value databází máme například grafové databáze (Neo4j, HyperGraphDB) specializované na ukládání hierarchických struktur a nebo databáze pro ukládání dokumentů reprezentované poměrně známou CouchDB a nebo MongoDB. Každý z těchto druhů NoSQL databází exceluje v jiné oblasti, kde nám klasické relační databáze nedostačují ať již z hlediska objemu dat, rychlosti, ceny, efektivity.

Všechny a nebo lépe řečeno většina těchto NoSQL databází (výjimky nevylučuji) se vyznačuje takzvanou případnou konzistenci dat. Pro většinu z nás je konzistence našich dat posvátnou krávou. Není se čemu divit, dvacet let jsme psali aplikace nad relačními databázemi v čase a prostoru definovaném ACID kde jsme konzistenci drželi referenční integritou a orámovali transakcemi. Jenom velice těžko si představujeme, jak naše data nejsou konzistentní a nebo lépe řečeno pohled na ně v určitý časový okamžik.

Případná konzistence

Abychom se vůbec probojovali k tomu, co eventual consistency znamená, musíme začít ze široka. S masivním rozvojem internetových aplikací rostl i objem dat, se kterými tyto aplikace pracují a nebo které je potřeba zpracovat. Nemusíme si hned představovat všechny ty giganty jako Facebook, Twitter a další sociální sítě, ale stačí obyčejné služby pro agregaci článků a nebo nástroj, kterým si analyzujeme data (třeba logy) vygenerovaná námi provozované aplikace. Zjednodušeně řečeno, problém relačních databází nastane ve chvíli kdy do nich hrneme hromady dat, se kterými potřebujeme pracovat. Především psát nad nimy dotazy - dělat pohledy na tato data.

S velkým objemem dat řešíme jak škálovat read a write operace. Klasický přístup pro škálovatelnost write operací je takzvaný sharding. Tedy, že data podle určitého klíče fyzicky sepratujete. Write operace jsou totiž narozdíl od čtecích vždy na určité úrovni vzájemně blokující. Jednoduchý přístup, je ten že data všech lidí začínajících na písmeno A dáváte do jiné tabulky než data lidí začínajících na písmeno B. Případně neděláte rozdělení na úrovni tabulek, ale rovnou databází. Pro rozprostření dat podle klíče se zde používá technika zvaná consistent hashing. Pro operace čtení se používá takzvaný replica read. V takovém scénáři máme databázové servery v master/slave módu. Kdy některé čtecí operace (nemusí nutně všechny) směřujeme na slave servery..

CAP teorém, vyberte si dva

Existuje něco, čemu se říká CAP teorém, podle kteréhho mají systémy tři základní atributy - dostupnost, konzistenci dat a partioning (fyzické rozdělení). Podle tohoto teorému je možné dáshnout pro distribuované systémy pouze dvou z nich. Vzhledem k tomu, že v předešlých odstavcích jsme si řekli, že pro zvládnutí velkého objemu dat potřebujeme sharding, to znamená že dochází k partioningu (data máme fyzicky na jiných serverech), zbývá nám volba mezi konzistencí dat a dostupností.

V případě, že konzistence dat je pro nás absolutní prioritou na úkor dostupnosti, znamená to, že náš systém jako celek může být v určitých momentech nedostupný. To je daň za to, aby jsme nepřečetli například data, která jsou zastaralá. Pokud je naopak absolutní prioritou dostupnost systému na úkor konzistence dat, znamená to, že v určitých chvílích můžeme číst data, která jsou zastaralá. Této konzistenci se říká případná. NoSQL databáze jsou charakterizované právě případnou konzistenci, ve smyslu "časem konzistentní" ši "výsledně konzistentní", s tím že mají vysokou míru dostupností.

Případná konzistence se jí říká protože klient čte konzistentní data jenom za splnění určitých podmínek, ve kterých se systém může nalézat. I případná konzistence má několik stupňů jako Read-your-own-writes. Pro zajímavost, v prostředí internetu je jedním ze základních systému pracující s případnou konzistencí DNS a jeho propagace změn skrze cache s definovanou dobou vypršení.

Pro vaší aplikaci to znamená, že můžete pracovat s daty, které nemusí být aktuální. Nemá cenu dodávat, že jsou typy úloh, pro které je tato konzistence dat akceptovatelná a pro které již ne. Například autoři CouchDB by se nebáli pomocí ní naimplementovat bankovní systém, chce to prostě jiné recepty.

Zdroje

neděle 4. července 2010

CZ Podcast 38 - Korporace a startupy

S Filemonem jsme v tomhle letnim počasí trochu popustili otěže, pokud jsme je vůbec kdy dřímali v rukouch, a zafantazirovali jsme na téma korporace a startupy.

pátek 28. května 2010

My z komplikovaného světa

Proč máme posedlost v přetechnizovaných řešeních? Není to dávno co jsem se přistihl při tom jak, mažu část zdrojových kódů v SVN. Jako memento bych si nejraději vypálil na pravé předloktí zkratku KISS (keep it simple and stupid). Pochopitelně raději čínsky, abych v nejhorším prohlásil, že to je část z jídelního lístku činského bufetu za rohem a důsledek mladické nerozvážnosti. Kdo z nás může s klidným svědomím říci, že nikdy neudělal nic co by nebylo přetechnizovaného.

Přetechnizovaní je stav kdy používáme technologie, postupy a vytváříme abstrakce, které nám z krátkodobého hlediska házejí klacky pod nohy a z dlouhodobého hlediska nemají ten efekt, který očekáváme.

Pro jeden z projektů jsem potřeboval úložiště dat. Vesměs sada XML dokumentů hierarchicky orgranizovaných plus metadata. Strávil jsem skoro čtrnáct dní implementací tohoto úložiště. Samozřejmě k úložišti bylo potřeba udělat uživatelské rozhraní pro správu dat. Jak to tak bývá, ukázalo se, že drobná změna zadání a praktická zkušenost rozcupovala mé představy o tom, že úložiště je skoro hotové. Po několikahodinovém souboji vlastního vědomí a svědomí jsem racionálně zvážil všechna pro a proti a raději existující kód smazal, aby mě v zbytečně neprovokoval. Asi za dva dny jsem naimplementoval a otestoval tu samou funkčnost nad obyčejným souborovým systémem. Hierarchie je pomocí adresářů, některá metadata byla nahrazena prostou konvencí v názvech souborů resp. jejich přípon a metadata jsou obyčejné XML dokumenty. Jako uživatelské rozhraní lze použít jakýkoliv souborový manažer. Trvanlivost dat a jejich verzování lze zařídit jakýmkoliv Version Control System nástrojem (SVN, CVS atd.).

Jaké ponaučení jsem si odnesl? Někdy je potřeba udělat krok zpět, aby mohl člověk udělat dva dopředu. Z jakého důvodu vytváříme stále přetechnizovaná řešení je mi neznámo. Možná jsou více vzrušující, když je nosíme v hlavě. Možná máme prostě utkvělo představu, že to není vlastně tak složité. Možná nevěříme, že 80% je hodně a kvůli 20% to obětujeme. Občas si prostě vybájíme architektonická omezení, která nás mají ochránit před nukleární katastrofou a přitom nám hrozí nanejvýše prvomájový deštíček. Tak či onak KISS.

středa 26. května 2010

CZ Podcast 36 - Concurrency

Díl 36 byl opravdu skvělá a hlavně poučná zábava. S Václavem Pechem jsme probrali pojmy concurrency, data flow, stm, actors, fork-join a další. Původně měl díl trvat 25-30 minut, ale nakonec jsme jej utnuli skoro po 50 minutách a další půl hodiny jsme mimo záznam s Filemonem tahali z Václava rozumy. Až tolik nás tohle téma zajímalo. Užijte si to alespoň jako my.

sobota 15. května 2010

Mračna, sluníčko a nebo smrádek a teploučko nad Javou

Honza Novotný a Lukáš Křečan se vypravili na letošní GeeCON a zprostředkovali nám své postřehy z tamního dění GeeCON – cast prvni, GeeCON 2010 – den první a GeeCON 2010 – Den druhý. Jestli mě něco z těch zpráv zarazilo, pak to byla neutuchající víra ve světlé zítřky Javy. Musím se tedy přiznat, že po přečtení rozhovoru s A Discussion with Josh Bloch on the Future of Java a toho co jsem se dozvěděl od kluků, vidím několik zásadních problémů.

Jedno vcelku jednoduché pravidlo říká, že ten kdo neinovuje, bude koukat na svět leda zpod kytek. Nemusí se inovat příliš, ale inovovat se prostě musí, jinak vás konkurence dříve nebo později zadupe do země. Jenže my se dozvídáme pouze samé Jobovy zvěsti. JCP jako hlavní standardizační hybatel dění v Jave je v podivném klinči zájmů jednotlivých skupin a s nevyřešenými problémy ohledně licencí k TCK. Sun evidentně vývoj Javy 7 podcenil a tak se dozvíme, že bylo uvolněno málo zdrojů ať již lidských a nebo finančních. Dnes jsme v situaci, kdy se pořádně neví co v Jave 7 vlastně bude. O nějakém datu vypuštění nemůže být řeč. Při prezentaci o clusures jsem měl mžitky před očima, když jsem viděl jakým amatérským způsobem se řídí věc tak zásadní jako tato (přidávají se do bety!). V tomto kontextu je jistě zajímavé zjištění, na jaké všechny oblasti má dopad rozšíření jazyka.

Korunu všemu nasadí chystané zaříznutí dvou implementací JVM pod jednou střechou (JRockit a HotSpot). Chápu, že není ekonomické, živit dva různé týmy dělající stejnou věc. Na druhou stranu, kde by byly obě JVM bez toho, aniž by si konkurovaly? To co je dobra zpráva pro lidi držící kasičku, není dobrá zpráva pro nás uživatele. Nedokážu si dost dobře představit, jak se budou obě řešení spojovat ani technicky ani lidsky.

Nic neplatí v ITt víc, než že stav věcí není ani tak dobrý, jak se prezentuje na konferencích, ale ani tak zoufalý, jak jej vidí lidé uvnitř dění (insideři ze Sunu). Java teď neleží ve stádiu klinické smrti, ale ani nad ní nesvítí sluníčko na cestě k lepším zítřkům. Pravda je tak někde uprostřed, nazval bych to ne zrovna moc poeticky: smrádek, ale teploučko. Bohužel tenhle vegetativní stav má tendenci se zhoršovat. A přiznejme si to upřímně, jestli nepřijde někdo, kdo s tím začne pořádně hýbat, tak se nic nezmění. Trochu mám obavy, že to nebude Oracle, minimálně pokud napne síly k JavaFX. To by mohlo pomoci jednotlivým částem platformy, ale nikoliv celku.

čtvrtek 13. května 2010

CZ Podcast 35 - startup Korekt.me

V dalším díle naší/vaší oblíbené show jsem vyzpovídali Martina Adámka. Martin se pokoušel prorazit s online službou korekt.me na korekturu cizojazyčného textu. Protože nejsme jenom banda geeku, přišlo nám zajímavé položit mu pár otázek na téma, jak se takový startup rozjíždí, co je důležité, kde udělal chyby, jak daleko je od první myšlenky k realizaci a jaké si odnesl ponaučení.

neděle 9. května 2010

Jak jsem si užil Service Oriented Architecture v praxi

Poslední půlrok jsem strávil na zajímavých projektech v jedné z největších bank tady v Česku. Musím říci, že největším zjištěním pro mě bylo něco co bych nazval SOA v praxi. Musím se upřimně přiznat, že před tím, než jsem poznal praxi, přišla mi SOA jako věc příliš abstraktní, pod kterou jsem si nedokázal představit nic konkrétního. Bohužel tato třípísmenná zkratka je natolik zprofanovaná, že těžko najít něco zprofanovanějšího. Pokud se oprostíme od nánosu všeho toho květnatého humusu, myšlenka jako taková se skutečně realizuje. Jak to funguje v praxi se pokusím nastínit na následujících řádcích.

V bankách se donedávna stavěly aplikace s monolitickou architekturou. Ta byla tvořena dvěma částmi frontend a backend, které byly úzce spjaté.

Tohle architektonické rozložení sil vám hází nejeden klacek pod nohy. Především je to špatná znovupoužitelnost toho co nabízejí krabičky s názvem backend a frontend. Pokud to chcete změnit, pak je prakticky nemožné vzít páteř bankovních systému v podobě backendu a začít z ní vytrhávat jednotlivé obratle a ty měnit za něco nového. Jediný možný způsob provedení je vystavení funkcionalit backendu pomocí služeb. Vnímavý čtenář pochopil, zde přichází přerod v SOA. Bohužel backendy jsou často prehistorické systémy, kde schopnost vrátit data v XML je čestnou výjimko. Povětšinou se používají se textové či binární zprávy.

V praxi to znamená, že je potřeba služby vystavit na nějaké infrastruktuře, která umožní použít prostředky, jenž považuje naše doba za standardní. K tomutu účelu se používá Enterprise Service Bus (ESB), která hravě zvládne konverze na úrovni transportního i aplikačního protokolu. Jako technologie se používají Webové služby (SOAP over HTTP).

Takto použité uspořádání znamená, že služby vystavené na ESB definují model. V případě SOAP over HTTP se jedná o model zpráv, které služby přijímají a vracejí. Tento model musí jednak respektovat všechny informace, které potřebují backendy a jednak musí být dostatečně obecný, aby klient nebyl svázaný s konkrétní implementací backendu, nechceme vytvářet příliš těsné vazby. Tento model se nazývá Canonical Data Model (zkráceně CDM).

CDM je jakýmsi lingua franca, pomocí kterého si systémy vyměňují zprávy. Ačkoliv to není na první pohled patrné, CDM je coarse grained, tedy nemusí vždy obsahovat všechny co potřebuje konkrétní klient případně to nemusí být úplně ve vhodném formátu pro interní aplikační použití. Jako příklad může posloužit entita Adresa. Ta je v CDM definována určitým způsobem, ale frontend (klient obecně) může mít různé požadavky na to co všechno si ještě k adrese potřebuje navěsit, například Skype účet, IM účet apod. V takovém případě už máme modely tři, ten poslední je již specifický pro danou aplikaci.

Aplikační model již bývá interně namapován na technologie použité uvnitř aplikace pro ukládání nebo zobrazení. To znamená, že se na něj lepí různé technologické anotace případně je ohýbán, aby se dobře používal. Každá aplikace si musí vyřešit přemapování z aplikačního modelu do CDM modelu. Což lze udělat ručně programově a nebo pomocí šikovné knihovny Dozer.

Samozřejmě, aby to nebylo ještě málo složité, tak máme různé verze modelů a k nim potřebujeme nějakou governance (správu). A to už se dostáváme za rámec tohoto článku a pro mě oblastí neprobádaných.

Na závěr bych ještě pár vět věnoval něčemu málo patrnému, ale o to více důležitému. Žádný vývoj neprobíhá velkým třeskem, to znamená, že služby se průběžně vytvářejí a objevují. Stejně tak služby nejsou vždy dostupné a nebo není možné pro vývoj použít jejich živé systémy. Z tohoto důvodu velkou pozornost získávají simulátory služeb, které vůbec umožňují a výrazně zjednodušují vlastní vývoj aplikací postavených v SOA prostředí. Povídání o simulátorech služeb si ovšem nechám na někdy příště.

středa 28. dubna 2010

CZ Podcast 34 - NoSQL databáze

Po dlouhé odmlce jsme se opět sešli a připravili takové kratší povídání, ve kterém jsme naťukli NoSQL databáze. Doufáme a slavnostně slibujeme, že naše odmlka nebude dlouhá ;-).

sobota 24. dubna 2010

Key/Value databáze

Na jednom z projektů jsem použil pro ukládání dat key/value databázi a rád bych se podělil o několik postřehů, které jsem získal. V mém případě jsem jako key/value databázi zvolil Voldemort a to z toho důvodu, že je kompletně napsaná v Jave. Původně vzniknul Voldemort jako interní projekt používaný službou LinkedIn, který byl posléze uvolněn jako open source a je dále rozšiřován.

Před tím než se pustíme do větších detailů, musím ukázat klientské API, přes které s Voldemortem komunikujete a můžete ho očekávat od každé key/value databáze. Jedná se o rozhraní podobné mapě, které má tři metody put, get a delete.

String key = "dagblog.url";
client.put(key, "http://dagblog.cz");
String value = client.get(key);
client.delete(key);

Kdy použít key/value databázi

Jednoduchá odpověď se nabízí, všude tam kde se nehodí relační či jiná databáze. Já osobně jsem key/value databázi zvolil ze dvou důvodů výkonnost a jednoduchost ukládaných dat (to byl vstupní předpoklad zadupaný dalším vývojem ;-). Díky tomu, že všechny operace jsou řízené přes klíč, lze velice jednoduše škálovat (architektura Voldemortu) a rychlost odezev je relativně stabilní bez ohledu na to kolik dat je uloženo.

S tím souvisí i další věc a to je vlastní API, které máte k dispozici. Možná jste si již všimli, že API nemá žádnou metodu, kterou by bylo možmé hledat dat. K dispozici není ani žádný dotazovací jazyk typu SQL. Z toho vyplývá několik poměrně nezanedbatelných architektonických omezení, které je potřeba vzít v potaz.

  • Nemůžete udělat projekci dat, kdy spojíte dvě či více entit přes join (o tom jak řešit joiny si povíme později.). K datům se nedostanete jinak než přes znalost jejich klíče.
  • Není možné vytáhnout pouze část dat. Převedeno do prostředí relačních databází a SQL to znamená nemožnost v select části dotazu specifikovat sloupečky.
  • Není možné udělat dotaz, který najde data jednoho typu. Převedeno do řeči SQL select * from table.
  • API nenabízí žádnou možnost transakčního zpracování či hlídání integrity dat. Konzistence dat tedy plně leží na bedrech aplikace.

Otázka číslo jedna proč tomu tak je a otázka číslo dvě komu to prospěje. Všechna výše uvedená architektonická omezení mají za cíl umožnit právě jednoduché škálování a tím i brutální výkonnost. Tato kritéria vám naopak naznačují, že key/value databáze nebude vhodná pro aplikace, které potřebují dělat složité dotazy nad daty. Případně aplikace, kde by přechodná nekonzistence dat (ve smyslu přechodu stavu několika svazaných hodnot pod různými klíči) mohla znamenat problém, například převod peněz z jednoho účtu na druhý.

Samozřejmě key/value databáze mají kromě výkonnostních i další výhody. Díky jednoduchému API se dají jednoduše zamockovat. Všechny testy i vývoj částí závisejících na key/value databázi pohodlně obsloužíte mockem, který představuje mapu držící ve potřebné v paměti. Data, které ukládáte jako hodnoty, nemusíte normalizovat jako v případě relační databáze.

Voldemort a praktické zkušenosti

Nakonec se počet entit ukládaných pomocí key/value databáze zastavil na počtu 15. Mluvím o entitách v případě key/value databáze, protože jsem potřeboval ukládat celkem komplexní graf složený právě z různých entit (tříd) a k nim jsem potřeboval pár pomocných struktur.

Díky tomu, že jsem nakonec ukládal graf a potřeboval jsem vytahovat jeho části, muselo dojít k jisté dekompozici. Každá separátně ukládaná část grafu měla svůj vlastní dedikovaný prostor (tabulku v řeči relační databáze) nazývaný store.

Každý store může používat různé strategie pro serializaci a deserializaci klíčů a hodnot, které ukládáte. Voldemort podporuje celou řadu formátu JSON, Thrift , Protocol Buffers, Java serializaci a další. To prakticky znamená, že můžete vaše objekty serializovat jako celky. Já jsem použil JSON, protože díky tomu měl každý store svoji definovanou strukturu.

public class User {
 private String firstName;
 private String lastName;
    
    ...
}

V případě JSONu byl formát storu {"firstName":"string","lastName":"string"} a tato struktura byla v Jave reprezentovaná jako java.util.Map, kterou vyžaduje Voldemort pro ukládání dat v tomto formátu.

User user = new User("john", "doe");
Map value = new HashMap();
value.put("firstName", user.getFirstName());
value.put("lastName", user.getLastName());

//uložení dat
client.put(1, value);

//načtení dat
Map map = client.get(1);
String firstName = map.get("firstName");
String lastName = map.get("lastName");

Při konfiguraci storu na použití Java serializace by kód vypadal následovně (nutný předpoklad, že objekt User implementuje rozhraní java.io.Serializable) ).

User user = new User("john", "doe");

//uložení dat
client.put(1, user);

//načtení dat
User user = client.get(1)

Jak na joiny

Už jsem naznačil, že key/value databáze nenabízejí možnost dělat joiny, proto pokud je potřebujete, musíte je udělat programově a nebo zohlednit při návrhu storu. Nejdříve jak to uděláme programově. Řekněme, že entity User se ukládá do jednoho storu a entita Address do jiného storu. V takovém případě musím být chopen na základě znalosti uživatele zjistit všechny jeho adresy. Nejjednodušší možností je poznamenat si při ukládání uživatele klíče všech adres.

Address address = new Address("Na konci světa", "Zatavi", "12345");
User user = new User("john", "doe", address);

Map addressValue = new HashMap();
addressValue.put("street", address.getStreet());
addressValue.put("city", address.getCity());
addressValue.put("zipcode", address.getZipcode());

addressClient.put(1, addressValue);

Map userValue = new HashMap();
userValue.put("firstName", user.getFirstName());
userValue.put("lastName", user.getLastName());
//uložíme se klíče asociovaných adress
userValue.put("addressKeys", Arrays.asList(new Integer[]{1}); 

userClient.put(1, userValue);

Programový join při čtení vypadá analogicky

Map userValue = userClient.get(1);
List addressKeys = userValue.get("addressKeys");
for(int key: addressKeys) {
 Map addressValue = addressClient.get(key);
}

Tímto kouskem kódu si dotáhnu všechny asociované adresy. Voldemort umožňuje i hromadný get, abych nemusel bych v kódu procházet přes jednotlivé klíče, ale rovnou bych předhodil jejich množinu. Ne vždy je ovšem žádoucí, a v případě key/value databází to platí dvojnásob, dělat dekompozici ukládání na úrovni entit. V podstatě jediný důvod pro dekompozici je v případě, že je těch dat velké množství a nebo s nimi potřebujeme manipulovat (get/put) bez ohledu na zbytek systému. Pokud u vašich dat vidíte velkou nutnost dekompozice je to známka toho, že není vhodné používat key/value databázi.

Pokud se joinu chcete vyhnout, múžete data uložit společně. Tedy jeden společný storage. V našem případě by to mohlo vypadat následovně.

Address address = new Address("Na konci světa", "Zatavi", "12345");
User user = new User("john", "doe", address);

Map addressValue = new HashMap();
addressValue.put("street", address.getStreet());
addressValue.put("city", address.getCity());
addressValue.put("zipcode", address.getZipcode());

Map userValue = new HashMap();
userValue.put("firstName", user.getFirstName());
userValue.put("lastName", user.getLastName());
userValue.put("addresses", Arrays.asList(new Map[]{addressValue});

client.put(1, userValue);

Nebo v případě, že bychom použili Java serializaci.

Address address = new Address("Na konci světa", "Zatavi", "12345");
User user = new User("john", "doe", address);

client.put(1, user);
 

Postřehy

V projektu, kde jsem Voldemort použil, jsem si napsal tenkou vrrstvu, která mi umožňovala transparentním způsobem ukládat jednotlivé entity. Každá entita měla tři metody metody, jednu pro vráceni klíče, vlastní reprezentace jako mapy (hodnota) a jednu metodu, která měla zrekonstruovat stav objektu z mapy. Zároveň jsem naimplementoval lazy loading pro entity, které v grafu objektů nebyly ještě načtené. Tím se zefektivnil počet dotazů na storage a celkový objem přenášených dat.

Při použití Voldemortu a myslím si, že to jde obecně generalizovat na jakoukoliv key/value databázi, došlo k tomu, že persistentní vrstva aplikace pěkně narostla. Bylo to právě nutností dělat všechnu tu logiku jako joiny, dekompozici objektu a jejich uložení, kontrolu konzistence atd. Bylo to tedy docela pracné, ale na oplátku jsem dostal kód 100% napsaný v Jave, ke kterému jsem mohl napsat velice jednoduše testy.

Závěr

Key/value databáze se nehodí pro jakýkoliv projekt, to je myslím celkem jasné. Není možné o ní uvažovat jako o plnohodnotné náhradě relační databáze, protože její koncept je naprosto odlišný. To mimo jiné znamená, že není možné při jejím použití aplikovat ty samé vzory a postupy, které jsme se naučili právě na relačních databázích. Jakmile začnete uvažovat o key/value databázi v inténcích relační databáze, je potřeba zvážit jestli vám key/value databáze nabízí to co potřebujete a nebo jestli jste někde v návrhu neudělali chybu.

Key/value databáze lze velice dobře používat jako doplněk relačních (dokumentových,objektových) databází. Pro specifické účely ve vaší aplikace se může hodit key/value databáze a zbytek dat může ležet v klasické relační databázi.

čtvrtek 1. dubna 2010

Po čem nejen muži touží

Matně šátrám v paměti, kdy jsem vlastně začal používat RSS čtečku. No určitě je to hodně dávno. Na RSS čtečce bylo svého času kouzelné, že člověk nemusel oblézat všechny oblíbené stránky a hledat kde se co šustlo nového. Ze začátku mi RSS čtečka ušetřila spoustu času, nicméně postupem času se i z mého Google reader účtu stalo informační smetiště. Samozřejmě se to nestalo z čista jasna a možná i u vás to mělo stejný průběh. Postupně si do čtečky začnete nabalovat zajímavé informační zdroje, jenže čím víc jich tam máte, tím paradoxně méně času máte na výběr toho opravdu zajímavého obsahu.

Počet nepřečtených titulku narůstá a příchodem Twitteru posílá RSS čtečku na druhou kolej. Právě před rokem se Twitter stal mým primárním zdrojem informací. Jeho povaha je trochu jiná, protože neslouží primárně v uvozovkách hloupoučké aggregaci titulků. Výhodou Twitteru je to, že lidé, které následujete dělají profiltrování obsahu a vám předkládají jenom ty relevantnější odkazy. Samozřejmě i Twitter začne po čase trpět podobným neduhem jako RSS čtečka a to přesně ve chvíli, když dosáhnete kritické hodnoty počtu lidí (u mě 50), které sledujete.

Osobně mi chybí nástroj/služba, který by dokázal na základě toho, co čtu na počítači v jakékoliv elektronické formě, servírovat řekněme určitý počet článků denně s největší relevancí. Ten počet by byl optimálně volitelný, v mém případě maximálně tři až pět článků.

Samozřejmě by to muselo zohlednit aktuálnost těch informací, trendy sledovanosti atd. Když se v mé statistice hledání na Google objevují věci spojené v 40% s Javou, mou oblibenou stránkou je InfoQ a na Twitteru se objevilo, že tam je super článek o Jave, který ihned retweetnulo velké množství lidí, které přímo či transitivně následuji, pak od takto inteligentního nástroje očekávám, že tento článek uvízne v jeho síti a bude mi nabídnout právě v tom denním výběru. Nemyslím si, že to je utopie. Třeba takový nástroj existuje, třeba se na něm někde v laboratořích Google vyšívá. Uvidíme, každopádně za něco takového bych byl ochoten i platit.

čtvrtek 11. března 2010

Pryč se Singletony

Gang of Four odhalil na světlo světa katalog návrhových vzorů, díky kterému se do širokého povědomí dostaly přístupy k řešení typických úkolu v objektovém programování. Mezi nejznámější návrhové vzory patří bezesporu Singleton, řešící existenci pouze jedné instance dané třídy. Nevím jestli je jeho popularita zapříčiněna tím, že jej každý pochopí a nebo tím, že jej každý potřebuje (nebo si to alespoň myslí), každopádně singletony najdeme v každém kódu. Bohužel ve skutečnosti jakékoliv použití Singletonu sebou nese značná rizika a nevýhody. Pro mě osobně testování a svázání objektů. Pravda, není to chyba vzoru jako takového, ale spíše jeho zneužívání na nesprávných místech.

Pojďme zkusit najít zakopanou kostra pudla. Singleton ze své podstaty drží nějaký kontext, ostatně proto jej zavádíme. Dobrá rada na začátek. Pokud najdete v kódu singleton, který nedrží kontext, pak máte skvělou příležitost tenhle singleton (chování) odstranit, protože je zbytečný. Skrze kontext se dostáváme k jiným částem systému (service locator), to mohou být například nacacheovaná data, pool připojení k databázi a tak dále. To stále ještě není problém, ten nastane ve chvíli, kdy začnete singletony nořit do sebe. Z aplikace se totiž stane jedna velká drátovaná koule bahna.

Známe problém, ale známe řešení? Podle mých zkušeností je nejlepším řešením obrácená kontrola realizovaná pomocí dependency injection. Dependency injection neelimujeuje singletony jako takové, ale umožňuje je přesunout pryč z aplikačního kódu do vrstvy frameworku. To je přesně o co tu běží. V čistě napsané aplikaci by neměl být použitý jiný singleton než ten představující entry point do vlastní aplikace. Typickým příkladem je singleton frameworku, kterému se předá řízení při přijetí HTTP požadavku. V případě desktopové aplikace je to singleton představující service locator, přes který se získávají jednotlivé controllery.

pátek 19. února 2010

Když nerozhodují jenom technické aspekty

Každý z nás zažil situaci, kdy byl postaven před nalezení vhodné technologie nebo frameworku pro řešení určitého problému. Dlouhou dobu jsem zastával názor, že nejdůležitějším kritérium jsou technologické aspekty jako stabilita, dokumentace, komunita, zralost atd. Dneska už mi pomalu dochází, že každé rozhodnutí sebou nese kromě technických i sociální dopady, které je neradno ignorovat. Pokud tedy nechcete riskovat vlastní defenestraci.

Bohužel věci se začnou komplikovat ve chvíli kdy proti sobě postavíte technické a sociální aspekty, protože se jedná o mnohdy protichůdné požadavky. Pokud máme například tým lidi, kteří pět let píší web aplikace v Jave a řekneme jim, že další budou psát třeba v Ruby a Ruby on Rails.V takovém případě se lehce může stát, že se jich půlka naštve a odejde, ačkoliv z technologického pohledu se to může zdát jako ta nejlepší věc.

Pokud se rozhodujete pro jakoukoliv technologii, zvažte kromě technologických aspektů i "měkká" kritéria, která se vyplatí neignorovat. Slovy klasika: “musíme tomu štěstíčku naproti“. Lidé se obecně rádi učí nové věci, ale musí za tím vidět nějaký hlubší smysl. se úplně nejraději učí věci, které zvyšují jejich cenu na trhu. Tím nemám rozhodně na mysli, aby jste začali psát v jazyku Cobol, protože lidí ovládajících tento jazyk je relativně málo. Spíše jde o věci, které jsou takzvaně v kurzu, bráno v kontextu předešlých vět. Super skvělý framework, který jste si napsali na koleni se nebude chtít nikdo učit, protože až ho to za dva roky přestane u vás ve firmě bavit, tato zkušenost mu životopis nevylepší.

Jednoduché věci se prosazují daleko snáze oproti těm komplexnějším, přestože mohou přinést užitek. Pokud chcete prosadit něco komplexnějšího mějte po ruce nějaký wov efekt. Je to sice levný trik, ale zabírá… Vždy a za každých okolností mějte na paměti, že lidé rádi nadávají na to čemu dokonale nerozumí. A jsou z toho frustrováni. Tomu nezabráníte, neberte si to osobně a hlavně buďte na to připraveni třeba školením.

čtvrtek 28. ledna 2010

Proč nepotřebuji (zatím) asynchronní JDBC

Lukáš Křečan se zkusil zamyslet nad tím, jestli v Jave potřebuje asynchronní JDBC API a svůj závěr vtisknul přímo do článku Proč nepotřebuji asynchronní JDBC. Já si dovolím Lukášem mírně doplnit.

Nejdříve bychom si mohli demonstrovat na jednoduchém kódu Lukášem zmiňované Servlet 3.0 API s podporou asynchronního volání, které bude v našem dalším povídání hrát důležitou roli.

@WebServlet(name = "AsyncServlet", urlPatterns = { "/AsyncServlet" }, asyncSupported=true)
public class AsyncServlet extends HttpServlet {
 
  protected void doGet(HttpServletRequest request, HttpServletResponse response) {
  AsyncContext ac = request.startAsync(request, response);
  ac.start(new Worker(ac));  
 }
 
 public static class Worker implements Runnable {
  private final AsyncContext ac;
  
  public Worker(AsyncContext ac) { 
   this.ac = ac;
  }

  @Override
  public void run() {
   HttpServletResponse response = (HttpServletResponse) ac.getResponse();
   try {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = null;
    try {
     out = response.getWriter();
     out.println("<html>");     
     out.println("<body>");
     out.println("<h1>Servlet AsyncServlet output</h1>");
     for(int i = 0; i < 10000; i++) {
      out.println("<p>Asynchronously generated response :-)</p>");
      out.flush();
      try {
       Thread.sleep(200);       
      } catch (InterruptedException e) {}
     }
     out.println("</body></html>");     
    } catch (IOException e) {     
    } finally {
     out.close();
    }
   } finally {
    ac.complete();
   }
  }
 }
} 
  

Trocha popisu. Na řádku 5 instruujeme kontejner, že požadavek bude vyřízen asynchronně. Na řádku 6 odpálíme asynchronní exekuci. V tomto případě se použije vlákno z poolu servletového kontejneru. Samozřejmě to nemusí vždy vyhovovat a my mužeme vytvořit klasický ThreadPoolExecutor a vlákna brát z něj.

Po vykonání řádku 6 se nám tedy v novém vlákně spustí exekuce viz třídá Worker a původní vlákno servletového kontejneru dokončí metodu doGet a může být použito k obsluze jiného HTTP požadavku. Metoda run třídy Worker tedy běží v jiném vlákně. Pomocí AsyncContextu, který jsme si předali a tvoří nás komunikační kanál se servletovým kontejnerem, jsme schopni vytvořit repsonse. Dokončení asynchronní práce se signalizuje voláním metody complete na řádku 40.

Nyní k jádru pudla. Kde nám do hry vstupuje ono vzývané asynchronní JDBC API. Představme si náš příklad lehce upraven o volání nám dobře známého JDBC. Stačí nám pouze třída Worker.

public static class Worker implements Runnable {
  private final AsyncContext ac;
  
  public Worker(AsyncContext ac) { 
   this.ac = ac;
  }

  @Override
  public void run() {
   Connection conn = getConnectionFromSomewhere();
   PreparedStatement ps =  conn.prepareStatement("insert into orders (a) values ('a')");
   ps.executeUpdate();
      ac.dispatch("/dekujeme-za-nakup.jsp");   
  } 
 }    

Co se stane? Servletový kontejner má vlákno vrácené a může obsluhovat další HTTP požadavky, ale vlákno vykonávající metodu run bude zablokované na řádcích 10 a 12. Jíra Mareš má do jisté míry pravdu, že na řádku 10 nám může pomoci poolovaní na úrovni databázových připojení. Nicméně vlákno bude zablokováno nejpozději na řádku 12.

Představme si situaci, že máme eschop a uživatel právě učinil nákup. Požadavek se odeslal a kód zůstal trčet na řádku 12. Asi nechceme, aby měl uživatel deset sekund "zmrzlé" UI prohlížeče, ale raději bychom mu ukázali stránku kde mu poděkujeme za nákup a třeba ještě něco nabídli z dceřiného obchodu.

Bez asynchronního JDBC API musíme obě blokující volání (10,11) zabalit ručně do asynchronního volání. Původní metoda run potom vypadá přímo pohádkově.

@Override
public void run() {
 new Thread(){    
  public void run() {
   Connection conn = getConnectionFromSomewhere();
   PreparedStatement ps =  conn.prepareStatement("insert into foo (a) values ('a')");
   ps.executeUpdate();
  }    
 }.start();   
 ac.dispatch("/dekujeme-za-nakup.jsp");
} 

Nechtěl bych zde polemizovat, že JDBC je samospasné. Je to jenom špička ledovce. Každopádně je to dobrý začátek k tomu, aby si podobným způsobem nemuseli zaneřádit kód aplikační vývojáři. Samo o sobě asynchronní JDBC nepřinese žádné drastické zvýšení výkonu (v tom jsme s Lukášem za jedno), snad možná svižnější UI. Aby mělo asynchronní JDBC nějaký výkonnostní dopad, bylo by potřeba mít driver a databázi, která asynchronní volání podporuje.

A mimochodem není to taková utopie viz níže

středa 27. ledna 2010

Oracle Sun akvizice. Hotovo a potvrzeno.

Larry Ellison ve webcastu k finálnímu dokončení akvizice firmy Sun (nyní již Oracle) uklidnil všechny javisty. Do Javy se investovat bude viz FAQ. Najdete tam i kusé informace o tom co se chystá Oracle udělat se Solarisem, MySQL, NetBeans a dalšími produkty. Ještě dávám k dobru hlášky, které mě pobavily a zaujaly z twitterového vysílání k této události. IBM a cloud computing si to od Larryho pěkne slíznul.

RT @Oracle: Larry Ellison: Solaris will be the OS for a cluster of computers, not just a high end box #oraclesun

Larry: "Best 2 databases on planet are DB2 on mainframes and Oracle on modern computers" #oraclesun

RT @sunmicrosystems: Larry Ellison: we are going to make MySQL better #oraclesun

RT @Oracle: Larry Ellison: Solaris will be the OS for a cluster of computers, not just a high end box #oraclesun

RT @vandenadort: Larry: IBM doesnt have Java, they haven't got Oracle database, what they have is a problem. They're a decade behind us #oraclesun

RT @oracletechnet: Ellison: I love Linux, but Solaris is more mature and reliable for the high end #oraclesun

Larry Ellison: DB2 is about a decade behind when it comes to Oracle technology #oraclesun

Ellison "Why in the world didn't IBM create a scalable dbase machine. IBM is far behind, I don't think they have a chance at all."#oraclesun

#oraclesun: Ellison: "I can't understand why IBM has never come out with a database machine. DB2 doesn't cluster, doesn't scale, nothing."

#OracleSun LE: won't measure Java success in terms of revenue but in terms of tech success->Sun tried this, might work for Oracle?

Ellison: "There is no in-memory dbase that will take the place of a relational dbase." #oraclesun

Larry - The only thing new about Cloud is the name, we've been doing it for years. Itunes, Sales Force, etc all run #Oracle #oraclesun

RT @oracletechnet: Ellison: The only thing new about cloud computing is the word "cloud" - it's just a computer attached to the Internet #oraclesun

neděle 24. ledna 2010

Nedělní rozjímání nad softwarovým vývojem

Nemálo lidí přemýšlí o různých technikách zefektivnění softwarového vývoje. Zažil jsem metodologií, která byla klasický vodopád obohacený a milestony po šesti týdnech. Tedy na začátku se udělal sběr požadavků, jejich analýza, pak design, implementace a verifikace/testování na závěr. Každou z těchto činnosti dělal v podstatě jiný tým lidí. Sběr požadavků dělal tým funkčních architektů, analýzy techničtí architekti, design a implementaci vývojáři a verifikaci a testování oddělení kvality. Ačkoliv tento systém vývoje fungoval, mohl fungovat daleko efektivněji a lépe.

Prvním problémem je více méně striktní rozčlenění odpovědností, ačkoliv by se to mohlo zdát jako logické a správné, tak je to ve své podstatě kontraproduktivní. Práce každé skupiny má totiž jasný začátek a konec, s tím, že na ní navazuje práce jiné skupiny. Bohužel to sebou šílený redundanci v podobě sdílení informací. Když osoba A na začátku celého řetězu něco vymyslí nebo změní, je potřeba tuto informaci rozšířit přes všechny navazující skupiny a to v jakýkoliv okamžik.

Aby se této redundanci v předávání informací zamezilo, vznikají dokumenty. Celé řádka dokumentů v různých revizích, které popisují co prěsně autor zamýšlel. Máme sice jedno místo, kde se udržují informace, ale lidé musí pálit čas tím, aby tyto informace sepsali a další lidé tím, aby je vstřebali.

Obecně si myslím, že rozškatulkovaný vývoj na skupiny lidí prostě nefunguje kvůli sociálním problémům. Jedna skupina si něco vymyslí a další za měsíc zjistí, že to je neproveditelné. Vznikají zbytečné třenice díky tomu, že architekt požaduje Táčmahál a vývojáři jsou schopni dodat v lepším případě srub kanadského dřevorubce nebo v tom horším kůlničku na dříví.

Druhý problém je v tom, že fáze analýzy je sice ukotvená na začátku celého procesu nicméně pouze pro to, aby se na jejím základě dokázaly udělat časové odhady náročnosti a proto, aby mohli další skupiny lidí pracovat. Bohužel tento přístup má poměrně zásadní nedostatek. Né vždy totiž vidíme plně pod kapotu celého řešení. Spíše naopak, vidíme pouze tu část, se kterou jsme dobře seznámeni a dopad na navazující části nám často uniká. Takže naše analýza z principu stojí na vodě. Zkuste v takovém případě udělat odhad časové náročnosti.

Teď jsme si popsali, některé z nevýhod a teď jak proces zrefaktorovat, tak aby fungoval k plné spokojenosti všech zúčastněných.

Prvním problém je odstranění informační bariéry a sdílení informací.

Psát v případě funkčních požadavků desetistránkové pamflety je nesmysl. Nejpochopitelnější je načárat funkční specifikaci na chování uživatelského aplikace a přidat stručný popis. Pokud to nedokážete, pak je nejspíše problém v tom, že zadání je příliš složité. Příliš složité zadání na úrovni uživatelského rozhraní nejspíše neznamená, že by zadání bylo složíte. Spíše to svědčí o tom, že to co uživatel chtěl bylo špatně pochopeno. Když chce uživatel skalpel, dejte mu skalpel a nikoliv multifunkční švýcarský nožík, který obsahuje navíc šroubovák, vývrtku a pilník.

Nepište analýzy pokud to není opravdu potřeba a rozhodně je nepoužívejte jako zadání práce pro někoho jiného a nebo k časovým odhadům. Důležitá rozhodnutí, která mají tendenci se v analýzách objevovat, odložte až na poslední možnou chvíli (viz Lean software development) kdy budete mít všechny potřebné informace.

An agile software development approach can move the building of options earlier for customers, thus delaying certain crucial decisions until customers have realized their needs better. This also allows later adaptation to changes and the prevention of costly earlier technology-bounded decisions.

Prací softwarového vývojáře není sepisování esejí či jejích louskání. Nejefektivnější způsob výměny informací je přímá komunikace a zapojení se všech členů týmu ve všech činostech vývojového cyklu. Striktní rozdělení činností vede pouze k vytváření bariér. Vedlejším efektem je to, že se určitá část lidí specializuje pouze na určitou část řešení. Dochází potom k třenicím, že lidé co dělají uživatelské rozhraní se cítí odstrčení od jádra systému a ty co dělají jádro nemají potuchy co potřebují ti co dělají uživatelské rozhraní. Stejný kastovní systém dělá problém i při dělení na vývojáře a architekty.

Možná je to anarchie, možná je to cowboy coding, ale podle mého soudu by všichni měli dělat všechno. Tím se nejlépe sdílí týmové znalosti a nutí to k větší míře komunikace. A lidi to pochopitelně víc baví. Striktní rozdělení na architekty a vývojáře neexistuje. Zásadní rozhodnutí se přijímají společně. Funkci architekta v uvozovkách drží vývojáři, kteří jsou respektování zbytkem týmu a mají dostatečnou autoritu fungovat jako arbitr sporu typu použijeme knihovnu typy X nebo Y.

Vsuvka:Role manažera spočívá pouze v tom, že poskytuje servisní služby zbytku týmu. Dělá zapisy meetingu, zajišťuje hardware/software, dohlíží a připomíná na termíny, zajišťuje komunikaci s dalšími tými. V podstatě slouží jako tlumič různých byrokratických omezení. Manažer nikdy neděla technologická rozhodnutí nicméně jeho názor je vítán a respektován.

Občas mám pocit, že se různé procesy a metodiky vývoje hodně přeceňují. Z výše uvedených řádku by mohl leckdo nabít dojmu, že jsem vodopád zrefaktoroval například na Scrum. Přiznám se, že nevím, agilních metodik je celá řada. Někdy je to hra se slovíčky a ve výsledku se dospěje k tomu samému. Já osobně věřím ve dvě věci při softwárovém vývoji.

  • komunikace, komunikace a zase komunikace namísto byrokracie snažící se komunikaci suplovat
  • silné individuality jako jádro malých týmů, kde každý člen se podílí na všech činoostech

Jestli tomu bude říkat nebo v tom hledat Scrum, Iterative and incremental development či Lean software development je poměrně nezajímavé.