sobota 28. listopadu 2009

Eclipse E4 - nejlepší RCP platforma

Dlouhou dobu mi ležel v "šuplíku" dokument Eclipse E4 popisující koncept, kterým ubíra další generace Eclipse.

Hodně často je slyšet, že Eclipse, jako IDE pro Javu, nedosahuje takové úrovně jako IntelliJ IDEA. Můžete s tímto názorem souhlasit a nebo jej rozporovat, ale je důležité si uvědomit následující fakta. Eclipse není primárně navržen jako IDE pro Javu, ale jako platforma pro vývoj nástrojů a aplikací.

Pokud tedy očekáváte, že verze 4 přinese nějaký zásadní posun v oblasti vývojových nástrojů, pak budete pravděpodobně zklamání. Samozřejmě přijdou nějaké dílčí vylepšení, například podpora komplexnějšího projektového layoutu, ale revoluci nečekejte. Osobně si myslím, že to je dobře, protože Eclipse vývojáři se mohou soustředit na to co děla Eclipse Eclipsem a to je vlastní platforma. Eclipse možná není tím nejlepším IDE pro Javu, ale bez nejmenší diskuze je nejlepší platformou pro vytváření nástrojů a aplikací.

Kromě vylepšeného programového modelu, který by měl umožnit lepší spolupráci pluginů, mne zaujaly poměrně zásadnější změny na poli vlastního UI. První velkou změnou je možnost popsat UI (SWT) deklarativně - pomocí XML a nebo EMF modelu. Aplikační kód nebude tedy již obsahovat definici UI což přinese několik výhod.

  • S modelem UI bude možné manipulovat za běhu podobně jako měníme například pomocí JavaScriptu DOM HTML stránek.
  • UI půjde nastylovat. E4 pro tyto účely nabízí rozšířené CSS (lepší selektory).
  • UI bude možné renderovat různými způsoby.

U posledního bodu bych se rád krátce zastavil. Eclipse E4 totiž již obsahuje renderer SWT komponent do Adobe Flex. Cesta do duše internetového prohlížeče je otevřena. Když uvážíme sílu tohoto frameworku pro vytváření RIA a programový model Eclipse, pak se zdá, že to je nejslibnější kombinace pro tenké klienty vůbec. Nenapadá mě moc technologií, které by mohly konkurovat a to i z .NET světa.

pátek 13. listopadu 2009

CZ Podcast #33 - reloaded

Možná jste se už báli, že nás postihla ptačí, prasečí či jiná chřipka, ale my jsme opět tady (jenom Filemon měl nějakou dětskou nemoc). Každopádně další díl jsme věnovali novinkám kolem nás. Roumen pohovořil o open source procesu kolem IntelliJ IDEA, já o zážitcích s .NET a Filemon o MDA (generátorech kódu). Bavte se.

neděle 1. listopadu 2009

Do pranice: Vhodnost ORM

Dvakrát se mi v poslední době stalo, že jsem se snažil někoho přesvědčit o nevhodnosti použití Hibernate a obecně ORM nástrojů pro přístup do databáze. ORM přístup má svoje výhody, ale i věci, které činí jeho použití obtížné.

Faktory, které ovlivňují jestli je ORM vhodná volba.

  • Aplikace pracuje pouze s více typy databází. V takovém případě přináší ORM neocenitelné služby v oblasti přenositelnosti. Ta nemusí být dokonalá, ale určitě převáží nad práci vynaloženou nad portací vrstvy pro přístup k datům pro N dalších typů databáze.
  • Aplikace potřebuje číst a zapisovat košaté objektové struktury. Zde nám ORM neušetří práci na psaní dotazů, ale ušetří nám hromadu kódu, který bude potřeba na jejich zpracování. Mám na mysli především kód, který prochází ResultSet a staví objektový strom a naopak kód, který prochází objektový strom a staví PreparedStatement.
  • Aplikace si může dovolit upravit RDBMS schéma, aby vyhovovalo objektově-relačnímu mapování. Ačkoliv Hibernate nabízí doslova kouzla pro namapování čehokoliv na cokoliv je lepší upravit RDBMS schéma, tak aby vyhovovalo.

Jednou z charakteristik ORM frameworků je jejich snadná počáteční adopce. Tyto řešení fungují velice snadno pro vzorová schémata typu: potřebuji namapovat one-to-many vztah, potřebuji získat entitu na základě jejího identifikátoru. Řekl bych, že tato vlastnost a databázová přenositelnost je pozlátko, které hodně vývojářů zláká. Bohužel je zde i temná strana síly, se kterou zahrávati neradno je a počítati musí se s ní.

Osobně bych to vyjádřil takto, pokud nemáte v týmu někoho se zkušeností s ORM, čeká vás plno nemilých překvapení. To je dané komplexností ORM a vy pravděpodobně nemáte ani tucha co je pod kapotou. První vystřízlivění nastává ve chvíli kdy si zapnete výpis SQL dotazů následované LazyInitializationException a zakončeno magickými zápisy do databáze, které vám nedávají smysl.

To střízlivění a bolehlav je důsledkem komplexnosti, kterou ORM představuje. Takže kromě toho, že se učíte jazyk vlastního frameworku, musíte vstřebat a pochopit právě tuto komplexnost. Stejně jako máme návrhové vzory pro objektově orientovaný návrh nebo návrh enterprise systémů, tak máme i vzory pro to jak úspěšně používat ORM. A věřte mi, že máte problém pokud ty vzory neznáte.

Nerad bych, aby tenhle článek vyzněl tak, že ORM je špatné. To v žádném případě není. Jenom je dobré si uvědomit, že jako každé řešení se pro některé úkoly hodí více, pro některé méně a pro některé vůbec. Samozřejmě je na místě otázka co jiného když ne ORM. Docela dobrý kompromis mezi komplexním ORM a nízkoúrovňovým JDBC představuje framework iBatis (viz třeba Honza Novotný iBatis 3.0 preview – část první), kdy mapujete objektový graf na SQL dotazy namísto tabulek.

Budu nesmírně rád pokud mi zde pod článkem vyjádřite svůj názor o vašich zkušenostech s ORM.

neděle 18. října 2009

Testování aplikací - panelová diskuze

Co se stane, když dáte dohromady javistu, dotnetaka, pythonistu a rubyistu a necháte je diskutovat o testování aplikací. Po pravdě řečeno jsem nevěděl co od toho čekat, ale rád jsem přijal pozvání, které mi adresoval Jarda Jirava na akci Testování aplikací - panelová diskuze. Spolu se mnou diskutoval ještě Karel Minařík (Ruby), Jan Král (Python), Borek Bernard (Flex, .NET) a Michael Juřek (.NET) za účasti osmdesáti posluchačů.

Na začátek musím předeslat, že akce byla opravdu povedená a moji spoluřečníci byli skvěle připraveni. Na internetu se objeví dokonce i audio záznam. Rád bych zde shrnul to nejzajímavější co jsem si z diskuze odnesl.

V případě dynamických jazyků jako Ruby nebo Python jsou testy alfou a omegou celého psaní. Testy zde zněla jako mantra takřka pro jakoukoliv softwárovou disciplínu. Test sloužil zároveň jako jeho design a měřidlo kvality kódu. Přístup Test first byl dosti často citován jako způsob pro to kde začít s kódem. Jak správně zaznělo z publika od Pavla Jetenského psát aplikace postavené nad staticky typovým jazykem ještě jde, ale dělat to za použití dynamického jazyka je problém.

Téma, na kterém jsme se zasekli, by vydalo určitě na samostatný článek. Jednalo se o přípravu dat pro testy. Jedna z pouček o psaní testů říká, že příprava vlastních dat pro test by neměla záviset na žádné aplikační logice. Líbilo se mi, že se nám doufám podařilo shodnout, že při psaní aplikací postavených nad databází je toto pravidlo pouze teorie a jakákoliv redundantní příprava dat postupem času dosti rychle ztrácí dech. Například kvůli tomu, že databázové schéma či aplikační omezení se stále vyvíjí a je těžké je držet konzistentní.

Z naší diskuze mě zaujalo ještě pár střípků

  • Carbon footprint - čím dřív začnete testovat na nižší úrovni abstrakce tím menší počet počítačů je potřeba (ekologický fundamentalismus dotažený k dokonalosti? ;-).
  • Pex - je rozšíření Visual Studia, které dokáže projít a zanalyzovat váš kód a na základě této znalosti vygenerovat odpovídající testy.
  • Borkova ilustrace složitosti psaní testů pro jednotlivé typy kódu. Nejjednoduší bylo povětšinou psát testy pro klasické knihovny oproti například desktopovým aplikacím. Dobrý argument na někoho kdo mi bude doporučovat jeho vlastní framework.

sobota 10. října 2009

Chudokrevný model, chudý příbuzný objektově orientovaného návrhu?

Nedávno se mě jeden kolega zeptal jestli budeme mít anemic domain model (chudokrevný?). Byl jsem trošku v rozpacích co tím myslí. Po krátke diskuzi jsme si vyjasnili termíny (problém jsem znal, ale termín jsem zapomněl) a já jsem prohodil, že asi budeme. Když nad tím přemýšlím, musím říci, že to byla blbost.

Pokud si přečtete výše uvedeny článek Martina Fowlera dostane se vám erudovaného vysvětlení co to je chudokrevný doménový model model. Pokud to dělat nechcete, pak se budete muset spokojit s mojí interpretací. Chudokrevný doménový model je takový model, kdy doménové třídy reprezentující business entity systému neobsahují žadnou logiku. Jsou to pouze "přenosky" dat se settry a gettry.

Fowler dále správně upozorňuje na fakt, že chudokrevný doménový model vede k příliš těžkopádné a tlusté aplikační vrstvě. V té se mísí všechna aplikační logika namísto toho, aby ležela právě v doménovém modelu kam patří. Pokud jste v posledních pár letech dělali nějakou vícevrstvou aplikaci, pak se schválně podívejte na velikost všech tříd, které v názvu obsahují slovo Service. Jsou to u vás největší molochy v celém projektu jako u mě?

Problém s těmito molochy je v tom, že jsou jenom velice těžce jakýmkoliv způsobem refaktorovatelné. Samozřejmě pokud pominu fakt, že z metody o pětsistech řádcích uděláme pět malých o sto řádcích. Představa nějakého objektového re-designu je skoro nemožná.

Každý chytrý J2EE tutoriál či článek nám radí jak je dobré členit náš program do vrstev. Máme tak vrstvu servisní (aplikační logiky), vrstvu prezentační a vrstvu persistence (ukládání dat). Bohužel už nikde, až na pár míst, se nedočteme jak správně by měly tyto vrstvy vypadat. Výsledkem je, že sice správně separuje kód se stejnou odpovědností (UI, persistence), ale neděláme to objektově správně. Ve smyslu, že kód který patří do doménového modelu daváme do vrstev kam vůbec nepatří.

Jenže co to je objektově správně a potřebujeme to vůbec? Dokázali jsme žít se špatným objektovým návrhem léta a naše programy fungovaly dobře. Ovšem to by neměl být důvod nesnažit se jejich strukturu zlepšit, pokud víme, že je něco špatně. Hodně jsem přemýšlel o tom jakým způsobem to udělat a přijde mi, že nejlépe to řeší Domain Driven Design (zkráceně DDD).

Klíčove je, že aplikačni logika, která leží v servisné vrstvě, nebo nedej bože ve vrstvě persistence, se přesune do doménových tříd. To neznamená ovšem, že by najednou měla každá z těchto tříd vědět jakým způsobem se má uložit do databáze nebo snad ovládat transakční logiku. Doménové třídy například požadavek na uložení delegují na vrstvu persistence.

Servisní vrstva a vstva pro ukládání dat by měla zůstat co nejtenčí. V podstatě to znamená, že slouží jenom k tomu, aby došlo k správnému překladu jedné objektové reprezentace na druhou a kordinaci s infrastrukturou. Nemyslim si, že je jednoduché takto aplikace vytvářet. Největší problém je v tom, že s doménovými třídami nakládáme obvykle v kódu jinak než s třídami jiných vrstev.

Třidy z doménového modelu vytváříme povětšinou konstruktorem. V takovém případě máme problém jak do nich dostat právě třídy jiných vrstev. No ale to už je na jiný článek.

Na závěr dám k dobru ješte pár dobrých článků k tématu

středa 12. srpna 2009

Pálit trasírkami

Někdo z pravidelných čtenářů tohoto blogu by mohl následující přirovnání považovat za můj násilný pokus nalézt paralelu v umění válečném. Nicméně to o čem budu povídat není nejen z mojí hlavy, ale i termíny jsou původní.

Volně převyprávěno z Tracer Bullets and Prototypes - Pragmatic Programmers Andy Hunt and Dave Thomas talk with Bill Venners about the importance of getting feedback during development by firing tracer bullets and building prototypes.

Představte si, že ležíte ve tmě někde v buši a máte zasáhnout cíl. Máte dvě možnosti. První, znáte přibližnou polohu cíle, povětrnostní podmínky, atd. a z těchto údajů spočítáte balistickou dráhu kulky, nastavíte mířidla, zatajíte dech a vystřelíte. Pokud jste počítali dobře, vaše údaje se shodovaly s reálnými a cíl se nepohnul tak možná trefíte.

Druhou možností je použít značkovací munici též zvanou trasírky. Trasírka je speciální kulka, která za sebou po vystřelení nechává svítící stopu. V zásobníku bývá napáskováná každá n-tá střela tohoto typu. Při použití značkovací munice prostě vystřelíte a podle dráhy střely, kterou vidíte, zkorigujete náměr, tak aby pokud možno další střela našla cíl a nebo se mu alespoň přiblížila.

Nyní je pravá chvíle na uvedení paralely se softwárovým vývojem. Představte si, že stojíte před vývojem nového softwaru a nebo na prahu nového releasu. Někde na jeho konci je doručení finální podoby. Stejně jako při té střelbě v buši je mnohdy obtížné vědět přesnou polohu a čas od času se cíl pohne (kdo by to byl čekal). Některé požadavky dopadnou více či méně včas, některé jsou nejasné, a některé si vyložíme jinak. V takovém případě postup, kdy uděláme jeden velký odhad (předpoklad) na začátku a potom doručíme na konci (vystřelíme) kompletní řešení, často selhává.

Oproti tomu trasírky se dají do řeči softwárového vývoje převést asi následovně. Na začátku uděláme nějaký předpoklad, provedeme podle něj vývoj a po čase to vezmeme a ukážeme zákazníkovi. On nám řekne jak blízko nebo daleko jsme od jeho představ. Uděláme korekci a v další iteraci a opět ukážeme zákazníkovi. Tak společnými silami, postupným korigováním dráhy střely, dojdeme k řešení po kterém zákazník touží.

Mě se pálení trasírkami zdá jako vhodný způsob, ačkoliv v něm vidím jedno nebezpečí. Občas se stane, především pokud nešijeme na míru jenom jednomu zákazníkovi, že to co si vymyslí jeden zákazník, se jeví jako nepoužitelné pro jiného zákazníka, protože jeho představa je diametrálně odlišná. Tím chci říci, že není úplně nejlepší, aby korekci vaší hlavně dělal zákazník bez vaší asistence, protože by to také mohlo skončit tím, že se střelíte do nohy.

neděle 2. srpna 2009

Knihovny tříd vs. Knihovny komponent

Jako základní stavební kámen vývoje považuji volně provázané komponenty. Problém je v tom, že Java nemá adekvátní prostředky na to, abych mohl vůbec komponentově vyvíjet. Jako největší bolest vidím to, že nemůžeme dosáhnout zapouzdření. To vede k tomu, že v Jave nepoužíváme knihovny komponent, ale knihovny tříd. Knihovny tříd mají tu nevýhodu, že nejsou jasné hranice toho, co je ještě veřejné API a to co je implementační detail. výsledkem je Babylonské zmatení jazyků na úrovni tříd.

Komponenta je něco co má následující charakteristiku.

  • Vícenásobné použití
  • Není specifická pro daný kontext resp. využitelná v různých kontextech
  • Lze jí skládat dohromady s jinými komponentami
  • p
  • Dodržuje zapouzdření pomocí rozhraní
  • Jednotka nezávislého nasazení a verze

Dlouhou dobu jsem si myslel, že OSGi bude tou správnou cestou, ale musím říci bohužel není, alespoň ne v tento čas. OSGi sráží do kolen právě ono stigma toho, že jsme byli celou tu dobu zvyklí vyrábět knihovny tříd. Pokud dnes budete chtit udělat aplikaci postavenou na OSGi, pak narazíte na to, že knihovny třetích stran nejsou vůbec připraveny. A to už nemluvím o tom, že udělat webovou aplikaci nasaditelnou jako přenositelný WAR archív, je věc více než složitá

Paradoxně nejblíže k této charakteristice mají Enteprise Java Beanu, bohužel jejich užití sráží další nevýhody jako například příliš restriktivní programový model. Jsem ohromě zvědavý co vypadne z JSR 277 Java Module Systém. Bohužel si myslím, že alespoň ze začátku tu bude stejný problém jako s OSGi, tedy že na to nebudou knihovny stavěné, nicméně alespoň zacelí mezeru po chybějícím standardu.

Jako další, a nemalý problém, vidím to, že pokud mám technologii jako OSGi, tak je to jenom jedna polovina skládačky. Tou druhou je pro mě kooperace s Dependency Injection frameworkem, který by měl řídit to, jakým způsobem bude vnitřně komponenta assemblovaná. Ideální představa je taková, že komponenta má dané rozhraní představované například Java Interfacem. Implementace je složení několika java tříd pomocí Dependency Injection s tím, že tyto třídy nejsou vidět mimo rozsah komponenty, to znamená, že nikdo nemůže udělat lookup těchto tříd. To je například věc, která je prakticky i ve Springu velice těžko realizovatelná.

Můžu říci, že mě tato chybějící podpora čistého komponentového vývoje nejvíce omezuje v týmovém pojetí. Není například vůbec jednoduché nalinkovat jasné rozdělení odpovědností. Můžu sice o nějakém JARu říci, to je komponenta XYZ, ale ve chvíli, kdy si ho někdo přidá na classpath, tak jakékoliv hranice komponenty padají a použití je řízené tím co nabídne code completion v IDE. Díky tomu se potom jednotlivé JARy používají jinak, než bylo zamýšleno, protože jakékoliv hranice padají.

Java má před sebou dlouhou cestu hledání optimálního řešení, o tom, že je to potřeba není myslím sebemenšího sporu.

pátek 31. července 2009

Prezentace - Java EE 6 and how their relate to Spring Framework

Jürgen Höller presents some of the new features coming in Java EE 6 and how their relate to Spring Framework: Profiles, Servlet 3.0, JSR-236 Concurrency, JSF 2.0, JPA 2.0, JSR-303, JAX-RS, EJB 3.1, JSR-299. Doporučuji juknout až tak od 25. minuty záznamu.

Highlights

  • Spring 3.0 bude stále ještě podporovat Java EE 1.4
  • Java EE 5 ma zivotni cyklus 2007 - 2013 (jsme v první třetině jejího používání)
  • Nekonzistence mezi jednotlivými JSR specifikacemi. Pravá ruka neví, co děla levá aneb kdo dříve příjde, ten dřév mele.
  • Některé specifikace, respektive jejich části, jsou kontroverzní, například autodeployment v servlet 3.0, automatické zámky na singleton EJB komponentách.
  • JAX-RS standard pro REST, chybějící integrace s web frameworky, proto zvolil Spring vlastní model, ačkoliv má stále integraci s existujícími JAX-RS implementacemi (RESTEasy, Jersey)
  • JSR 299 (WebBeans), postupná změna zaměření specifikace. Původně zamýšlená jako pojítko JSF a EJB, nyní Dependency injection. Přesah do dalších specifikací, je možné, že se část posune do EJB 3.1.

Z meho pohledu Java EE 6 zatím vypadá jako jeden velký rozharany stroj. Tak uvidíme jestli se ho podaří vyladit.

neděle 28. června 2009

Jak pěstovat portfolio znalostí

Po nějaké době jsem se opět dostal k čtení výborné knihy The Pragmatic Programmer: From Journeyman to Master od Andrew Hunta a Davida Thomase. Tentokrát jsem se začetl do kapitoly Your Knowledge portofolio. Výše jmenovaní pánové tam kromě vypíchnutí faktu, že nejdůležitější vlastností jsou vaše zkušenosti a vědomosti, dávají k dobru pár rad k tomu, jak si vlastní vědomostní portfolio řídit k jeho dalšímu rozšíření. Metoda k tomu zvolená je podobná k finančním investicím.

  • seriozní investoři investují pravidelně, je to jejich zvyk.
  • diverzifikace (různorodost) investic je klíčové pro dlouhodobý úspěch
  • chytří investoři rozprostřou své investice přes ty konzervativní až po ty rizikové
  • investoři se snaží levně koupit a prodat za maximální hodnotu
  • portfolio je potřeba čas od času zrevidovat a přeskupit

Ke každé z těchto rad je vždy uvedeno jak jí uplatnit v praxi vývojáře. Nechci už moc opisovat, takže se podělím o ty, které nejsou moc obvyklé, ale víceméně jsem si je ověřil vlastní praxí.

Alespoň jednou za rok nový jazyk nebo technologii

Když jste vývojáři v Jave, naučte a nebo prozkoumejte alespoň jednou za rok nový jazyk nebo technologii. Vůbec nevadí, že tuto technologii nepoužijete na aktuálním projektu. Třeba tam narazíte na zajímavé přístupy, které by vás normálně minuly. Vzpomínám si, jak se mi na prezentaci o Grails líbil Meta Object Programming a dynamické rozšiřování persistentní vrstvy. Říkal jsem si, jaká je to škoda, že to nejde v Jave, abych při bližším zkoumání zjistil, že to nakonec lze pomocí AOP.

Čtěte nepočítačové knihy

Hodně často se zapomíná, že víc čas než strávíte komunikací s počítačem strávíte na různých poradách a nebo komunikací se spolupracovníky. Takže není na škodu odložit Blocha a jeho Efektivní Javu a šáhnout třeba po Fareed Zakariovi a jeho dílku o střetu civilizací. Samozřejmě číst se dá ledascos a inspirace je všude kolem, antikou počínaje a životopisem Lance Armstronga konče. Nedávno jsem našel úžasné paralely mezi softwarovými projektu a příklady úspěšně provedených speciálních operací jako Mussoliniho únos Otto Skorzenym, přepadení táboru Son Tay či osvobození růkojmých na letišti v Entebe v Ugandě.

Neučte se jenom technologie v technologické špičce

Když se dnes budete učit Spring framework, tak je to jako přijít s křížkem po funuse. To je technologie, která už je tu minimálně pět let a pokud jste nezaspali dobu, tak už jí musíte znát. Je potřeba hledat technologie, jazyky či postupy, které na svoje masivní použití teprve čekají. Samozřejmě pořád je zde možnost, že vsadíte na koně, kterého čeká jenom patnáct minut slávy, ale to vůbec nevadí. Kromě toho, že získáte zkušenosti, tak jednou trefíte do černého a získáte náskok.

Zkoušejte opak toho co používáte

Nejhorší věc, která se vám může stát je, že ustrnete. Proto je důležité hledat opak toho, co máte. Používáte celý život Windows, nainstalujte Linux. Děláte architekta, kódujte pro radost v nějakém open source projektu. Máte celý život brunety, zkuste blondýnu ;-).

pátek 19. června 2009

Podcast 32# Google Wave

Tramtadadá podcast numero třicetdva je mezi námi. Podařilo se nám ulovit hosta více než zajímavého a to šefredaktora magazínu Zdroják Martina Hassmana. Během povídání jsme se kromě Google Wave a HTML 5 zeptali i na další zajímavé věci z oblasti Rich internet Application. Vaše ohlasy jsou vítany na adrese czpodcast zavinac gmail.com.

čtvrtek 11. června 2009

CZ Podcast 31 - JavaOne

Po delší odmlce jsme tu zpět a v plné síle, tentorkát s novinkami z JavaOne. Součástí tohoto balení je i soutěž o licence vývojového prostředí IntelliJ IDEA. Vaše odpovědi jsou očekávané na adrese czpodcast@gmail.com.

pátek 22. května 2009

Proč by se vývojář neměl bát červeného světla

Setkávám se s názorem, že vývojář by měl před každým commitem pustit při nejmenším build celého projektu a všechny testy. To je přístup, který neodpovídá je v rozporu s kontinuální integrací. Proč děláme kontinuální integraci, je to proto, abychom neustále viděli zelené světlo a nebo proto, aby jsme zavčasu zjistili, že máme problém? Občas se mi zdá, že je to jenom kvůli tomu zelenému světlu a to na úkor efektivního využití zdrojů ať již lidských či technických.

Každý projekt, kterého jsem se účastnil, přerostl v určitou dobu kritickou mez, kdy přístup spustím build a testy před commitem prostě neškáloval. Kompletní build našeho HP SOA Systinet trvá na mém počítači přes dvacet minut a to se vůbec nebavím o spuštění testů. Kdyby každý vývojář toto dělal na svém počítači, tak se z toho buďto ukouše nudou a nebo nic nestihne, protože bude čekat, až mu doběhne build.

Je proto efektivnější udělat commit, který může potenciálně rozbít build. Efektivnější je to protože většina commitu ten build prostě nerozbije. Většina vývojářů totiž dělá změny lokálního charakteru, a nejčastější problémy, které těmito zásahy mohou vzniknout, odhalí IDE. Čili zůstane relativně malé množství problémů a kvůli nim se nevyplatí pouštět celý ten kafemlejnek lokálně.

Servery kontinuální integrace bývají zpravidla mnohem výkonnější něž lokální vývojářské stanice a navíc mohou dělat celou řadu optimalizací. Distribuovat build, udělat analýzu závislosti a vybuildovat jenom to co se změnilo, použít lokalní cache, buildovat dávkově a podobně. Čili věci, o kterých si vývojář se svými omezenými zdroji může jenom nechat zdát.

Rozsvícené červené světlo neznamená žádnou tragédii! Pokud tuhle hru přijmete je potřeba ji hrát s jedním pravidlem. Do rozbitého stavu by se neměly nehromadit další commity. To můžete zajistit automatickým zamknutím version control systému v případě zboření. Povoleny jsou jenom commity, které to opravují. Rozpoznávat je lze rovněž automaticky, vývojář to o nich prozradí v commit message podle předefinované šablony. Pak nehrozí situace, že vývojář rozbije build, pak ho přejede tramvaj, a už to nikdo neopraví, protože bude zamčený version control systém.

Samozřejmě existují i méně invazivní metody. Při použití distribuovaného verzovacího systému lze mít hierarchii repozitoří. Pak je možné dosáhnout toho, že se commit automaticky posouvá v hierarchii repozitoří od té týmové až po tu projektovou v závislosti, jestli se povedlo na dané úrovni vybuilldovat. Ve výsledku tak nedochází k zamykání version control systému.

pondělí 11. května 2009

Kontroverze kolem Dependency Injection aneb když dva dělají totéž není to totéž

Minulý týden udělali SpringSource a Google (respektive vývojáři Guice framewrku) společné oznámení, ve kterém představili návrh anotací určených k řízení Dependency Injection (dále DI). Zajímavost této události je v tom, že v prostředí Java EE již existuje poměrně pokročilá, né-li hotová, specifikace pod JSR 299 dříve nazývaná Web Beans. Nepodezírám lidi ze SpringSource či Google, že neví o tom, že Web Beans řeší skoro totéž. Jenže stará pravda je v tom, že když dva dělají totéž, není to totéž.

Reakce link Gavina Kinga, jakožto lídra specifikace JSR-299, na sebe nenechala dlouho čekat. Návrhu zmíněné dvojice vyčítá to, že je příliš povrchní a neřeší plno aspektu, které jsou s DI spojeny, například řízení v závislosti na deploymentu, a má pravdu. Otázkou zde je, jestli existuje takový zájem, který by SpringSource a Guice, aby se pouštěli do tvorby takové specifikace. Poslední poměrně skeptická vyjádření lidi ze SpringSource na adresu Java EE 6 a profilů, které se objevily na konferenci SpringOne, naznačují, že žádný takový zájem neexistuje.

Většina věcí, o kterých Gavin King píše, je minimálně Spring frameworkem nabízena out of box. Možná mají lidé kolem Roda Johnsona jenom pocit, že to s JSR-299 dopadne jako s jinými poměrně ambiciozními specifikacemi v Java EE. Problém této specifikace je možná v tom, že nebyla od začátku psána jako striktně DI orientovaná specifikace, tedy její přenositelnost do prostředí standardní Javy je velice omezená. Takže to dopadne jako experiment na vývojářích použitelný ve třetí verzi, ačkoliv mě osobně ta specifikace nepřijde vůbec špatná. Další možností je, že JSR-299 nebude nakonec součástí Java EE prověřit, což mohou zase vědět lide ze SpringSource.

Ať je ten důvod jakýkoliv, je nesporným faktem, že to vrhá špatné světlo na celý specifikační proces Javy. A opět, s jeho kritikou nikdy Rod Johnson & spol. nikdy nešetřili. Ve výsledku to pak vypadá, že si všichni sledují jenom vlastní zájmy, a na nějakém širší shodě vlastně nikomu nezáleží.

středa 22. dubna 2009

Do pranice: malé samopopisující versus velké okomentované

Během code review jsem se začetl do knihy Refactoring od Martina Fowlera a musím říci, že jeho styl programování se mi velice líbí. Jde o přístup k tomu jaký volí zápis metod a využívání extract method. Obvykle co vidím nejen sám u sebe je přístup delší metody s vloženými komentáři (pokuď vůbec) co daná část metody dělá.

public Configuration getConfiguration() {

    // load the driver (supplied to installer) using custom classloader
    try {
        if (driverClass != null) {
            loadDriver(driverClass, dbDrivers);
        }
    catch (ClassNotFoundException e) {
        throw new ConfigurationException(e);
    }

    // configure datasource
    BasicDataSource dataSource = new BasicDataSource();
    // Do not set the class name, becuase the datasource calls
    // Class.forName only in the systemclassloader where the driver
    // is not present.    
    // dataSource.setDriverClassName(driverClass);
    dataSource.setUrl(connectionURL);
    dataSource.setUsername(userName);
    dataSource.setPassword(password);
    dataSource.setInitialSize(1);
    dataSource.setMaxActive(15);
    dataSource.setDefaultAutoCommit(true);

    // create configuration instance
    Factory scopes = ScopeFactory.getInstance();
    Configuration cfg = new Configuration(scopes);
    cfg.setDataSource(dataSource);

    return cfg;
}
Java2html

Podle Fowlerova receptu by mohl kód po refaktoru vypadat následovně.

public Configuration getConfiguration() {
    loadDriverInCustomClassloader();     
    BasicDataSource dataSource = configureDataSource();    
    return createConfigurationInstance(dataSource);
}

protected void loadDriverInCustomClassloader() {    
    try {
        if (driverClass != null) {
            loadDriver(driverClass, dbDrivers);
        }
    catch (ClassNotFoundException e) {
        throw new ConfigurationException(e);
    }
}

protected BasicDataSource configureDataSource() {
    BasicDataSource dataSource = new BasicDataSource();
    // Do not set the class name, becuase the datasource calls
    // Class.forName only in the systemclassloader where the driver
    // is not present.    
    // dataSource.setDriverClassName(driverClass);
    dataSource.setUrl(connectionURL);
    dataSource.setUsername(userName);
    dataSource.setPassword(password);
    dataSource.setInitialSize(1);
    dataSource.setMaxActive(15);
    dataSource.setDefaultAutoCommit(true);
}

protected Configuration createConfigurationInstance(BasicDataSource dataSource) {    
    Factory scopes = ScopeFactory.getInstance();
    Configuration cfg = new Configuration(scopes);
    cfg.setDataSource(dataSource);
    return cfg;
}
Java2html

Fowler uvádí tři základní důvody pro tento přístup.

  • lepší znovupoužitelnost metod uvnitř třídy pokud jsou jemnější
  • snazší překrytí v potomkovi
  • lepší čitelnost, větší metody se čtou jako série komentářů

Mě osobně přijde jako nejrelevantnější poslední bod, tedy čitelnost vlastního kódu. Na příkladu, který jsem uvedl, to ještě možná tak nevypadá, ale pokud se metody táhnou jak špagety, tak mi to přijde jako ideální přístup pro zlepšení čitelnosti a tím pádem kvality kódu.

úterý 14. dubna 2009

Google Application Engine, konec Java hostingu?

Minulý týden oznámila firma Google podporu Javy pro jejich platfotmu Google Application Engine. Byla to zpráva poměrně překvapivá, protože dlouhou dobu vše nasvědčovalo tomu, že Google zvolí jiný jazyk kvůli všeobecně známé problematičnosti s hostováním Javy. Alespoň takové byly náznaky nebo alespoň jejich interpretace uvnitř Java komunity, které Google nikdy nijak nekomentoval. Možná to bylo nakonec dobře, protože tím na sebe Google nevytvářel zbytečný tlak spojený s veřejným oznámením připravované podpory. Pod pokličkou se pilně pracovalo na řešení, které umožňuje běh webových aplikací postavených nad Javou.

V této souvislosti není na škodu zamyslet se nad tím, proč byla nakonec zvolena Java. Bylo to zřejmě pragmatické rozhodnutí učiněné na základě faktu, že podpora Java znamená fungující Java Virtual Machine (JVM), která je schopna sama o sobě hostovat kromě vlastního jazyku Java i další jazyky jako například Ruby či Groovy. To určitě hrálo Jave do karet.

Z technického hlediska Google App Enginu stojí za zmínku jakým způsobem si Google poradil s úskalími, které Java pro hosting přináší. Kromě věcí, které není zas až tak složité ohlídat jako například vytváření nových vláken či ukončení běhu JVM, je zajímavý například limit pro maximální doba odpovědi na požadavek, která je 30s. Pokud aplikace v požadovaném limitu nevrátí odpověď, má uživatel smůlu. Z pohledu škálovatelnosti klade Google App Engine důraz na to, aby se stav pokud možno nedržel v session na úrovni HTTP protokolu. Zapomeňte na sticky session, protože každý požadavek může směřovat na úplně odlišný server.

Hned pár hodin po ohlášení podpory Javy se začalo spekulovat, jestli to bude znamenat konec konkurenčních hostingů. Myslím si, že nikoliv a ty důvody jsou čistě technického charakteru. Možnosti škálovatelnosti aplikace postavené nad Google App Engine jsou sice takřka neomezené, ale daň je krvavě placené kompromisy na implementační úrovni. Pokud vezmeme jakoukoliv klasickou webovou Java aplikaci, tak při jejím přenesení pravděpodobně spláčeme nad výdělkem. Kromě masivního využívání session pro udržení stavu konverzace bude tím nejzásadnějším problémem relační databáze.

Dvacet let jsme stavěli naše aplikace nad relačními databázemi, ale Google App Engine nic takového nenabízí. Místo toho slouží pro uložení dat BigTable, která s pomocí Map/Reduce frameworku nabízí neskutečné možnosti v oblasti škálovatelnosti na úrovni zpracování dat ale... Přestože Google App Engine nabízí vyšší úroveň abstrakce nad BigTable v podobě ochuzené implementace JPA či JDO, jedná se poměrně o fundamentální posun ve vnímání toho jak jsou data uložena a jak s nimi pracovat. Nejedná se nejen o posun ve vnímaní, ale i ryze praktické důvody jako jsou nástroje a postupy, které byly dlouhodobě používány.

Z výše uvedeného je patrné, že Google App Engine nebude rozhodně vhodný pro všechny typy webových aplikací. Pokud není hlavním kritériem aplikace škálovatelnost, pak Google App Engine nabízí sice zajímavé možnosti, ale vykoupené zásadními kompromisy při návrhu a vlastní implementaci, kdy tím nejzásadnějším je právě uložení a práce s daty. To bude hlavní příčina,že se nedá očekávat nějaký masivní přesun aplikací na Google App Engine. V poslední době se díky masivnímu rozvoji virtualizace objevilo několik zajímavých obláčku, např. Stax , kde je Java platforma nabízená jako služba. V takovém řešení dostanete k dispozici Tomcat, MySQL a platíte přenesená data a procesorový čas a nebudete tak nuceni dělat nějaké zásadní kompromisy v místech, kde to vaše aplikace zřejmě nepotřebuje.

Zdroje

středa 8. dubna 2009

Micro-blogging jako nástroj pro zlepšení týmové komunikace

Některé myšlenky začínají opravdu kouzelně. Včera za mnou přišel jeden z kolegů pozeptat se, jestli náhodou nemám nabíječku na jeho typ mobilního telefonu. Při té příležitosti utrousil otázku, co si jako zasloužilý bloger, myslím o využití formátu micro-blogging pro zlepšení komunikace mezi týmy. Nejdřív jsem nechápal na co se mě pta, ale pak mi vysvětlil, že micro-blogging je například Twitter, který právě vidí na displeji mého notebooku.

Pokud o Twitteru nic nevíte, doporučuji seriál, z kterého jsem si dovolil použít následující popis:

Twitter je instant messaging (nástroj pro výměnu okamžitých sdělení) dostupný z webové stránky. Na Twitteru můžete publikovat svoje příspěvky (takzvané Tweety) o délce maximálně 140 znaků. Když na Twitteru někoho následujete (following), můžete číst jeho příspěvky, sdělení. Když oni (followers) následují vás, mohou číst vaše příspěvky.

Pokud pracujete ve větším týmu, třeba jako já, je občas problém udělat nějaké krátké sdělení a o něco zajímavého se podělit s vašimi kolegy. Můžete najít užitečný nástroj, zajímavý článek, chystáte se udělat nějaký větší zásah a nejste si jistí jeho vedlejšími efekty, či něco podobného. V takovém případě máte dilema, můžete to poslat na společný mail, ale zase to muže být informace, která nezajímá všechny. Jinými slovy, ředitele našeho centra asi nebude zajímat, že vyšla nová verze Mavenu. Vytvářet kvůli tomu příspěvek do blogu je zase moc pracné a navíc to většinou předávaná informace nemá hlubší charakter.

Micro-blogging je právě úžasným kompromisem mezi mailem a regulérním příspěvkem pro blog, někde jsem viděl přirovnání SMS přes internet. Zprávu vidí všichni kdo vás následují a vy tak neotravujete další spoustu lidí, které pravděpodobně o vaše komentáře nemají zájem.

V našem případě by se systém alá Twitter dal integrovat s vývojářskými nástroji. Občas se stane, že rozbijete build. V takovém případě je na build serveru vidět kdo to rozbil, ale už není vidět, jestli na tom ten člověk pracuje. Ta informace jestli na tom člověk pracuje, či jestli vůbec ví o tom co způsobil, by se dala integrovat právě přes systém alá Twitter. U rozbitého buildu by bylo tlačítko, které by po kliknutí vytvořilo automaticky tweet. Na build serveru by se zase naopak reverzně k zbořeným buildum asociaovaly tweety.

Já osobně jsem myšlence zapojení micro-bloggingu jako součásti mezi týmové komunikace velice nakloněn. Stejně jako na Twitteru se při použití za zavřenými dveřmi uvnitř firmy najdou hvězdy, které bude sledovat většina a také pasivní uživatelé, které nebude sledovat skoro nikdo. Díky tomu bude zaručena přirozená rovnováha mezi tím, že podstatné informace od lidí, co mají co říci, proudí ke všem a ty méně podstatné míří pouze k několika málo zainteresovaným.

neděle 5. dubna 2009

Tranzitivní závislosti v Mavenu z pohledu návrhu modulu

Tranzitivní závislosti v Mavenu neodpouštějí chyby v návrhu struktury modulů. Pojďme se podívat na to s čím je potřeba počítat. Mějme modul Foo. Tento modul je použit jednak v kontextu serveru, jako součást webové aplikace, a jednak v lokálním kontextu jako součást command line nástroje. Modul Foo má pro svojí řadu několik závislostí. Řekněme jednu společnou pro obě prostředí a potom dvě rozdílné množiny, každou pro jedno prostředí, jak je znázorněno na následujícím obrázku.

Mechanismus tranzitivních závislostí v Mavenu způsobí, že pokud modul Foo přidáme do WARu, dostanou se nám tam všechny závislosti a to včetně těch lokálních (žluté krabičky). A naopak, pokud si necháme vygenerovat například classpath pro lokální použití, dostanou se nám tam závislosti nutné pouze pro prostředí serveru. V případě, že by šlo pouze o malé množství závislostí, asi by to nevadilo, ale v případě, že se jedná o větší množství, musíme se tím začít zaobírat.

První a nejlepší způsob je udělat refaktor modulu Foo a ten rozdělit na tři části. Na modul obsahující logiku pro server Foo server, modul obsahující logiky pro lokální použití Foo local a modul obsahující logiku společnou pro obě části Foo common. Tento poslední modul vznikne pouze za předpokladu, že existuje sdílená logika. Zároveň s rozčleněním do těchto modulů roztrhneme i závislosti původního Foo modulu. Ideální stav zobrazuje následující obrázek.

No nežijeme v ideálním světě a tak se může ukázat, že modul Foo půjde refaktorovat velice složitě, pokud vůbec, neboť se může jednat o dědictví z minulosti. V takovém případě máme dvě možnosti. Tam kde modul Foo chceme použít, uděláme nechtěným závislostem přítrž jejich explicitním vynecháním. Toto řešení má tu nevýhodu, že na každém místě použití modulu Foo musíme tento manuální krok zopakovat. Pokud nám v budoucnu nastane situace, že modul Foo bude potřebovat novou závislost, řekněme kolizní závislost, ať již pro serverové či lokální prostředí, budeme muset opravit manuální odstranění o další závislost.

Druhou možností je využití takzvaných volitelných (optional) závislostí, které mají tu vlastnost, že nejsou součástí tranzitivního uzávěru. Na dalším obrázku jsou volitelné závislosti vyznačeny čárkovaně. Díky tomu, že nejsou součástí tranzitivního uzávěru, tak je sice moduly, které je používají "nenakoupí", ale zároveň to znamená, že je budou muset opět explicitně uvést tam kde budou potřeba. To ilustruje následující obrázek, kdy si WAR explicitně přidává volitelné závislosti.

I toto řešení má stejnou nevýhodu v podobě manuálního opakovaní všech volitelných závislostí na každém místě použití a s tím spojený problém budoucího rozšíření. Pro eliminaci této nevýhody lze použít následujícího triku. Zavedeme si speciální moduly pro obě prostředí, které nám poslouží pouze k seskupení závislostí. Díky tomu budeme mít management závislostí pro dané prostředí centralizovaný pouze do jednoho místa. Tyto ad hoc moduly je pak možné použít namísto původního modulu Foo.

Tento seskupovací workaround lze použít v podstatě na úpravu jakýchkoliv nevyhovujících závislostí a lze jej vhodně kombinovat s explicitním vynecháním závislostí. Je škoda, že Maven nenabízí podobný mechanismus urovnání závislostí nějakým lepším způsobem. Na druhou stranu na to lze koukat i tak,že Maven vynucuje správné rozčlenění modulů a schválně nenabízí prostředky pro jejich obcházení.

středa 1. dubna 2009

NetBeans 7

Podařilo se mi dostat k připravované verzi nových NetBeans. Jak je vidět již na splash obrazovce, vývoj této verze má jasné směřování...

neděle 22. března 2009

Sochař a kamen

Dnes nebude komentovat žádnou "politickou" událost anebo šuškandu, nebudu se zaobírat nějakým skvělým frameworkem, ale zkusím se s Vámi podělit trošku programátorského know how (možná silné slovo v tomto případě), které mi ještě zbylo. Nad některými věcmi člověk nepřemýšlí, prostě je dělá automaticky. Zkoušeli jste se někdy zamyslet nad tím, jak při programování řešíte úlohy, které máte zpracovat. Já jsem u sebe našel něco, čemu říkám metoda postupného opracování, a používám pro to metaforu sochaře a kamenu.

Představte si jak asi pracuje sochař, když má vytvořit nějakou sochu. Na začátku vezme neopracovaný kus kamene, majzlík, kladivo a začne s hrubým otesáním. Socha dostává nejdříve základní obrysy těla. Tady je hlava, trup, končetiny. Postupem času začne sochař zabíhat do větších detailů. Tady je potřeba vytesat prsty, oči, nos. Pomalými krůčky se blíží k finální podobě, a každý další úder přidává na detailu.

Vždy když programuji, používám stejný postup jako sochař. Tedy začnu hrubými obrysy a postupně přidávám na detailu. Snažím se nezabíhat do zbytečných detailů, dokud nemám hotové základní obrysy. Krásně vytesaná ruka, mi neposlouží, pokud nebude vidět, že patří k nějakému tělu. Výsledkem má být socha jako celek, na to musíme vždy myslet. Ne ruka, hlava či noha ač by byla sebekrásnější . Stejné je to při programování.

Moji výhodou oproti sochařovi je, že mohu skoro kdykoliv vrátit úder majzlíku o několik kroků zpět. Díky iterativnímu vývoji nemusím v hlavě držet zbytečné detaily, na které je ještě čas a nebo na ně nemusí vůbec dojít, protože se změní například můj pohled na věc, anebo zadání. Všechno má svůj čas. Zároveň mohu kdykoliv odevzdat něco, co se bude více či méně podobat požadované soše, v závislosti na počtu iterací. Nemusí být dokonalá, ale socha to je.

středa 18. března 2009

IBM na námluvách se Sunem

Vypadá to vypadá, že IBM by mohlo koupit firmu Sun viz IBM in Talks to Buy Sun in Bid to Add to Web Heft. I hned po tomto ohlášení se začalo spekulovat, co by to mohlo znamenat pro Javu a další technologie Sunu.

Historická zkušenost praví, že tyto obchody bývají dvojího druhu. Možnost první, něco co má konkurence vám chybí v portfoliu, tak jí prostě koupíte. Možnost číslo dva, potřebujete se zbavit konkurence, tak jí prostě koupíte a ukousnete si její podíl na trhu anebo jeho část. Vzhledem k portfoliu IBM se nezdá, že by to byla možnost číslo jedna, alespoň ne jako primární motivace.

To by mohlo znamenat, že by IBM dále neinvestovalo do technologií Sunu. Těžko se dá predikovat, ale asi by nedávalo smysl, aby mělo IBM dvě IDE platformy jako NetBeans a Eclipse. Leckterého příznivce technologií Sunu jako GlassFish, NetBeans, Java FX atd. by mohlo hřát, že se jedna vesměs o open source technologie a tedy, že případný obchod přežijí. Ano, je skutečně pravděpodobně, že by ty technologie nezanikly. Bohužel jejich další rozvoj by se uzavřením investic ze strany IBM zřejmě úplně pozastavil. A tím je v konečném důsledku odsoudil k pomalému zániku.

V internetových diskuzích už se objevila celá řada spekulací a poznámek, které tento obchod komentují. Takřka nikdo neprojevuje radost nad tím, že potenciálním kupcem Sunu bude zrovna IBM. Sun se totiž choval jako inovátor, oproti tomu je IBM vnímaná jako zkostnatělý a neagilní moloch, alespoň takového jsem nabyl dojmu. Podle jedné ze spekulací, která se objevila, by nakonec celému obchodu mohl udělat přítrž americký antimonopolní úřad. Nakonec bych to zakončil nějakým optimistickým zvoláním, třeba: třeste se budoucnost je nejistá. Ve skutečnosti to nebude tak horké, protože se ještě nic neupeklo.

neděle 1. března 2009

Univerzální jazyk, děkuji nechci

Stále více sa utvrzuji v tom, že nelze navrhnout a uspět s jedním univerzálním jazykem použitelným pro všechny programové domény a cílová prostředí. Java jako jazyk si prošel dlouhým obdobím vývoje a nebojím se jej označit za jazyk zralý. Dlouhou dobu mluvím o tom, že snahy o jeho rozšíření v konečném důsledku spíše uškodí jednak ztrátou zpětné kompatibility a jednak zvýšením komplexnosti. Za snahou rozšíření jazyku stojí dva důvody, tím prvním je nepochybně snaha držet prst na tepu doby a tím druhým urputná snaha udělat z Javy univerzální multiúčelový jazyk.

Zkusme na chvilku přijmout fakt, že se z Javy stane multiúčelový jazyk. Budeme pomocí něho psát aplikace pro mobilní zařízení, serverové či desktopové aplikace a nebo v něm popisovat front end nějaké bohaté internetové aplikace (Rich Internet Appplication). Stop. My už to vlastně děláme. Ne všude se ovšem Java ukazuje jako nejvhodnější jazyk. Má svoje omezení a limitace. Ty jsou dané koncepcí a návrhem jazyku z jeho raných dob. Když se rozhlédneme kolem sebe, uvidíme zde jazyky, které jsou v dané oblasti minimálně agilnější a lépe plní potřeby vývojářů. Co s naším jazykem? Můžeme jej dál ohýbat podle módních trendů potřeb s rizikem, že výsledkem bude zvláštní kompilát nebo myšlenku univerzálního multiúčelového jazyku opustit.

Jakkoliv je myšlenka multiúčelovho jazyku více než lákavá, jeho realizace je hodně na vážkách. Nevěřím, že to může prakticky fungovat. Jako daleko bližší vnímám koncept více jazyku integrovaných na úrovni virtuálního stroje/platformy jako je Java či .NET. Ve chvíli kdy píšu kód, jehož zpracování musí být efektivně paralelizovatelné, pak šáhnu pravděpodobně po jazyku, který bude pro tyto účely navržen od počátku např. Erlang. To samé platí i pro další aplikační domény, kde bych měl volit jazyk podle účelu, ke kterému byl navržen. Výhodou je vyšší produktivita a efektivnější vývoj. Myšlenka správného jazyku na správnou věc je zastoupena i v prosazujícím se trendu doménově specifických jazyků (DSL).

Vice jazykový koncept ovšem přináší úskalí, na který doplatil již prastarý Babylón. Pověstné zmatení jazyků je jednou z věcí, kterou je nutné mít stále na zřeteli. Nestačí umět jeden jediný univerzálnímu mulitfunkčnímu jazyk, ale najednou jazyků více. Na tento argument pravděpodobně narazíte u svých manažerů a nelze jej jen tak shodit ze stolu. Proto je důležité vnímatm na jaké úrovni jsou jazyky integrované. Virtuální stroj je skvělé místo, protože umožňuje vzájemnou kombinaci na prověřeném podvozku. Ten sám o sobě zaručuje, že principy fungování základy zůstaly kvalitní. Třešinkou na dortu je, pokud zde existuje podobnost nebo příbuznost jazyků jako například Java a Groovy.

čtvrtek 26. února 2009

Efektivita buildovacích nástrojů rozhoduje

Po té co jsem si pročetl článek Maven or Ant, který raději vůbec nečtěte neboť je plný nesmyslů, jsem se rozhodl, že letmo nakouknu na Gradle, jestli třeba náhodou ten Maven... Hned na úvodní stránce jsem si přečetl, že je to v podstatě přes Groovy obalený Ant s dependency managementem řešeným přes Ivy či Maven. Abych to zkrátil, po letmém prolétnutí Gradle user guide jsem spokojeně zavřel prohlížeč a řekl si, že touto cestou opravdu ne.

Gradle bude určitě skvělý systém, ale bohužel nenaplňuje jednu fundamentální potřebu, alespoň tedy co se mojí maličkosti týká. Nevím jestli to máte jinak, ale já od buidlovacího systému (degradujme na tento termín nástroje - Ant, Maven, Gradle, Gant atd.) očekávám především efektivitu vyjádřenou poměrem mé snahy oproti tomu co na mě vypadne.

Tím chci říci, že množina mnou aplikovaných případů užití je redukována na vytvoření projektu, kompilaci, puštění testů, zbuildování vysledného package a natažení projektu do IDE. Tečka, nic víc. Jízlivá otázka, potřebujeme vůbec něco víc? Odpověď nechám na Vás. Čím jednodušeji budou splněny tyto případy užití z pohledu buildovacího systému, oproti tomu co budu muset udělat, tím větší efektivitu my ten systém přinese.

Maven mi zatím přináší nejvyšší efektivitu. Už jenom vytvoření projektu přes archetype je otázka půl minuty. A od toho se samozřejmě odvíjí i další případy užití. Oproti tomu systémy jako Gradle nebo Ant mě nutí k něčemu co je mi ze srdce odporné a to k programování vlastního buildu. Kdy už konečně autoři těchto systémů pochopí, že jejich uživatelé nechtějí řešit takové problémy, že je někde potřeba uvádět (programování je jenom forma zápisu) cosi ohledně kompilace, packagingu apod. oni prostě ten systém chtějí používat!

Proto mám tak rád Maven. Jeho autoři totiž pochopili, že pro běžné developerské použití by měla být námaha s tím spojená rovna pokud možno nule. Samozřejmě pokud pomineme čtení nějakoho howto či dokumentace, které nás čeká při začátku používání jakékoliv nové technologie.

středa 25. února 2009

Instantní IDE

Jak hodně je vzdálená myšlenka IDE, které poběží v prohlížeči? Když jsem se poprvé dozvěděl o tomto konceptu, tak jsem si neuměl představit, jak by to mohlo fungovat. Odpověď mi dal projekt Bespin, ke kterému vzniknul na Eclipse postaveny backend. Ta myšlenka je docela jednoduchá, v prohlížeči běží jenom vlastní editor, všechny úlohy jsou na pozadí nebo formou uživatelem zadaných příkazů posílány na server, kde se vykonají a zpět jsou poslány jejich výsledky.

Za tímto účelem Bespin definuje server API, které představuje bridge mezi klientskou a serverovou stranou. Bespin je standardně dodáván se serverovým backendem postaveným na Pythonu. Tento backend je ovšem jednoduše vyměnitelný.

The Eclipse IDE, as you know it, is an OSGi-based application, and is built entirely out of components (called plug-ins or bundles). Many of these components can run headless, on a server, such as the underlying resource model, the incremental Java compiler, etc. Using the headless components, it was very easy to implement the Bespin client-server API.

Chvíli jsem si zkoušel s Bespinem upraveným pro editováni Javy hrát a mám z toho dva silné dojmy. Ten první se dá jednoduše vyjádřit zvoláním funguje to! Například kompilační chyby jsou reportovány v editoru. Ten druhý se dá charakterizovat jako pěkné na efekt, ale prakticky nepoužitelné. Dlužno dodat zatím.

Komfort desktopového IDE je o světelnou glaaxii někde jinde. To je samozřejmě pochopitelné, protože desktopová IDE ušla pěkně dlouhou cestu a o Bespinu se nedá snad ani říci, že by byl v plenkách. Zkusme se na chvíli od tohoto faktu oprostit a zamyslet se nad tím, co by nám mohly IDE běžící v browseru přinést. Těch výhod oproti klasickému desktopovému IDE vidím několik.

Jako první věc člověka napadne, že výhodou bude přítomnost IDE všude tam kde máme webový prohlížeč. To sebou nese celou řadu ne tak docela patrných kladů. Nemusíme se tak starat na každém počítači kde pracujeme o setup IDE, checkout projektů, různé nastavení buildování atp. To vše leží nastaveno někdo na serveru a já jako vývojář se o to nemusím starat.

Díky tomu, že vše leží někde na serveru, nemusím zmiňovat maličkosti je zálohování. Bude například jednoduché udělat upgrade na novější verzi IDE. Kolikrát se vám stalo, že jste potřebovali rychle něco upravit, ale IDE se zrovna rozhodlo, že potřebuje uvolnit naalokovanou paměť a nebo, že vám na pozadí běžela úloha, která práci IDE zpomalovala. V případě na serveru běžících komponent to není problém a myšlenka využití cloud computingu se přímo nabízí. Na jednou nehrozí, že by bylo málo místa na disku, výpočetního výkonu a nebo paměti.

Předpřipravené prostředí je další výhodou webových IDE. Žádné stahování Eclipse, Javy, nastavení Mavenu či Antu. Prostě se jenom přihlásíte a je to. Něco jako instantní polévka, nasypete do hrníčku a zalijete horkou vodou. Někdo v souvislosti s webovými IDE často mluví o takzvaném kolaboračním případu užití. Například editujete soubor a váš kolega ve svém IDE vidí co přesně děláte. Osobně se mi nezdá zatím nijak zvlášť silný, ale třeba začnou sociální sítě pronikat i do této oblasti.

Webová IDE mají budoucnost, nedá se asi očekávat, že tu budeme mít v nejbližší budoucnosti IDE pro Javu či .NET, které bude konkurovat dnešním desktopovým IDE. Spíše se dá očekávat pozvolný nástup a to v oblasti dynamických jazyků a webových technologií jako Ruby nebo PHP, kde je vývoj o poznání jednodušší než v Jave.

středa 18. února 2009

CZPodcast #30 - novinky

Firma JetMinds nám poskytla zázemí pro nahrávání podcastu číslo 30. Tématem byly novinky, takže doufáme, že se budete dobře bavit.

sobota 14. února 2009

Springframework mockujeme beany

V tomto článku si ukážeme, jakým způsobem je možné docílit mockování bean (POJO managovaná Springem). Představme si situaci, kdy chceme některé z naších bean pro běh testů nahradit mocky.

Mějme rozhraní FooInterface, jeho implementaci FooBean a třídu BeanWorkingWithFoo, která používá toto rozhraní pro svojí činnost.

public interface FooInterface {
  public String getSomething();
}

public class FooBean implements FooInterface {

  private String something;
  
  public FooBean(String something) {
    super();
    this.something = something;
  }

  public String getSomething() {
    return something;
  }

}

public class BeanWorkingWithFoo {
  private FooInterface fooInterface;

  public FooInterface getFooInterface() {
    return fooInterface;
  }

  public void setFooInterface(FooInterface fooInterface) {
    this.fooInterface = fooInterface;
  }
}      

Konfigurace Springu pak vypadá následovně.



<beans>

  <bean id="foo" class="FooBean">

    <constructor-arg value="foo" />   

  </bean>

  

  <bean class="BeanWorkingWithFoo">

    <property name="fooInterface" ref="foo"/>

  </bean>

</beans>

K testování třídy BeanWorkingWithFoo máme následující kód.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath*:META-INF/applicationContext.xml",
     })
public class PrimaryBeanTest {

  @Autowired
  private BeanWorkingWithFoo beanWorkingWithFoo;

  
  @Test
  public void testSomething() {
  }
}

Nyní by jsme rádi zajistili, aby námi testovaná instance BeanWorkingWithFoo používala mock beanu FooInterface. Jaké máme možnosti. Asi nejjednodušší postup spočívá v setup metodě testu, kde nastavíme do instance BeanWorkingWithFoo programově vytvořenou instanci mocku. Bohužel né vždy tomuto řešení kód nahrává. Například nemáme potřebný setter a nebo mockovaný objekt je uhnízděn někde hlouběji v objektové struktuře. Což je sice problém řešitelný, nicméně nikoliv elegantní.

Elegantní řešení by spočívalo v tom, že bychom si nadefinovali testovací kontext, v tomto kontextu nadeklarovali náš mock jako beanu a nechali Spring původně deklarovanou beanu překrýt mockem. To můžeme udělat tak, že námi deklarovaná beana mocku bude mít stejné id jako beana původní a zároveň pokud se kontext s mockem nahraje až jako druhý. BeanFactory se pak postará o to, že původní beana daného id bude překrytá.

Toto řešení má dvě nevýhody. Musíme vždy zaručit, že přepisovaná beana má id, a kontext s definovanými mocky je nahráván jako poslední. O nevýhodu se jedná protože nám specifické požadavky testů diktují implementační detaily. Né vždy totiž chceme, aby naše beany byly referencovány idčkem, ale preferujeme autowiring typem. Druhou nevýhodou je fakt, že při nahrávání kontextů přes wildcard na classpath je složité zaručit jejich správné pořadí (rozhoduje pořadí JARů na classpath).

O autowiringu typem jsem mluvil především ve spojitosti s řízením dependency injection anotacemi, kde je typ jejich defaultním určovatelem. V našem případě, beana BeanWorkingWithFoo může být místo v XML zedklarována pomocí anotací (opomeňmě fakt, že by id referencované beany by šlo vynutit anotaci Qualifier).

@Component
public class BeanWorkingWithFoo {
   @Autowired
  private FooInterface fooInterface;

  public FooInterface getFooInterface() {
    return fooInterface;
  }

  public void setFooInterface(FooInterface fooInterface) {
    this.fooInterface = fooInterface;
  }
}

Kvízová otázka. Co se stane a jak tomu zabránit pokud máme více bean (mock a reálnou implementaci) stejného rozhraní (FooInterface)?

IoC kontejner nám při startu zahlásí, že se nedokáže rozhodnout jaká z bean má být použita a skončí s chybovou hláškou. V tomto případě (vícenásobný výskyt při autowiringu typem) si můžeme pomoci způsobem, na který mě upozornil kolega (díky Sváťo :-), a který by mi asi jinak zůstal skryt v dokumentaci Springu viz sekce Autowiring collaborators. My totiž můžeme beanu našeho mocku označit takzvaně jako primary. Pokud je totiž jedna z bean označena jako primary, pak je automaticky zvolena jako nejvhodnější kandidát pro autowiring.



<beans>

  <bean class="FooBeanMock" primary="true" />       

</beans>

Tímto způsobem jsme ošetřili případy, kdy se používá autowiring typem. Nyní nám zbývá dořešit případy, kdy ovlivnění pořadí kontextů není jednoduché. V tomto případě si pomůžeme využitím jednoho z rozšiřitelných míst IoC kontejneru. Naimplementujeme rozhraní BeanFactoryPostProcessor a díky tomu budeme moci překrytí bean programově. K překrytí pojmenovaných bean využijeme aliasování. To znamená, že beana našeho mocku bude mít alias na idčko původní beany. Tím pádem všechny reference jménem na původní implementační beanu skončí na našem mocku.

public class MockPostProcessor implements BeanFactoryPostProcessor {
  
  public void postProcessBeanFactory(
      ConfigurableListableBeanFactory beanFactorythrows BeansException {
    //Ziskame jmena vsech bean s rozhranim FooInterface
    String beanNames[] = beanFactory.getBeanNamesForType(FooInterface.class);
    
    //Jedna z techto bean je nas mock a tu mi musime najit 
    //resp. jeji jmeno, na ktere ukaze alias. Pro lepsi rozpoznavani
    //jestli je bean mock a nebo neni jsem si udelal specialni
    //anotaci Mock. Diky tomu bezpecne poznam beanu mocku.  
    String mockBeanId = null;
    for(String beanName : beanNames) {
      Object bean =  beanFactory.getBean(beanName);
      if(bean.getClass().getAnnotation(Mock.class!= null) {
        mockBeanId = beanName;
        break;
      }
    }      
    
    //Nyni uz staci nastavit  idcko naseho mocku jako alias
    //pro vsechny puvodni idcka.  
    if(mockBeanId != null) {
      for(String beanName : beanNames) {          
        if(!beanName.equals(mockBeanId)) {//osetren alias sam na sebe
          beanFactory.registerAlias(mockBeanId, beanName);
        }   
      }
    }
  }
}

Takto vytvořená postprocessor přidáme do kontextu k definici mocku.



<beans>

    <bean class="MockPostProcessor"/>

    <bean class="FooBeanMock" primary="true" />    

</beans>

Samozřejmě postprocessor lze neimplementovat obecně, aby dokázal aliasovat všechny nadeklarované mocky.

úterý 10. února 2009

Assertions, takové malé připomenutí

Když byly v Jave 1.4 představeny Assertions, tak kde kdo asi očekával, že se klíčové slovo assert stane běžnou součástí zdrojových kódů. Nevím jak vy, ale jak pátrám v paměti, tak jsem snad assert nepoužil. Můžete namítnout, že to vůbec nic neznamená, ale co hůř, já jsem použití assert snad ani neviděl ve zdrojácích open source knihoven.

Je to skutečně s podivem, protože assert má svůj význam, minimálně namísto komentářů "sem to nikdy nedojde". Jako vysvětlení toho, že se nám javistům assert nikdy nedostalo pod kůži mám tři důvody.

Marketing

Přišlo mi, že kolem Javy 5, 6, 7 byl docela velký humbuk. Na člověka se valila spousta informací co v dané verzi bude a co nebude a vedly se učené dišputace proč tato vlastnost ano či ne. Sun trochu odfláknul propagaci, myslím že kdyby na nás z každého zdrojáku v tutoriálech Sunu koukal assert, tak tu nemám teď psát.

Vymahatelnost

Velkou nevýhodou použití assert spatřuji v tom, že jej sice máte v kódu, ale pro jeho zapnutí potřebujete nastavit speciální přepínač pro JVM. Jenže pamatujte na to... Daleko lepší by bylo aktivovat assert na úrovni kompilátoru a to ještě tak, že by byl standardně zapnutý. K jeho vypnutí by docházelo na explicitní žádost. Zde je alespoň z mého pohledu slabá obhajoba JVM přepínače.

Unit test kultura

Tuším, že assert konstrukt převzala Java z Céčka, kde se jedná o celkem zaběhnutou konvencí. Alespoň já o assert mluvím především s programátory, kteří na javu přešli z Céčka. Jenže v době zavedení do Javy, byl již poměrně silně zavedený koncept unit testů. Tedy to co se pomocí assert kontrolovalo mimoděk, tak se pomocí unit testů kontrolovalo (testovalo) přímo a tvoří to v Jave jakousi konvenci.

sobota 7. února 2009

Leakující streamy

Nedávno jsem opravoval jednu svojí botu, která byla způsobena tím, že jsem předpokládal, že JDBC driver resp. PreparedStatement uzavírá po ukončení transakce předaný InputStream. Bohužel nic takového se neděje. Naše speciální implementace InputStream se chovala tak, že určitou část dat si držela v paměti a zbytek odswapovala do souboru v tmp adresáři. Tento soubor se měl smazat při zavření asociovaného streamu a pro strýčka příhodu měl ještě nastavený deleteOnExit příznak .

Díky tomu, že se nevolal close daného streamu, tak se v tmp adresáři rojily nové soubory jako houby po dešti. To vedlo k tomu, že za určitou dobu běhu serveru tmp adresář přetekl a došlo místo a nebo file descriptory (chyba lávky - nody clusteru se tak často nerestartuji. Takže deleteOnExit byl pro parádu). Celá situace našeho streamu, byla ještě komplikovaná faktem, že o jeho vyrábění se také staral Hibernate, protože tento stream se použil při mapování jako user type. To znamenalo, že selektovaná entita měla asociovaný stream aniž by si to člověk uvědomil. Naštěstí byla většina kódu izolována pouze v persistentní vrstvě.

Najít a odladit všechny nezavřené streamy ovšem nebylo tak jednoduché, protože tam byla indirikece přes Hibernate a user type. Nakonec někde v kódu persistentní vrstvy zůstával nějaký leak, který jsem nebyl z kódu sto přímo vyčíst. Nakonec jsem byl nucen vytvořit speciální debugovací kód, který v konstruktoru našeho streamu vypsal stacktrace označený identity hashcodem a zároveň přidal tento identity hashcod do vzniklého souboru v tmp adresáři. Projetím logu a párováním pozůstalých souborů s označenými stacktracy se mi nakonec podařilo odstranit zbývající leaky.

Samozřejmě, mě nemohlo toto ad hoc řešení uspokojit, protože mi přišlo málo systémové. Kdokoliv kdo použije daný user type (používáme jej obecně pro binární data v DB) může snadno zapomenout na onu zákeřnou indirekci a leak je na světě. Taky jsem si chtěl být jisty, že všechny vyšší vrstvy někde nezapomenou zavolat uzavření streamu a tedy uvolnění drženého souboru. Metodologie, kterou jsem použil pro odhalení zbývajících leaku se mi osvědčila a tak nebyl důvod dotáhnout její použití.

Celý trasovací kód jsem vyčlenil do aspectu, takže kdykoliv je teď potřeba, tak můžeme pro naše integrační testy či manuální testy zapnout tento aspect, který na exit JVM vypíše neuzavřené streamy resp. kód, který je otevřel. Výstup pak vypadá přibližně následovně.


-------------------------------------------------------

Unclosed stream allocated from: 



java.lang.Thread.getStackTrace(Thread.java:1436)

cz.sweb.pichlik.leakdetector.LeakDetector.ajc$afterReturning$cz_sweb_pichlik_leakdetector_LeakDetector$1$5f03d6db(LeakDetector.aj:29)

cz.sweb.pichlik.leakdetector.FooInputStream.(FooInputStream.java:12)

cz.sweb.pichlik.leakdetector.LeakDetectorTest.testSmoke(LeakDetectorTest.java:11)

...zbytek vynechán  

  

Ve výše uvedeném výpisu jsem pro účely článku vynechal plný stacktrace. Kód, který leak způsobil vypadá následovně.

public class LeakDetectorTest {
  @Test
  public void testSmoke() throws Exception{
    new FooInputStream(getClass().getResourceAsStream("LeakDetectorTest.class")).close();
    for(int i = 0; i < 5; i++) { 
      new FooInputStream(null);
    }
  }
}

Aspect vypadá následovně.

public aspect LeakDetector {
    
    private final Map<Integer, StackTraceElement[]> openStreams;  

    pointcut streamConstructor(): target(FooInputStream&& (execution(FooInputStream.new(..)));
    pointcut streamClose(): target(FooInputStream&& (execution(void close()));
    
    public LeakDetector(){
        openStreams = new ConcurrentHashMap<Integer, StackTraceElement[]>();
        Runtime.getRuntime().addShutdownHook(new LeakPrinter(openStreams));
    }
    
    /**
     * Puts a stream into watched area.
     */
    after() returning: streamConstructor() {
        StackTraceElement stacktrace[] = Thread.currentThread().getStackTrace()
        Integer streamId = getObjectIdentifier(thisJoinPoint);
        
        openStreams.put(streamId, stacktrace);   
    }
    
    /**
     * Removes a stream from watched area.
     */
    after() returning: streamClose() {      
        Integer streamId = getObjectIdentifier(thisJoinPoint);
        openStreams.remove(streamId);
    }
    
    private Integer getObjectIdentifier(JoinPoint jp) {
        return System.identityHashCode(jp.getTarget());
    }

}

Aspect obsahuje dva pointcut výrazy. Jeden pro zachycení vytvoření streamu a druhý pro jeho uzavření. Na tyto dva pointcut výrazy jsou navěšené dvě advice. První advice zajistí, že když je stream zkonstruován, udělá se snapshot aktuálního stacktrace a ten se spolu s identity hashcodem uloží do mapy. Druhá advice zajistí, že při volání close metody streamu, se na základě identity hashcode odstraní z mapy příslušný záznam. Aspect má ještě ve vlastním konstruktoru vlákno, které zaregistruje jako shutdownhook. Vlákno nedělá nic jiného, než že vypíše obsah mapy. Na konci běhu programu máme v mapě tedy pouze stacktracy určující místa kde vznikají neuzavřené streamy.

Pokud chci aspect použít, tak jako nejvhodnější se jeví load time weaving. Díky tomu neni potřeba žádná speciální kompilace, protože aspect se dostane do kódu při classloadingu. Pokud si chcete hráti, tak k dispozici je Maven project se zdrojovými kódy a nastavenym AspectJ compilerem.

Související články