10. prosince 2008

Překlad výjímek z databáze při použití Hibernate

Kdo používá Hibernate, ten možná již tuší, kam budu dnešním příspěvkem mířit. Jde o to, že chyby, které detekuje Hibernate se snaží do výjimky dávat jméno třídy a atributu, který chybu vyvolal. Ovšem pokud vám chybu vyhodí databáze, pak vás Hibernate nechá ve štichu a předhodí vám výjimku datábáze a dělejte si s ní co chcete.

Toto chování se mi nikdy nelíbilo, protože mu moc nerozumím, Hibernate má vše co potřebuje. Zná dialekt, který by umožnil překlad databázově závislých výjimek, do obecné formy obsahující jméno tabulky a názvy sloupců. Následně je možné využít mapování a přeložit název tabulky a názvy sloupců na jméno třídy a atributů. Proč to Hibernate nedělá? Nevím ...

My jsme vždy chtěli mít vlastní DAO výjimky, které by byly nezávislé na použitém ORM. A zároveň jsme chtěli aby obsahovaly jméno třídy a atributů. Nikoliv tabulky a sloupce, protože tyto výjimky jsou většinou zpracovávány vrstvami aplikace, které o databázi nemají mít nejmenší tušení.

Řešení jsme měli, ale nelíbilo se nám, protože jsme de facto museli mapování zapisovat dvakrát (jednou z objektů do relací pro Hibernate a podruhé z relací do objektů). Dodnes nevím proč nejsou programátorsky přístupné mapovací soubory, nebo nevím jak je z Hibernate dostat, což jsme chtěli pro překlad sloupců na atributy použít. Občas jsme diskutovali co s tím, ale ne a ne přijít na ten správný nápad. Až takhle jednou jdeme z oběda a s kolegou Lubošem jsme si dali brain storming a triviální řešení jsme našli (nechápu jak to, že nás nenapadlo dřív).

Je až trapně triviální. Stačí si rozparsovat Hibernate mapovací soubory a vytvořit z nich mapování opačné, než jaké reprezentují. Tato akce představuje nesložitý algoritmus, jedinou složitostí je dědičnost, kde je nutno vytvořit vhodnou reprezentaci, aby se při zpětném překladu zvolilo správné jméno třídy (to nejkonkrétnější), v případě překladu více atributů umístěných různě hluboko v hierarchii tříd.

Druhým krokem je vytažení informace z SQLException, kterou vyhodí databáze. Zde je pár drobných oříšků, např. získání jmen sloupců v případě chyby unikátního klíče (námi použitá DB2 vrátí jméno unikátního klíče, které je nutno pomocí katalogu překlopit na jména sloupců).

Takže cca. po 3 dnech programování (nejprve jsem si dělal prototyp v groovy a pak jsem vytvořil kompletní implementaci v javě) máme řešení, se kterým jsme maximálně spokojeni. Stačí nám zapisovat Hibernate mapování a kód za nás udělá zbytek. My pak už pouze zachytáváme např. DARequiredException, která obsahuje jméno objektu a jeho atributu.

PS. Kód jsem neuváděl, protože není složitý, akorát ho je poměrně dost, takže by se velmi pravděpodobně jednoduchost sdělení hodně zkomplikovala.

1. prosince 2008

Lze testovat aplikaci, která s tím nepočítá

Motivací pro dnešní psaní je 28 czpodcast. Takže zpět k titulku, jde to, ale težko a to je ten problém. Ať už je to metoda, třída, modul nebo celá aplikace, vše musí být navrženo a naimplementováno s ohledem na testovatelnost.

A teď k jádru pudla. Testovatelnost UI je skoro to nejhorší. Ať je to UI webové, swingové a nebo nějaké jiné. Proč? Protože se mění. Většina změn aplikace se projeví v jeho uživatelském rozhraní. Proto se testy musí neustále měnit a modifikovat. Takže není ani tak problém v tom testy napsat, ale udržovat.

Dá se z této situace nějak vybruslit? Nedá, ale dá se řada věcí eliminovat. Tím co se eliminovat dá, je skutečnost, že se rozložení prvků v uživatelském rozhraní mění. Dojde-li k takové změně, pak špatně napsaný test prvek nenajde a nebo najde špatný prvek. Je nutno prvky UI identifikovat spíš než podle umístění (ať fyzického nebo logického) identifikovat podle nějakého logického jména. Tj. ve swingu musíme komponentám dávat jména a v HTML musíme tagům, které pro nás symbolizují komponenty, dávat speciální hodnoty atributům (id nebo class, ale i jiné), tak abychom je v kódu stránky dokázali jednoduše najít.

Pak i když s komponentami trochu hneme, tak nám to nevadí, protože podle tohoto logického názvu je vždy spolehlivě v okně nebo stránce najdeme.

Takže jako musíme komponentu napsat tak, abychom ji byli schopni otestovat, musíme i UI napsat, tak abychom jej otestovali. Rozhodně si tím ušetříme spoustu času a kolikrát si testování de facto umožníme.

14. listopadu 2008

JSF vs. Tapestry - tentokrát AJAX

Zase trochu přileju olej do ohně, tentokrát se podíváme na jednoduchý AJAX příklad. Opět začneme na blogu Jima Driscolla, který napsal A simple Ajax JSF 2.0 example. Při pohledu na tento příklad se opět nemohu ubránit dojmu, že vývoj stránek je v JSF opravdu děs, no posuďte sami (pro jednoduchost ukazuji pouze to co je zajímavé a ne celou stránku):

<h:body>
<h:form id="form1" prependId="false">
<h:outputScript name="ajax.js" library="javax.faces" target="head"/>
<h:outputText id="out1" value="#{count.count}"/>
<br/>
<!-- Increment the counter on the server, and the client -->
<h:commandButton id="button1" value="Count"
onclick="javax.faces.Ajax.ajaxRequest(this, event, {execute: this.id, render: 'out1'}); return false;"/>
<br/>
<!-- Resets the counter -->
<h:commandButton id="reset" value="reset"
onclick="javax.faces.Ajax.ajaxRequest(this, event, {execute:'reset', render: 'out1'}); return false;"
actionListener="#{count.reset}"/>
</h:form>
</h:body>
A jak to samé uděláme v Tapestry nám ukáže Howard L. Ship na svém blogu v příspěvku Tapestry 5 Ajax Screencast. Šablona bude:
<body>
<t:zone t:id="output">${index}</t:zone>
<p>
<t:actionlink t:id="increment" zone="output">increment</t:actionlink>
</p>
<p>
<t:actionlink t:id="reset" zone="output">reset</t:actionlink>
</p>
</body>
A nyní přistupme k Java kódu, ten je v JSF malinko jednodušší, protože definuje pouze beanu s hodnotou počítadla:
@ManagedBean(name = "count")
@SessionScoped
public class Count {
Integer count = 0;

public Integer getCount() {
return count++;
}

public void reset(ActionEvent ae) {
count = 0;
}
}
A nyní ta "složitější" Java třída, tedy Tapestry verze:
public class Index {
@Property
@Persist
private int index;

@InjectComponent
private Zone output;

Object onActionFromIncrement() {
index++;
return output.getBody();
}

Object onActionFromReset() {
index = 0;
return output.getBody();
}
}
Navíc zde máme definováno co se má měnit po provedení AJAX requestu, toť celá komplikace navrch.
Pro mě je to stále jasné, JSF je špatná volba proto, že je hrozně komplikované a těžko mě někdo bude přesvědčovat o opaku.
PS. Letěl okolo mě moc hezký článek o porovnání Wicket a JSF s názvem A Wicket user tries JSF. Ukázky, které jsou tam uvedeny na mě budí dojem, že Tapestry je kombinací toho dobrého z obou těchto světů: jednoduchou Java část z JSF a jednoduché šablony z Wicket.

13. listopadu 2008

Co to je čitelný kód aneb Literate Programming

Obdivuji lidi co mají tu vlastnost, že dokáží naprosto přesně vyjádřit to co ostatní jenom tuší (řada ani to ne). Teď jsem zase narazil na jednoho takového člověka, kterým je Donald E. Knuth, jenž mě dostal svým spiskem o Literate Programming. Nosnou myšlenkou, která mne zaujala je:

Nesnažme se svým programem počítači sdělit co má dělat. Snažme se programem vysvětlit druhým programátorům, co chceme aby počítač dělal.

To je přeci ono. Nepíšeme program jenom proto, aby dělal co má dělat, ale také proto, aby ho dokázal někdo udržovat (to je ten člověk, kterému vysvětluje, co chceme aby počítač dělal).
Již dlouho jsem náš vývojový proces přizpůsoboval této myšlence, možná jsem ji měl někde zakopanou v podvědomí, ale nedokázal jsem ji tak krásně vyjádřit.

3. listopadu 2008

JSF vs. Tapestry - jak jednoduché je dělání komponent

Opět jsem narazil na velmi zajímavý blog, který porovnává složitost vytváření komponent v JSF 2.0 a Tapestry 5 ("Simple" JSF 2.0 Component vs. Tapetry).
Samotného mě takové porovnání již dlouho zajímalo, protože jsem se o JSF přestal zajímat někdy okolo verze 1.0, přišlo mi zkrátka moc složité a komplikované. Navíc mělo veliké problémy na úrovni integrace s JSP (to už je snad minulost). Takže pokud se někdo nechce koukat na originál, pak vězte, že napsat komponentu v JSF, která vypíše text na žlutém pozadí je realizováno následující komponentou:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:composite="http://java.sun.com/jsf/composite">
<head>
<title>This will not be present in rendered output</title>
</head>
<body>

<composite:interface name="yellowOut"
displayName="Very Basic Output Component"
preferred="true"
expert="false"
shortDescription="A basic example">
<composite:attribute name="value" required="false"/>
</composite:interface>

<composite:implementation>
<h:outputText value="#{compositeComponent.attrs.value}" style="background-color: yellow"/>
</composite:implementation>
</body>
</html>
Uf. To je skoro jako těžká dřina. V Tapestry stačí velmi krátká třída:
public class Out {
@Property
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String value;
}
A ještě kratší šablona:
<span style="background-color: yellow">${value}</span>
Takže já mám zase jasněji v tom, co je lepší používat.

27. října 2008

jOpenSpace 2008 - Java vs. dynamické jazyky - více návratových hodnot v Javě (aktualizováno)

Opravil jsem špatně uvedenou ukázku Tuple3.

V záznamu z jOpenSpace na téma Java vs. dynamické jazyky jsem zaznamenal postesknutí: jediné co mi v Javě chybí je možnost, aby metoda měla více návratových hodnot. Ovšem je nutné si přiznat, že to je možné již nyní. Správný název pro objekt, který je de facto kolekcí s tou vlastností, že každý prvek je jiného typu.

Simulovat tuto funkcionalitu pomocí List<Object>, ale to není cesta správným směrem. Dále jsem našel knihovnu javatuple, ta se mi nelíbila, protože místo universálního slova tuple se třídy jmenují Tuple, Triple, ... Nakonec jsme si implementaci napsali sami, a nelitujeme.

Takže třída Tuple2 vypydá:

public class Tuple2<A, B> implements Serializable {
   protected A v1;
   protected B v2;

   private static final long serialVersionUID = -4987109478796050933L;

   public Tuple2(A v1, B v2) {
      super();
      setV1(v1);
      setV2(v2);
   }

   public A getV1() {
      return v1;
   }

   public void setV1(A v1) {
      this.v1 = v1;
   }

   public B getV2() {
      return v2;
   }

   public void setV2(B v2) {
      this.v2 = v2;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == objreturn true;
      if ((obj == null|| !(obj instanceof Tuple2)) return false;
      Tuple2<?, ?> other = (Tuple2<?, ?>obj;
      return ObjectUtils.equals(getV1(), other.getV1()) && ObjectUtils.equals(getV2(), other.getV2());
   }

   @Override
   public int hashCode() {
      int hashCode = 0;
      if (getV1() != nullhashCode += getV1().hashCode();
      hashCode *= 31;
      if (getV2() != nullhashCode += getV2().hashCode();
      return hashCode;
   }

}
Dále následuje Tuple3:

public class Tuple3<A, B, C> extends Tuple2<A, B> {
   protected C v3;

   private static final long serialVersionUID = -4987109478796050933L;

   public Tuple3(A v1, B v2, C v3) {
      super(v1, v2);
      setV3(v3);
   }

   public C getV3() {
      return v3;
   }

   public void setV3(C v3) {
      this.v3 = v3;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == objreturn true;
      if ((obj == null|| !(obj instanceof Tuple3)) return false;
      Tuple3<?, ?, ?> other = (Tuple3<?, ?, ?>obj;
      return super.equals(obj&& ObjectUtils.equals(getV3(), other.getV3());
   }

   @Override
   public int hashCode() {
      return super.hashCode() 31 ((getV3() == null: getV3().hashCode());
   }

}
Kód pro Tuple4 je již jednoduše vytvořitelný. Zbývá vytvořit implementace až kam potřebujete (my jsme se zastavili na čísle 7). Na závěr jsem vytvořil factory objekt, aby bylo vytváření pohodlnější:

public class Tuple {

   public static <A, B> Tuple2<A, B> newTuple(A a, B b) {
      return new Tuple2<A, B>(a, b);
   }

   public static <A, B, C> Tuple3<A, B, C> newTuple(A a, B b, C c) {
      return new Tuple3<A, B, C>(a, b, c);
   }

   ...

}


Když na tuto implementaci koukám, není mi jasné proč standardní knihovna neobsahuje něco podobného. I bez podpory přímo v jazyce je to řešení použitelné.

Google Developer Day 2008

V pátek 24. října jsem se zúčastnil akce pořádané společností Google s názvem Google Developer Day v Hotelu Clarion ve Vysočanech. Protože mi to klasicky trvá déle než něco napíšu, pak vás mohu odkázat na Postřehy Martina Hassmana a Pavla Cvrčka, kteří byli rychlejší. Také jsem k celé akci přistupoval s despektem a vzhledem k naléhavosti úkolů z práce jsem se málem nezúčastnil. Ale nakonec musím říci, že mé pocity jsou podstatně pozitivnější než např. z poslední návštevy Sun Tech Days.

Úvodní key note se nesla v duchu toho, že pokud bude žít web bude žít i Google. A dále uvedla do kontextu všechna témata, kterých se celý den měl týkat, tj. Chrome, AppEngine, GWT, Apps (Search, Maps, Data API, ...), OpenSocial a Android. Pak již paralelně probíhaly jednotlivé přednášky ve 4 sálech, v pátem se konaly workshopy a v šestém byla relax zóna. Můj vkus byl malinko jiný než ostatních, tak alespoň přispěji k zacelení mezer v popisu přednášek.

Jako první jsem zvolil úvod do AppEnginu - Dive into Google App Engine (zvažoval jsem JavaScriptový engine V8, ale nakonec jsem se rozhodl pro AppEngine, který spíš využiju). Přednáška byla nakonec tím nejzajímavějším co jsem viděl. Vždy mě trápilo, když bych chtěl psát nějakou aplikaci pro web, kde ji pustím. AppEngine je odpovědí na tyto starosti. Programuje se v něm velmi jednoduše, Python není složitý jazyk, navíc se chystá další jazyk (pokličku se pozvednout nepodařilo, takže není jasné o jaký jazyk se jedná). Kdo píšete aplikace pro web, hledáte hosting a nechcete psát v PHP, mrkněte na něj.

Následovala přednáška o výkonu aplikací napsaných v GWT potažmo všech webových aplikací - Measure in millseconds: Performance tips for GWT (and AJAX in general). GWT nepoužívám takže jsem si jej trochu přiblížil (v podstatě ještě z doby programování v C++ mám odpor k jakémukoliv generovanému kódu a proto jde i nějak GWT mimo mě). Ovšem mile mě překvapilo, jak je to sofistikovaný systém. Co se dalších tipů týče, nic nového jsem se nedozvěděl, snažit se mít co nejméně CSS a JavaScript souborů, mít je co nejmenší a používat CSS Sprite, to jsou dnes již design pattern webového vývojáře.

Pak jsem si řekl, že to risknu a dozvím se něco o social networks. Zavítal jsem na přednášku Best practice for OpenSocial development. Pro mě nejslabší zážitek. Měl jsem pocit, že jsem buď moc starej a nebo z jiné planety, protože jsem nějak nechápal, kdo používá takové věci, zkrátka nejsem nějak in.

Zasklil jsem i Android (o tom se dá načíst ledacost) a zavítal jsem na jedinou českou přednášku Large-scale computing, Google-style: MapReduce, BigTable, Hadoop, HDFS and others přednášenou Peter Kukolem. Na MapReduce se moc nedostalo. Ale bylo to hodně zajímavé, protože se řešilo co to znamená computing v rozměrech Googlu, co vše se stává problémem při počítání v takovém měřítku.

Na závěr jsem shlédl Integrating 'Google' into your applications: Google Data APIs & AJAX APIs, týkající se popisu rozhraní k aplikacím Googlu. Zde jsem se dozvěděl o různých rozhraních ke Google Search (JavaScriptové či REST) či o Google Data API, které se používá pro přístup (čtení i zápis) k datům v kalendáři či Google Apps.

Zbaběle jsem utekl před večírkem a pelášil domů za rodinkou. Dojmy pozitivní, jsem moc rád že jsem se mohl zúčastnit, příště rád půjdu zas. PS. Moc se mi líbil přístup k lidem s notebookem, všude halda prodlužovaček a přístup na net, prostě super. Já dávám jedničku s hvězdičkou.

jOpenSpace 2008 - Spring - otevřenost novinkám

Už jsem se bál, že zbytek záznamů z nultého ročníku jOpenSpace neexistují a hned jsem dostal odpověď v podobě dalších pěti záznamů. Šestým v pořadí je záznam od Dagiho Spring adoption in large enterprise project. Spring používáme a převážně jako IoC container, tak mě toto téma zajímalo. Bohužel kvalita zvuku je hodně špatná, takže jsem spíš neslyšel než slyšel.

Přesto jsem zaslechl jednu poznámku, která mě vybudila zamyslet se na téma: Kde se v lidech bere touha poznávat a používat nové vs. držet se v zajetých kolejích? Řadil bych se spíš k těm zvídavým, které nové věci zajímají a přemýšlejí o jejich aplikaci.

Je to dáno tím, že mě programování zajímá? Že to je i můj koníček. Nebo je to tím, že chci něčeho ve své profesi dosáhnout a proto se snažím? Nebo je to prostě tím, že věci většinou dělám pořádně a nesnažím se něco odfláknout, jenom proto abych už to měl za sebou? Asi je nutná kombinace všech zmíněných důvodů, aby programátor měl chuť se sebevzdělávat a tím byl otevřený novým věcem.

Vždyť všechny lidské činnosti podléhají zubu času, stále se hledají lepší a dokonalejší řešení čehokoliv, jenom v oblasti IT je to všechno trochu markantnější a rychlejší. Ovšem pozor, i s prosazováním nových věcí to není tak jednoduché. Je nutné se na ně vždy podívat i skepticky, protože hrozí 2 věci. První je over-engineering projektu, kdy na řešení problému používáme příliš složité technologie. A druhým problémem je vklouznutí do slepé uličky, protože ne vše co se v době svého vzniku jeví jako dobré se dobrým ukáže i po čase používání.

Ve svém důsledku se obávám, že i ty skeptiky, kteří neradi posouvají své znalosti někam dál, potřebujeme. Není přeci nic podnětnějšího než přesvědčování takového člověka, protože je nutné vymýšlet argumenty a při této činnosti se kolikrát ukáže, že jsme měli na očích růžové brýle.

Takže závěrem: doufám, že budeme mít vždy šťastnou ruku ve volbě novinek a že se budu potkávat spíš s těmi nadšenci pro nové věci, které budeme moci probírat a řešit, zda jsou užitečné.

21. října 2008

jOpenSpace 2008 - Metodiky vývoje - jak děláme review kódu

Dneska vám předkládám poslední reakci na první dávku audií z jOpenSpace, po ORM a dokumentaci mě oslovila diskuse na téma metodiky vývoje. Poslední 2 zaznamenaná témata mě k nějakým poznámkám nevyburcovala.

Co se metodiky vývoje v podstatě mě velmi mile překvapilo, že se již naplno prosazují iterativní a agilní způsoby vývoje, které začínají odsouvat nevhodný vodopád. To je velmi potěšující. Je až nepochopitelně překvapující, že se vodopád udržel tak dlouho (mimo jiné podle knihy Craiga Larmana Agile and Iterative Development: A Manager's Guide je zjištění jeho nefunkčnosti hodně staré).

Poslední věc z diskuse je taky všude stejná. Zapojit zákazníka do vývoje je velmi težké, ale pokud se to podaří, je to super věc. My se především staráme o jednu už né-malou aplikaci, kterou poskytujeme jako službu. Je-li zákazník interní (vymyslíme si nějakou funkcionalitu, či vyvíjíme něco dovnitř) pak je to super, je-li zákazník externí, pak je odezva většinou pomalá.

Co ovšem vzbudilo mou chuť napsat tento příspěvek, je poměrně složitý způsob reviewováví kódu, které bylo nastíněno. Protože s naším systémem jsem poměrně hodně spokojen a mám pocit, že je na úrovni, rád se s ním s vámi podělím. Review jsem od začátku zamýšlel tak, aby každý kód, který vytvoříme byl reviewován. Z počátku jsme kontrolovali příchozí změny z CVSka. Pak nás začlo být v teamu víc než 2 a tento postup přestal fungovat.

Zhruba v tu dobu jsme nasadili systém JIRA pro evidenci požadavků. Tím se nám nabídla možnost evidovat jakoukoliv práci na projektu jako požadavek, který definuje, kdo jej bude implementovat a zároveň kdo jej bude reviewovat. Požadavek nemůže být zavřen, pokud nebylo provedeno review. Jednoznačnou výhodou je přehled toho, co se na projektu děje. Dále review provádíme průběžně a nikoliv až na konci iterace (přecijenom dělání review není moc populární a zajímavé), navíc je review skutečně provedeno na každý změněný řádek a to považuji za podstatné (víc očí víc vidí a rozumí-li kódu dva mozky, pak jim pravděpodobně bude rozumět i třetí).

Jako vývojový nástroj používáme Eclipse a proto jsem hledal podporu review kódu integrovatelnou do Eclipse. Jediné co jsem našel byl Jupiter (koukám, že se na něm usilovně pracuje, tak třeba se zlepší). Dlouho jsme jej používali a zjistili jsme, že má řadu nevýhod a proto jsem hledal náhradu. Koukal jsem na Crucible, ale nelíbilo se mi, že by evidence review byla mimo již existující infrastrukturu (podobně jako v případě Jupiteru).

Jako zatím top volba se ukazuje integrovat systém JIRA s naším subversion serverem (pomocí subversion pluginu) tak, aby u každého požadavku zobrazoval change sety, které se jej týkají (k tomu stačí, aby komentář commitu do subversion obsahoval kód požadavku). Následně jsme potřebovali nástroj na zobrazení obsahu subversion a volba padla na Fisheye, protože je sofistikovanější než ViewVC.

A jak samotné review probíhá? Je-li požadavek vyřešen, pak je nutno provést review. Podívám se na požadavek a vidím jaké soubory, byly v souvislosti s jeho řešením commitovány. Přímo ze systému JIRA je možno se prokliknout do Fisheye, kde potřebuji další klik na zobrazení změn souboru s požadavkem souvisejících. Je-li vše v pořádku, pak stačí požadavek označit jako reviewovaný a pak už jej může vedoucí projektu zavřít.

Není-li vše v pořádku, pak přijde na řadu diskuse. Tu nijak nedokomuntujeme a je věcí programátorů, jak ji zrealizují. Pokud se ukáže, že je nutné provést změnu kódu (překvapivě se to děje docela často), pak je v systému JIRA vytvořen další požadavek na změnu (nepřehledný kód, nějaká chyba v kódu, chybějící test atd.). Tento požadavek je normálně řešen a je i reviewován jako každý jiný. Commit do subversion obsahuje kódy obou požadavků, aby byl v systému JIRA spojen s oběma (jak s původním, tak s review).

A jaký má systém výhody a nevýhody? Řadu už jsem jich zmínil, ovšem další výhoda tkví v přesné evidenci toho co se děje, v jakém stavu je který požadavek a co se v souvislosti s jeho plněním měnilo a jak. To je neocenitelné. A nevýhody? Pokud je požadavek hodně rozsáhlý, pak je složitější se v souborech vyznat. Je-li to umocněno více change sety (tj. více commity), je to skutečně náročné.

A uplným závěrem motivační větu: Review kódu skutečně zvyšuje jeho kvalitu a napomáhá dřívějšímu odhalení chyb. Navíc se programátoři učí číst kód druhých, orientovat se v něm, komunikovat o něm a lépe poznávají systém, který programují.

14. října 2008

Spring bean z Java enumu

Dneska jsem potřeboval vytvořit ve Spring IoC Java enum, ale jak na to. Než jsem začal vytvářet nějakou factory, řekl jsem si, že to už musí být vyřešené. Google pomohl a našel jsem blog post Creating a Spring Bean from a Java 5 Enum.

Ve stručnosti se věc dá shrnout do dvou ukázek, první jest pro Spring 1.2.2 a menší:

<bean id="latte" class="cz.xxx.PersonType" factory-method="valueOf">
<constructor-arg>
<value>ADULT</value>
</constructor-arg>
</bean>
Kde ADULT je jméno konkrétního enumu. Domnívám se (nezkoušel jsem), že tuto variantu je nutné použít i ve Springu 1.2.2 a vyšším, pokud se odkazujete na enum v okamžiku, kdy není jasné, že výsledkem má být enum (např. položky listu, mapy).

Používáte-li Spring 1.2.2 a starší, pak na místě kde má být enum stačí použít:
<bean id="person" class="cz.xxx.Person">
<property name="type" value="STUDENT"/>
</bean>
Jednoduché, ale moc šikovné. Tak to mám rád.

13. října 2008

jOpenSpace 2008 - Dokumentace - nezatracujme FOP

A máme tu pokračování inspirované poslechem audio záznamů z jOpenSpace konference. Již jsem psal o ORM a nyní mé poznámky k tématu Dokumentace. Toto téma mě opravdu hodně zajímalo, protože jsem měl dojem, že na našem projektu dokumentace moc nevzniká a hrozně mě zajímalo, jak to dělají druzí.

V podstatě vývojářskou dokumentaci neděláme žádnou, takže pro nováčka může být dost obtížné se v kódu zorientovat. Proč to tak je? No v podstatě se snažíme psát přehledný a jasný kód, což je pohlídané především systémem review, který používáme (o něm více v příštím příspěvku). Navíc je to vše umocněno skutečností, že mé schopnosti orientovat se v kódu jsou nadstandardní a protože podle sebe soudím tebe, myslím si, že to dovedou všichni. Ve výsledku se ukazuje, že to chvilku trvá, ale ve výsledku je struktura aplikace poměrně dobře pochopitelná. Hlavním problémem stejně zůstává skutečnost co aplikace dělá a proč, a o tom bych dokumentaci psal hodně nerad, protože by to bylo na hrozně dlouho.

Byl jsem potěšen, jak i v tomto ohledu je tvorba naší dokumentace v souladu s okolím. Především pro uživatelskou dokumentaci používáme DocBook, který v poslední době editujeme pomocí XMLMindu. A nyní se začínáme malinko odlišovat. Obecně se hovoří o různých způsobech převodu DocBooku do výstupního formátu. Zde jsme šli standardní cestou a tou je XSLT transformace, kterou získáváme jak manuál v HTML tak v PDF (přes FOP). Protože jsme si vybrali jenom podmnožinu DocBooku, kterou podporujeme, máme vlastní šablony, které nejsou komplikované a vše funguje ke 100% spokojenosti. Konfigurace fontů, která byla zmiňovaná jako komplikovaná, zas tak složitá není (v porovnání např. s iTextem je srovnatelně složitá).

Samozřejmě FOP má své mouchy a nedostatky, ale současné verze se od 0.20.5 liší a dosahují uspokojivých výsledků. Navíc se FOP docela vyvíjí a každá nová verze je lepší než ta předchozí.

Jako podpora nanáviděných formátu od nejmenované firmy, bylo zmíněno, že uživatelé stejně vyžadují Wordový dokument, který umějí zpracovat a proto nejde DocBook použít. To není pravda, protože převod DocBooku do RTF není problém a pak pomocí revizí zanést změny zpět do DocBooku také není složité.

Z diskuse je zřejmé, že s dokumentací se bojuje všude a najít vyvážení mezi dost a né příliš záleží projekt od projektu. Ale obecně platí, čím více dokumentace jsme schopní vygenerovat na základě jednoho zdroje (ať už je jím DocBook, kód, UML model atd.) tím lépe pro všechny zúčastněné. Jakmile začneme přepisovat myšlenky z UML, či z kódu do dokumentace je to cesta do pekel, dřív nebo později se dokumentace rozejde s originálem (a když se nerozejde, bude nás to stát velmi vysoké úsilí).

5. října 2008

jOpenSpace 2008 - ORM - Hibernate a klientská aplikace

Konečně jsem se dostal k tomu, abych si poslechl audia z akce jOpenSpace. Pro zájemce bych odkázal především na blog otce Fura.

Konference musela být jisto jistě velmi zajímavá a prospěšná. Moc mě mrzí, že jsem se nezúčastnil, ale mohu si za to především sám, protože jsem zasklil call-for-papers v konference java.cz. Dám si závazek, že napřezrok se to již nebude opakovat.

První záznam je z diskuse o ORM. Nosným tématem je použití Hibernate v klientských aplikacích. Problematické v tomto případě je, že Hibernate session object není thread-safe a Hibernate si hodně zakládá na lazy nahrávání čehokoliv (tj. k nahraným objektům je připojena session a atributy, asociace se dohrávají až v okamžiku, kdy je potřeba).

Klientské aplikace napsané v AWT, Swingu nebo SWT mají jedno velké specifikum oproti aplikacím webovým. Tím specifikem je jednovláknovost těchto knihoven. Tj. kód, který přistupuje k UI tak musí činit z UI vlákna (ve webové aplikaci má každý request své vlákno - skoro vždy). Z tohoto vlákna tedy není vhodné provádět náročné akce, protože dojde k zamrznutí UI. A jak v tomto prostředí řešit přístup k datům (pomocí Hibernate a jeho nesynchronizovaného objektu session)?

Varianty jsou v podstatě tři:

  1. používat session pouze z UI vlákna
  2. používat session pouze z jiného vlákna
  3. používat session jak z UI tak z jiného vlákna
První varianta je špatně, protože provádět dlouho trvající dotazy z UI vlákna zhorší odezvu UI. Druhá varianta je ideální, ale má jedno úskalí. Jak zařídit nahrání všech vlastností a vazeb objektu, které budou v UI potřeba tak, aby již nebylo nutné dotahovat žádná data (tj. jak obejít Hibernate laziness). Třetí varianta spočívá v nahrání dat v jiném vlákně a následném nahrání lazy atributů a vazeb z UI vlákna (dotahují se, až když k nim UI přistoupí a to tak učiní z UI vlákna).

Ještě je nutno zmínit jak to bude se správou session objektů. V prvním případě nám stačí jedna session, protože ji používáme pouze z jednoho vlákna. Pro druhý případ může session potřebovat víc, ale ve své podstatě to záleží na počtu výkonných vláken pro provádění komunikace s DB přes Hibernate. Ve třetím případě určitě potřebujeme pro každou událost (řekněme, že se jedná o obdobu requestu v klientské aplikaci) vlastní session, protože ji použijeme pro nahrání objektů a případné další lazy nahrávání z UI vlákna. Tyto 3 strategie je možné komplikovat dodáním synchronizace a využitím menšího počtu session objektů.

Mě osobně se nejvíce zamlouvá druhá varianta, protože veškerá režie s nahráním dat je mimo UI vlákno. Ale jak nahrát vše co je potřeba? Velmi jednoduše. Stačí, aby model každého UI prvku implementoval speciální rozhraní, které bude vracet ty atributy a vazby, které bude pro své vykreslení potřebovat. Díky tomuto kroku a stromové struktuře UI elementů stačí získat tento seznam pro model root elementu (ten se rekurzivně poptá u svých potomků). Inicializaci lazy atributů a vazeb je možné provést pouhým přistoupením k nim pomocí get metod (nebo pomocí metody initialize).

Bohužel klientskou aplikaci jsem již hodně dlouho nedělal, takže tento návrh je pouze z mé hlavy a né z praktické zkušenosti.

26. září 2008

Jak mě vypekla DB2

Začnu zeširoka. Možnost ukládat XML do databáze v DB2 se mi moc líbí. XQuery je plně integrováno s SQL, je možno tedy dělat dotazy i na XML data z SQL. Navíc jsou plně podporovány indexy, takže vyhledávání může být i rychlé.

Navíc v aplikaci, kterou vyvíjíme je velký tlak na uložení různorodých dat. Vytvářet velké množství tabulek nechci. Ukládat je rozložením do universální tabulky, kde bude více řádků pro jednu entitu (jeden sloupec nese název atributu a druhý jeho hodnotu), taky nechci. Takže jsem si vysnil ukládat je do XML.

10 dní jsem realizoval framework, který mi toto umožní a bude fungovat ruku v ruce s Hibernate. Vše jsem otestoval, vyzkoušel a funguje to super. No a dnes jsem se pustil do realizace v našem produktu. A ejhle, hned jsem narazil na problémy, které mě zastavily.

Není možné mít sloupec typu XML v tabulce, která používá MDC (MultiDimesional Clustering). Velmi špatná zpráva, protože MDC používáme pro zvýšení výkonu přistupu k datům v našich obřích tabulkách. Asi budu muste udělat druhou tabulku, kde budu ukládat pouze XML ... půjde to, ale výkon nebude nic moc ...

A druhá rána, sloupec typu XML nemůže být ve view, které používá INSTEAD OF triggery. Tak to zase používáme pro zápis dat do logovacích tabulek, abychom dokázali trackovat jak se měnila data. To asi budu muset obejít buď logováním přímo z aplikace (pomocí Hibernate a jeho Interceptoru), což se mi nelíbí. Přišel bych o tuto funkcionalitu při přímém přístupu přes SQL. A nebo budu muset udělat trigger přímo na tabulku, což není jednoduché, protože jsem do view často dotahoval data i z jiných tabulek.

Každopádně ... jsou to problémy řešitelné. Ale opět jsem se přesvědčil, že vývoj aplikací není předvídatelná činnost a nedá se naplánovat. Kolikrát si myslíme, že jsme na konci cesty a musíme se zase pěkný kus vracet.

Termín nám straší za dveřmi ... vysvětlete to obchodníkům ...

22. září 2008

Tapestry - jak dělat webové aplikace konfortně

Už je to zase příšerně dlouho co jsem si našel chvíli a navíc jsem měl chuť něco sepsat a protože se mi nahromadilo pár zajímavých čtení o Tapestry, pak je logické, že můj první příspěvek po takové době patří právě Tapetry. Navíc je to pár hodin, co vyšlo Tapestry 5.0.15, které mělo být prvním release candidatem. Bohužel se tak nestalo, kvůli chybičkám objeveným v pozdní stádiu releasu (blíže).

První článek, který vám chci naservírovat, je zajímavý, protože se mu podařilo velmi přehlednou formou shrnout proč je Tapestry zajímavé. Why you should consider Tapestry 5. Bohužel je už malinko starší. Ze stejného blogu pochází i porovnání s Wicket: A glimpse of Wicket 1.4 and Tapestry 5.

Tapestry se vždy hlásilo k následujícím pravidlům: rychlost a škálovatelnost vytvořených aplikací, pohodlný vývoj aplikace bez potřeby speciální podpory v IDE a vysoká produktivita vývojáře. A o produktivitě je Boost Your Productivity Using Apache Tapestry.

Specialitou Tapestry již od verze 4 je vlastní IoC framework. Ve verzi 4 se jednalo o HiveMind, ve verzi 5 jde prostě o Tapestry IoC. Proč má Tapestry vlastní IoC framework, co umí je možné se dočíst ve dvou článcích napsaných přímou autorem Howardem L. Shipem: Tapestry 5 IoC: Binding and Building Services a Tapestry 5 IoC: Introducing Service Configurations.

V neposlední řadě: pozitivní krok je i vznik AppFuse pro Tapestry 5.

21. července 2008

Konečně build systém na úrovni - Gradle

Již hodně dlouho se na mě ze všech stran valí, že Ant je překonaný a že bychom měli používat Maven. Jistě Maven přináší spoustu zajímavých myšlenek, především zavedl jednoutnou strukturu projektů a správu závislostí. Ovšem přinesl i spoustu problémů, jako pevně daný build cycle či buildování multi-projektu.

Na trhu open source projektů se objevuje nový hráč, který si řadu těchto nešvarů bere za své a snaží se je napravit. A o jakém projektu, že píši? O projektu Gradle. Gradle je teprve ve verzi 0.2, ale vyvíjí se mílovými kroky.

A co je to převratné, co mě zaujalo. Build skripty se píší v jazyce Groovy. Má to řadu výhod, skript je programován, je možné používat (zavolat) jakýkoliv kód (díky Groovy, jakýkoliv Javovský kód). Navíc je možné opakující se části volat jako funkce (které se dají vytvářet přímo v build scriptu). Bezvadná integrace s Antem. Kolik z nás má v Antu poměrně složité skripty na generování kde čeho. Jejich převod pod Maven je hotovým peklem. Dále build multi-projektu v maven jde pouze z kořenového projektu, díky čemuž se buildu celý multi-projekt. V Gradle je možné multi-projekt build spustit z libovolného projektu a tím se buildují jenom ty podprojekty, které jsou potřeba.

Konvence ohledně build cycle jsou v Gradle definovány pomocí pluginů. Tj. pokud použiji plugin java, pak je nadefinován konkrétní build cycle. Tento může být dle potřeby modifikován, buď jiným pluginem (např. plugin groovy) či samotným build skriptem. To znamená konec dvojí pouštění testů, aby mohl vzniknout Cobertura code coverage.

A co zatím chybí. Je toho stále dost, není nativní podpora pro TestNG, Coberturu. Neexistují integrace s IDE.

Zatím jsem lákání Mavenu odolal a doufám, že Gradle dospěje a pomůže mi vyřešit problémy, které s Antem máme. Hrozně nerad bych naše skripty převáděl a ladil v Mavenu.

9. června 2008

On se ještě používá jUnit? Vždyť máme TestNG.

Konečně jsem si poslechl záznam přednášky Jana Novotného Automatické testování v praxi. Jen více takových ...

Ale proč píšu tento příspěvek? Stále mě překvapuje jak velké množství lidí neustále používá jUnit, který mi přijde v porovnání s TestNG jak chudý příbuzný. Proto jsem se rozhodl nastínit 2 hlavní výhody TestNG, alespoň z mého pohledu.

Přecházel jsem na TestNG v době, kdy po jUnit4 nebylo ani vidu ani slechu, takže jsem měl rozhodování o hodně jednodušší. Ale i po uvolnění jUnit4 je TestNG lepší. Ovšem jako jUnit4 vyžaduje Javu 1.5, takže pro vás co běžíte na Javě 1.4 a méně, pak máte smůlu (ovšem testy můžete překládat jinou verzí Javy než produkční kód).

Na úvod porovnání uvedu: jako vývojové nástroje používám Eclipse, builduji Antem nebo Mavenem a necítím se být nijak limitován užíváním TestNG oproti jUnitu.

Nyní k výhodám. Hlavní skutečnost, která mě hnala za změnou jUnitu za něco jiného je skutečnost, kterou se sice podařilo vyřešit, ale neskutečmě se mi nelíbila. Jde o to, že každý test nejenom dostává vlastní novou instanci TestCaseu, ale tato instance je zároveň použita jako objekt nesoucí informaci o výsledku testu (proběhl / neproběhl). Proč mi to vadí? Protože pokud máte hodně testů a u hodně z nich si naplníte instanční proměnné nějakými instancemi, pak vám běh testů sežere hodně paměti (protože se instance TestCaseů neuvolní pro garbage collection), pokud nespadnou na nedostatek paměti. Takže buď musíte ručně nastavovat hodnotu null do všech instančních proměnných (pracné a náročné na nezapomenutí) a nebo mít připraveného předka, který bude mít tearDown s funkcí nastavování hodnoty null instančním proměnným.

Druhou obrovskou výhodou, kterou jsem dokázal ocenit až po chvíli užívání testNG jsou data-providery. jUnit4 nabízí něco podobného v podobě parametrizovaných testů, ovšem to co nabízí TestNG se to podobá hodně vzdáleně. Když se podíváme na příklad z článku o jUnit4 na devx.com:

@RunWith(Parameterized.class)
public class SquareTest {

private static Calculator calculator = new Calculator();
private int param;
private int result;

@Parameters
public static Collection data() {
return Arrays.asList(new Object[][]{ {0, 0}, {1, 1}, {2, 4}, {4, 16} });
}

public SquareTest(int param, int result) {
this.param = param;
this.result = result;
}

@Test
public void square() {
calculator.square(param);
assertEquals(result, calculator.getResult());
}

}
Z příkladu je zřejmé, že jUnit parametrizuje na úrovní třídy, protože parametry se ze statické metody předávají do konstruktoru třídy. Naproti tomu TestNG:
public class SquareTest {

private Calculator calculator = new Calculator();

@DataParameter(name = "square")
protected Object[][] data() {
return new Object[][]{ {0, 0}, {1, 1}, {2, 4}, {4, 16} };
}

@Test(dataProvider = "square")
public void square(int param, int result) {
calculator.square(param);
assertEquals(calculator.getResult(), result);
}

}
Data providerů můžu mít v TestNG víc, dokonce může data provider být z jiné třídy, než test, který jej využívá. Jediné, co si mi nelíbilo, je přehození parametrů metod assert, tj. první je actual a druhý expected. Naštěstí existuje třída AssertJUnit, která zachovává zvyklost z jUnitu.

Tyto dvě skutečnosti jsou pro mě tak silnými argumety, že jsem přešel a nelituji. Navíc použití data providerů je tak jednoduché, že dnes je používám možná více než je zdrávo, ale když jsou tak elegantní.

25. května 2008

Test prošel. To je špatně!

Test Driven Development má jednu obrovskou výhodu. Tj. napsat test na neexistující funkcionalitu, pustit jej a ... ano správně ověřit, že test neprošel. Co je to za výhodu?

Přiznám se, že TDD stále není můj šálek kávy. Jestli jsem moc starej a nebo jsem ještě nevyspěl, nevím. Ale stále píšu kód a ten pak testuju a ne obráceně. Stále je moje myšlení tam, že vymýšlím jak věc udělat, když ji tvořím a ne, když vymýšlím test.

No a tady je zakopanej pes, protože pokud chci být korektní, musím manuálně a naprosto proti směru vývoje věcí, nakonec kus kódu pozměnit a zjistit, zda se nestane to co inzeruju v nadpise.

Pokud totiž tento krok neudělám, pak se může stát co se mi už nejednou stalo a to, že testy prošli, ale ne proto, že jsem měl dobře napsanej kód, ale protože test netestoval to co měl.

Stále se přesvědčuji, že Extreme Programming je domyšlené do posledního puntíku a je jenom otázkou času, než to zjistím.

15. května 2008

Na unit testy si vždy čas udělám ...

Přečetl jsem si příspěvek Máte čas na unit testy? od Petra Jůzy a po dlouhé době, mě nějaký text přiměl k reakci (Kde je dagi se svými kontroverzními tematy).

Přiznám se, že s testováním jsem začínal nějakým 8 let zpátky za pomocí jUnit knihovny a měl jsem dobrý pocit. Spíš mě to ale zdržovalo. Postupem času jsem se naučil (alespoň si to myslím) testy psát, začal jsem používat Coberturu a přešel jsem na TestNG.

Nedokážu si představit, že bych neměl unit testy. Proč? Jak píšu kód, píšu testy, kterými ověřím, že to celé funguje ještě předtím, než začnu integrovat komponenty dohromady. Jak to dělají ti, co testy nepíšou netuším. Pokud si vše otestuju, pak v návazných objektech používám mock implementaci téhož (díky EasyMock knihovně) a testuju dál. Nejednou jsem kód měnil, abych ho dokázal otestovat a nejednou jsem se setkal s tím, že se mi taková změna v budoucnu vyplatila.

Psát testy stojí čas, ale i když testy nepíšete, nějak musíte testovat a to také stojí čas. Pokud dojde na nějaké úpravy v budoucnu, pak jsou testy k nezaplacení, protože vzpomenout si, jak jsem to vlastně před půl rokem testoval, to už chce sakra dobrou paměť. Při opravě chyb je to podobné, testy opět pomůžou.

Psát testy až po odladění aplikace je zvěrstvo a plýtvání časem. Má to význam pouze pokud chceme opravit chybu nebo udělat změnu. Pak se může vyplatit napsat na ni testy a teprve poté se pustit do změn.

Nepoužívám TDD a tudíž testy píšu až po napsání výkonného kódu. Nějak na tuto myšlenku nejsem ještě připraven.

A co my testy přinášejí především? Jistotu ...

18. února 2008

Jak nás vypek DateFormat.parse

Tak jsme zase objevili jednu, pro mě překvapivou, skutečnost. Ale vezmu to popořadě. Chceme parsovat datumy s časem reprezentované stringem. Používáme Javu, takže jednoduchý úkol pro DateFormat:


DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date datum = format.parse(retez);

Tento postup má pro mě nelogickou nevýhodu. Tj. pokud si například někdo zplete pořadí měsíce a dne v měsící (u tohoto formátu to není moc pravděpodobné, ale jsou jiné, kde to jde velmi jednoduše), stejně nám to datum vytvoří. Např. parserování textu 2008-24-04 1:30:43 neznamá chybu, ale datum 2009-12-04 1:30:43.
Absolutně tuto vlastnost nechápu, ale třeba se někomu hodí. Proč je ovšem implicitní, to nepochopím nikdy. Naštěstí se dá jednoduše vypnout:

DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setLenient(false);
Date datum = format.parse(retez);

Takže tentokrát už dostaneme, pro mě očekávanou, ParseException.
A teď se pomalu blížíme k dnešnímu překvapení. Co se stane, pokud na vstupu bude řetěz 2008-04-24 1:30:43 PM? Možnosti jsou tři: ParseException, datum 2008-04-24 13:30:43 nebo datum 2008-04-24 1:30:43? Osobně jsem předpokládal možnost první, přežil bych možnost druhou, ale pravdou je možnost třetí. DateFormat si i v ne-lenient módu odignoruje část vstupního řetězce. To jsem opravdu nečekal a dost mě to zarazilo. Takže pokud někdo chce skutečně správnou funknci parserování data z řetězce, musí použít:

DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setLenient(false);
ParsePosition p = new ParsePosition(0);
Date datum = format.parse(retez, p);
if (p.getIndex() < retez.length() - 1) {
throw new ParseException(...);
}

Pozor, v případě použití ParsePosition metoda parse nevyhazuje výjimku, musíte si chybu ošetřit sami.
Tak a máme konečně, dle mého názoru, správné parserování řetězce na text. Kód je o poznání složitější než ten, se kterým jsme začínali. Škoda, zřejmě chceme to, co není normální pro ostatní.

PS. Díky Luboši ...

1. února 2008

Nová Java: Jak z toho ven ...

Už je to nějaký pátek, co jsem se zabýval vlastnostmi, které bych rád viděl v Javě 7. Něco málo se na mém názoru změnilo: jsem ještě radikálnějsí. Proč? Jsem přesvědčen, že není možné rozšířit Javu tak, aby byla zpětně kompatibilní a zároveň nabízela prvjky, které by moderní jazyk měl mít. Sun se snaží udržen nejen zpětně kompatibilní bytecode, ale i zdroják. A to je ten problém.

A jak z toho ven. Současnou Javu bych nechal takovou jakou je. Cestu ven by nám ukázala nová Java, říkejme jí např. JavaNW (New Way). JavaNW by byla překládána do stejného bytecode, ale byla by nekompatibilní na úrovni zdrojového kódu. Co to znamená? Nepřijdeme o nic z existující infrastruktury: JRE, HotSpot, Terracotta, Tomcat, ... všechno funguje. Ale to není ještě konec seznamu, protože všechny knihovny budou také použitelné: standardní knihovny Javy, Hibernate, Tapestry, FOP, ... vše budeme moci používat i nadále. Takže vlastně skoro o nic nepřijdeme, ale co vlastně získáme? To co získáme je absolutně závislé na tom, jaká bude JavaNW?

Bude JavouNW Scala? Poslední dobu jsem vyplnil studiem tohoto opěvovaného jazyka. Musím přiznat, že jeho prvky jsou opravdu úchvatné (snad se o nich někdy rozepíšu podrobněji), ale je to jiný jazyk. Syntaxe je jiná, pravda kompaktnější (není tolik upovídaná a všechny vlastnosti jsou zakomponovány tak, že do sebe krásně zapadají). Je možné použít stávající knihovny, ale Scala má také vlastní, a ty je potřeba poznat. Je mi to moc líto, protože se mi Scala opravdu moc líbí, ale nemyslím, že se Scala stane JavouNW (nikdy jsem nevěštil, tak spoléhám na to, že to neumím ...).

Tak co třeba některý ze skriptovacích jazyků: Groovy, JRuby, Jython, ... Ne nemyslím si, že budoucnost je v netypových jazycích, Scala nabízí spoustu (netroufám si napsat všechny) vlastnosti, pro které se mi tyto jazyky zamlouvají, ale je typová. Nemyslím, že jsme schopni a ochotni se připravit o výhody typového jazyka: odhalení řady chyb již při překladu, lépe fugující Code Assist, refaktoring, ... Takže JavaNW musí být něco jiného.

Takže kde vzít JavuNW? Za rozumné považuji více vyjít z Javy, aby se syntaxe nového jazyka Javě více podobala a přechod nebyl tak bolestný. Zakomponovat do něj všechny "potřebné" prvky pořádně: generiky, closures, paralelní zpracování a další. Pak by přechod mohl být pozvolný, poklidný a měli bychom nový "nabušený" jazyk.

21. ledna 2008

Jak vnést trochu pořádku do CSS

Jsem puntičkář, mám rád, když věci mají jasný řád. Ale todle nějak nejde dohromady s našimi CSS soubory. Snažil jsem se malinko upravit layout stránky a vztekal jsem se s tím skoro půl dne. A pak mi srazil vaz Explorer a začal iterativní proces sbližování vzhledu Firefox vs. Explorer.

Nakonec jsem se poohlídl na webu po nějakých radách a typech, jak zanést řád do změti selectorů, atributů a jejich hodnot. Našel jsem pár šikovných rad, které jsou zřejmě lidem pracujícím s CSS delší dobu již známy, protože si je velmi pravděpodobně již vymysleli nebo přečetli. Ale pro Javisty, kteří považují CSS spíš za nutné zlo, snad budou tyto rady prospěšné (i když všechny popisované principy jsou nám již dávno známé).

Modulárnost

První věcí je modulárnost a její striktní dodržování. Přivede nás k opakovanému použití celých CSS souborů. Takže náš styl jsme rozdělili do následujících souborů:
  • Typografie - definuje základní vlastnosti HTML elementů včetně fontů, velikostí atd. Tento soubor je nezávislý na projektu.
  • Formuláře - asi nejsložitější část stylů, spousta hacků, aby formuláře vypadaly stejně ve většině prohlížečů apod.
  • Navigace - velmi často se menu aplikace dá použít napříč více projekty, takže proto jej umístěme do zvláštního souboru.
  • Layout - základní layout stránky je velmi jednoduše oddělitelný od zbytku a navíc je silně projektově závislý.
  • Barvy - definice barev je samostatná, což umožňuje jednoduché přebarvení stránek, vše máte na jednom místě.
Abychom neměli 5 CSS souborů (v souladu se závěry z Yahoo!) pak je vhodné mít ještě šestý soubor, který složí 5 zmíněných v jeden pomocí @import url("file_name.css");.

Sjednocení marginu a paddingu mezi Explorerem a Firefoxem

Následuje zjednošení počtu hacků, které používají jiné definice pro Explorer a Firefox. Celá věc je velmi jednoduchá a ušetří spoustu kódu:

* {
padding:0;
margin:0;
}

h1, h2, h3, h4, h5, h6, p, pre, blockquote, label, ul, ol, dl, fieldset, address {
margin:1em 5%;
}

li, dd {
margin-left:5%;
}

fieldset {
padding: .5em;
}

Speciální CSS soubor pro Explorer

Protože jsme stále potřebovali řadu hacků, speciálně pro Explorer (primární platformou pro vývoj je u nás Firefox), pomocí podmíněného komentáře dotahujeme styl pro Explorer (nakonec jsme použili stejnou hierarchii jako v kapitole o modulárnosi):

<!--[if IE] >
< link rel="stylesheet" href="IE.css" media="screen" />
<![endif]-- >

Závěr

Celé nám to chvíli trvalo, protože ve stylech skutečně panovala anarchie, ale nyní je velmi jednoduché představit nějaké změny, odstartovat nový projekt a podobně. Ukázalo se, že je možné zanést pořádek i tam, kde mi bylo tvrzeno, že to nejde ...

Odkazy

14. ledna 2008

Používám Linux a nelituju ...

Nějak se rozhořelo téma Linuxu na desktopu (dagi či Aleš Dostál), i když na specifickém desktopu a to jest desktopu vývojáře. Ja používám Linux na svém desktopu už skoro 5 let (od února roku 2003) a jsem s ním nad míru spokojen. Od jakživa používám SUSE, nyní openSUSE (altuálně 10.2) ve spojení s KDE (GNOME bylo zkraje hodně velký žrout paměti a už jsem zvyklý na KDE, takže měnit nebudu). Nově jsem si openSUSE nainstaloval i na své nové VAIO a světe div se, vše funguje (jenom původní token iKey 1000 není pod linuxem podporován, takže potřebuju iKey 3000 - to vše pro přístup do firemní sítě).

A proč nechci už Windows ani vidět? Důvody jsou 3: KWrite, terminal a ssh.

KWrite je ten nej editor na cokoliv, který jsem kdy viděl, přepínání kódování, blokové kopírování, podpora XML. Command line v podobě terminálu je naprosto k nezaplacení, nedokážu si představit, že bych pracoval bez ní (už v ní i kopíruju soubory, rozbaluju archivy apod.) a ve Windows jsem zatím nenašel solidní náhradu (ani jsem moc nehledal ...). A ssh je prostě víc než PuTTY, fungují všechny klávesy jak mají (např. ctrl + end).

Největším problémem je asi přenos dokumentů mezi MS Office a OpenOffice, ale zvykl jsem si. Podpora se za těch pět let hodně zlepšila, opravdu hodně moc ... není to na to, abych něco napsaného v MS Office vytiskl a vypadalo to, jako vytištěné z MS Office, ale čitelné je vše (včetně poznámek, tj. není pravda co psal ronnie).

A proč se mi líbí právě SUSE a né třeba Fedora nebo Ubuntu? Je to kvůli YASTu, protože funguje jak v terminálu tak v Xkách a nastavím s ním většinu věcí, které běžně potřebuju ...

Tj. nebojte se linuxu, je to jiný než myšoidní přístup Windows, asi nevypadá tak líbivě jako Windows, ale funguje spolehlivě a bezproblémově.

8. ledna 2008

Nová Java: Chceme ji? - tvrdá realita

Dneska jsem si pročítal nějaké články o Closures v Javě a narazil jsem na článek Closures and Preserving the Feel of Java, který nepřináší nic nového, ale v jeho komentářích jsem našel perličku od Kurta Christensena:

I remember a great presentation by Bjarne Stroustrup back around 1997 at the Computer Literacy bookstore. Someone said that Java looked like a much better, cleaner C++, to which Stroustrup replied that we should ask him about it again in 10 years after everyone was finished adding the features they want. Well, it's 10 years later, and new Java code is starting to look an awful lot like C++.
Tak trochu střílím do vlastních řad, protože jsem pro rozšiřování jazyka, ale nechci jej rozšiřovat za každou cenu, pokud se nějaké, byť prospěšné, rozšíření ukáže jako problématické, či zesložiťující syntaxi, pak jej nechme být ...

6. ledna 2008

Nová Java: Chceme ji? - počtvrté

Myslím, že jsem se dostal do finále, alepoň pro tento okamžik, protože poslední věc, která by jistě zasloužila vylepšení je vytváření naplněných collections. Dneska je nutné vytvořit instanci (Collection nebo Map) a postupně do ní přidávat prvky.

Jistě existují různé "zkratky" přes pole, která můžeme vytvářet pomocí inicialiazátoru. Další pokrok přináší Google Collections Library, ale stále to není ono. A přitom jednoduchou syntaxi již máme vymyšlenou, např. pro Groovy.

Takže proč collection nevytvořit:

Collection<Object> col = [ 1, 2, "33", new Long(10) ];
Je to jistě jednodušší než:
Collection<Object> col = new ArrayList<Object>();
col.add(1);
col.add(2);
col.add("33");
col.add(new Long(10));
Jen pro dolnění, prázdná mapa je: [].
Pokud přejdeme na na mapy, je věc identická. Nejprve klasicky v Javě:
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "1");
map.put(2, "dva");
map.put(3, "3");
A jak by tyto 4 řádky vypadaly, kdyby se vylepšila syntaxe vytváření map:
Map<Integer, String> map = [ 1:"1", 2:"dva", 3:"3" ];
Jenom pro doplnění prázdná mapa se vytvoří [:].

Závěr

Nedokážu odpovědět na otázku, zda takovou Javu chceme? Za sebe mohu říci, že změny, které jsem navrhoval podporuju. Ale nesmí dojít k nejasnostem jako v případě implementace generik. Vše musí zapadnout do již existujícího jazyka a fungovat. Pokud se ukáže nějaký problém, jsem pro, aby se z implementace vycouvalo.
Otázkou samozřejmě je, zda je nutné zachovat zpětnou kompatibilitu. Myslím si, že není problém udělat nekompatibilní JavuX a vní implementovat vše co potřebujeme, ale je to co chceme? Ja myslím, že ne, protože to už by nebyla Java ...

5. ledna 2008

Nová Java: Chceme ji? - potřetí

Původně jsem si myslel, že na tenký led typu closures se pouštět nebudu, protože to je hodně pálivé téma, ale když už se do toho pustil Dagi, chci přidat svůj pohled.

Předně co si pod pojmem closures představuji já: v podstatě zavolatelný kód, takový pointer na funkci. Nespojoval bych to se správou zdrojů (Automatic Resource Management).

Nejprve jsem si prošel všechny návrhy, které se okolo closures v Javě 7 přetřásají (JSR, BGGA, CICE, FCM, C3S). Musím se přiznat, že přestože jsem relativně dost nakloněn novinkám v Javě, tak BGGA návrh mi přijde hodně špatný. Kód je složitý, closures není možné použít všude, kde to dává smysl, a tzv. closures se nechovají jako kus Java kódu (nejde použít break, continue ani dokonce return). Takže pokud otázka stojí: Chceme BGGA návrh jako closures do Javy? říkám jasně a nahlas Ne.

Je jasné, že přidat do Javy closures tak jak je známe např. z Groovy se asi nepovede. Takže potřebujeme nějakou zjednodušenou variantu. A ty vidím dvě. První, která se mi líbí kvůli velmi jednoduché syntaxi a široké nabídce možností, je FCM (First Class Methods). Jsem přesvědčen, že mi pomůže skutečně zjednodušit všechny typy algoritmů, kde si na closures vzpomenu, když je píšu v Javě.

Kdyby existoval argument proč FCM nepoužít, pak se kloním k CICE, které není tak jednoduché jako FCM a není tak moc komplexní, ale přesto nabízí hodně. Bohužel neodstraňuje nutnost existence rozhraní, které bude "closure" implementovat...

Věřím, že se BGGA v Javě 7 nedočkáme ...