středa 10. října 2007

OT:programování není intelektuálně náročné

Dneska mě pobavil kolega, který musí z nějakého důvodu zjistit proč nefungují naše testy. Co čert nechtěl, testy nepsal on sám, ale naše pobočka v jihovýchodním koutě Asie.

Cyklus od jedné

for (int i = 0; i < CONTRACT_NAMES.length; i++) {
  if (i != 0) {
    ...
  }
}

Už vím k proč je v JUnit fail metoda

catch (SomeException e) {
  fail(e.getMessage());
catch (SomeOtherException e) {
  fail(e.getMessage());
}

Postupným zabořováním do kousků kódu vyprodukovaných v jihovýchodní Asii mě napadají tři vysvětlení, případně jejich kombinace.

  • programování není intelektuálně náročné
  • jiná mentalita, splnit úkol a moc nad tím nepřemýšlet
  • plat odvinutý od počtu vyprodukovaných řádků

Související linky

úterý 9. října 2007

Lekce ze škálovatelnosti

V článku Teorie a praxe v J2EE světě jsem se pozastavoval nad rozdílem mezi tím, co si můžeme přečíst v chytrých knihách o J2EE a tím jaká je praxe. Praktický pohled poskytla prezentace o architektuře systému eBay. Nati Shalom otevřel související diskusi na téma Why most large-scale Web sites are not written in Java.

Nati Shalom vyšel z dat sesbíraných ze serveru HighScalability viz následující tabulka.

Tabulka ukazuje, že preferovaným stackem je LAMP (Linux, Apache, MySQL, PHP|Perl). Je více než patřičné ptát se proč. Nati správně poukazuje na patrný rozdíl mezi požadavky web aplikací a mission-critical aplikací, které jsou obvykle stavěné nad J2EE stackem. Nicméně v oblasti škálovatelnosti vidí společné oblasti pro oba typy aplikací.

  • cacheování na úrovni datové vrstvy (minimalizace diskových IO operací)
  • snaha o Horizontal partitioning
  • minimalizace distribuovaných transakcí
  • snadná paralelizaci na úrovni aplikační vrstvy

Problém J2EE je v tom, že škálovatelnost je jakýsi virtuální pojem, který se táhne specifikací a marketingovými materiály. Z praktické zkušenosti s J2EE stackem mohu říci, že řádně škálují maximálně tak servlety. Pokud tedy chcete napsat vysoce škálovatelnou aplikaci v J2EE, nezbude vám nic jiného než spoustu technologií úplně vynechat.

K dobru přikládám moje tipy na architekturu dobře škálující střední vrstvy.

  • Bezestavový design a idempotentnost operací
  • lokální transakce
  • Hibernate
  • In memory data gridy
  • Spring

Stateless nebo česky bezestavový design je první předpoklad k dobré škálovatelnosti, znaméná totiž že není potřeba synchronizace stavu přes cluster. Pro dobré fungování aplikace je potřeba brát v potaz jistou toleranci k chybovosti, to by měla zaručit idempotentnost operací (výsledek operace se nemění v závislosti na počtu volání). Lokální transakce, protože JTA nepřináší žádné výhody v případě jediného transakčního participanta, naopak přidává zbytečnou režií.

Hibernate protože má podporu pro transakční cache (first level cache), velice snadno lze nakonfigurovat vysoce výkonnou second level cache (Comparing Memcached and Ehcache Performance díky Kolesi!), navíc by měl umožnit i horizontal partitioning. In memory data grid pokud již potřebujete držet nějaký stav, protože prostě řešení určená pouze a jenom pro škálování fungují lépe, než podpora v aplikačních serverech. A konečně Spring, kterým to všechno spojíte bezbolestně dohromady.

Závěrem, i v J2EE jde napsat aplikace, která bude dobře škálovat jenom musí člověk vědět jak na to...

pondělí 8. října 2007

Grid pro testy - realita nebo utopie?

Máte hromadu integračních a jednotkových (unit) testů a přemýšlíte jak z nich dostat co nejrychleji výsledky? Především integrační testy, které potřebují časově náročnější setup (start kontejneru, inicializace databáze atd.), jsou pověstnou žábou na prameni. My máme takových testů celou řadu a tak mě samozřejmě zajímá jakým způsobem urychlit jejich exekuci.

Nedávno jsem četl článek Jak na rychlé integrační testy ve Springu, který sice nabízí určité řešení pro testy závisle na databázi, ale má také poměrně dost nevýhod (nepoužitelné pro Hibernate, složitější vyjádření testovaných dat atd.). Novojovo řešení nabízí jistou míru urychlení, ale nikoliv dostačující.

Klíč k urychlení totiž neleží v urychlování sekvenčních operací, ale v jejich paralelizaci. To znamená prosté spuštění testů paralelně na různých strojích. Koncepce je následující.

  • Máme určité množství počítačů jejichž výkon není plně využit. Z nich můžeme postavit grid.
  • Do gridu můžeme dávat úkoly, které představují exekuce testů a report jejich výsledků.
  • Vývojář z IDE, Mavenu či příkazové řádku spustí test a nebo jejich sada. Tento úkol se vypropaguje do gridu, asynchronně provede a výsledky jsou reportovány zpět.

Grid přináší výpočetní výkon nezávislý na hardwaru vývojáře a umožňuje paralelizaci testů s efektivním využitím dostupných prostředků. Řešení, která umožňují distribuované testy, skutečně existují.

Samozřejmě distribuované testy mají několik hluchých míst. Především chybí infrastruktura pro spouštění testů. Spuštění testů nad stálou strukturou (konkrétní revize source code systému) je realizovatelné. Horší je to s lokálními změnami, nad kterými by měly testy běžet resp. vývojář by rád. Musela by se udělat tranzitivní uzávěrka a změny by se musely vypropagovat s testem.

Další možností je použití dvoufázového commitu (ve skutečnosti se tomu možná říká jinak). Lokálně pustíme pouze testy, které přímo verifikují danou změnu, Provedeme commit, tím dojde k naplánování puštění kompletní sady testů. Pokud testy projdou dojde k provedení vlastního commitu. Dvoufázový commit podporuje Team City od IntelliJ.

Distribuované testy vyžadují jistou kázeň při jejich tvorbě. Například nesmí docházet k vzájemnému ovlivnění testů. Pro testy, které mohou běžet na dané konfiguraci v jeden okamžik pouze jednou, například z důvodů kolize primárních klíčů, by musely existovat metadata (anotace), podle kterých by testovací framework řídil jejich spuštění. Podobných zádrhelů bychom asi našli o trochu více, ale to souvisí se zmiňovanou infrastrukturou.

Osobně se mi myšlenka využití gridu pro spouštění testů velice zamlouvá. I přes hluchá místa jsi dokážu představit relativně jednoduchý setup, který by se mohl využít v rámci continuous integration.