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.