Android a G1

Dnes budu psát o věci, která se Javy týká jen okrajově – o telefonu G1 s Androidem. Nafasoval jsem ho ve čtvrtek, trochu jsem si s ním hrál a musím prohlásit, že to je ten pravý telefon pro Java programátory a ajťáky obecně. Nebudu se zde věnovat programování, napsal jsem si jen pár jednoduchých prográmků, takže to moc neumím. Musím jen konstatovat, že to jde velice snadno. Za odpoledne jsem si napsal aplikaci na přeposílání SMSek. Nakonec měla i s uživatelským prostředím asi padesát řádek, nejvíc času jsem samosebou strávil výzkumem.

Problém je, že programovat nebudete potřebovat. Všechno už se dá stáhnout z Android marketu. Potřebujete aplikaci, která vypne podsvícení klávesnice, stáhnete si Dark Keys, potřebujete přeposílat SMS, stáhnete si dgAway. Skoro všechno co mě napadlo, že bych si naprogramoval se dá jednoduše a obvykle zdarma stáhnout. A najdete i pár perel, které by vás ani nenapadly. Třeba dálkové ovládání PC přes LAN (Gmote), kdy G1 může sloužit i jako touchpad. Na pouštění filmů naprosto ideální.
Samozřejmě má i svoje mouchy. Mě zatím nejvíc vadí nemožnost čtení PDF a práce s Office dokumenty. Ne, že bych to potřeboval tak často, ale občas ano. Na oboje jsou nějaké aplikace, ale kvalita zatím není nic moc. Můžete samozřejmě používat Google docs, ale není to ono. Takže na business použití je potřeba ještě chvíli počkat, než platforma dospěje.

Dalším negativem je, že si člověk nemůže být jist, co o něm všechno bude Google shromažďovat za data. Pro paranoiky jako já to může být docela problém. Zatím jsem se spokojil s tím, že jsem vypnul sychronizaci s Google programy a používám nezávislý mail, synchronizátor kontaktů a podobně. Není to stoprocentní, ale trochu mě to upokojilo. Pro méně paranoidní ajťáky, geeky a jinou havěť je ale G1 hračka, s kterou si užijí spoustu zábavy.

Já plácám sochy z hlíny

Slovutný architekt Dagi poodhalil tajemství své čarodějnické dílny a tím mě vyprovokoval k popisu toho, jak dělám sochy já. Nejsem žádný Michelangelo, který tvrdil, že je socha ukryta v kameni a je jen potřeba ji jen osvobodit, odsekat ten balast kolem.

Občas tedy zažiji ten úžasný pocit, kdy do kousky programu do sebe zapadají jako kousky skládačky. Okamžiky, kdy se sám od sebe vyloupne dobrý návrh, který je jednoduchý, elegantní a funkční. Ale to se mi děje jen občas, většinu času si připadám jako když plácám sochy z hlíny.

To si člověk nejdřív musí připravit kostru, aby bylo na co plácat. Jinak se mu ta socha vlastní vahou zbortí. Takže si člověk nejdřív musí rozmyslet, co za sochu vlastně potřebuje. Jestli to bude člověk, kůň nebo sedmihlavá saň. Je dobré si ujasnit kolik nohou, hlav a jiných výběžků to bude mít. V tomto okamžiku rozhodně není nutné se rozhodovat jestli to bude diktátor, spisovatel nebo básnířka. Je ale dobré vědět, že to bude člověk a že třeba bude stát vzpřímeně. Jakmile mám v tomto jasno, stluču si hrubou kostru a můžu začít plácat.

A pak už jen plácám, tady ubírám sem přidávám, často se mi to nedaří tak odhazuji celé velké kusy. V extrémním případě musím hýbat i s kostrou, ale to je pak velký problém. Většinou se snažím držet se kostry a plácat. Občas dokonce někam plácnu velký kus, který tam jako by zázrakem patří, který dá soše úplně jinou dimenzi. Většinu doby je to, ale spíš takové plácání pokus omyl a pomalé přidávání. Začínám tím co mi připadá důležité. U lidí to bývá obličej, u koní tělo a u sedmihlavých saní pozice hlav. Nicméně se to liší socha od sochy. V jednom se s Dagim nelišíme, detaily si obvykle necháváme na poslední chvíli. Důvod je zřejmý. Jakmile máte detaily, hrozně neradi ty kousky předěláváte. Jakmile máte dokonalý nos, hrozně těžko se vám odhodlává dát obličeji úplně jiný výraz. Jakmile máte hotovou ruku, těžko se přesvědčíte k tomu, že by v ní měl vlastně držet samopal a ne palcát. Takže je potřeba plácat a plácat a doufat v to, že jednoho krásného dne se vyloupne socha, která je prostě povedená. U které sice nebudete vědět jak jste se k ní dopracovali, ale i tak se vám bude líbit. No a když štěstí mít nebudete, tak to vždy můžete prohlásit za moderní umění a prodat mnohem dráž než nějakou normální hezkou sochu.

Hibernate: přistupovat pomocí polí nebo vlastností?

Onehdá jsem s kolegou řešil, jestli v Hibernate (JPA) používat přístup pomocí polí (field) nebo vlastností (property). Uvědomuji si, že nejsem ani první ani poslední kdo něco podobného řeší, nicméně mi došlo, že v tom sám nemám moc jasno tak jsem si dal za domácí úkol to nastudovat.

O co jde? Když mapuji entity, můžu si vybrat, jak bude Hibernate k objektům přistupovat. Mohu například napsat takovouto třídu.

@Entity
@Configurable
public class Client  {
	
	@Id @GeneratedValue(strategy=GenerationType.SEQUENCE)
	private Long id;

	@Column(unique=true,nullable=false)
	private String personalNumber;

	...
}

V takovémto případě bude při načítání z databáze Hibernate data zapisovat přímo do polí. To znamená, že například pro ID nemusíme mít vůbec set metodu, Hibernate nebo jiný JPA poskytovatel to tam magicky zapíše.

Nebo mohu zvolit druhou variantu.

@Entity
public class ClientGroup {
	
	private Long id;
	
	private List clients = new ArrayList();
	
	private String name;

	@Id @GeneratedValue(strategy=GenerationType.SEQUENCE)
	public Long getId() {
		return id;
	}

	private void setId(Long id) {
		this.id = id;
	}

	@OneToMany(cascade=CascadeType.ALL)
	public List getClients() {
		return clients;
	}

	
	private void setClients(List clients) {
		this.clients = clients;
	}
	public void addClient(Client client)
	{
		clients.add(client);
	}
	...
}

V tomto případě jsem dal anotace nad get metody a Hibernatu jsem tím dal najevo, že má pro přístup používat vlastnosti (property). Tzn. při plnění instancí z databáze bude volat set metody, při ukládání do databáze bude používat hodnoty z get metod.

Protože tu tvrdošíjně používám českou terminologii, shrnu to do slovníku.
Field access – přístup pomocí polí – anotace nad poli
Property access – přístup pomocí vlastností – anotace nad get metodami

Dobrá zpráva je, že v jednom programu mohu používat oba přístupy. Jednu třídu mohu mapovat tak, druhou onak. Sice bych to moc nedoporučoval, ale teoreticky to jde. U jednotlivých tříd ale oba přístupy míchat nemůžeme. Nemohu si říci, že ID chci mapovat jako field a seznam klientů jako property. Specifikaci už si nepamatuji, ale v praxi to funguje tak, že se typ přístupu určuje podle toho, nad co dám anotaci @Id.

Takže tu máme dva různé přístupy a nabízí se otázka, který je vhodnější. Oba mají svá pro a proti. Já osobně preferuji přístup přes pole. Prostě se smířím s tím, že mi Hibernate magicky mění vnitřnosti objektu. Podle některých to porušuje zapouzdření. Částečně mají tito lidé pravdu, ale tento přístup je podle mě menším ze dvou zel. Radši se smířím s tím, že mi zapouzdření bude narušovat Hibernate, než abych se smířil s tím, že mi ho bude narušovat programátor.

Vezměme si příklad ID. To je obvykle nastavováno Hibernatem. Rozhodně nechci, aby mi ho nastavoval nebo měnil programátor. V případě přístupu přes pole jednoduše nevytvořím set metodu a mám hotovo. V případě přístupu přes vlastnost musím vytvořit set metodu. Může být klidně i private, ale musí tam být. Takže stejně musím nechat Hibernate, aby mi prolomil zapouzdření. Stejně ho musím nechat volat private metodu. Nebo ji mohu nechat public, ale pak se musím modlit, aby mi někdo ID nezměnil. Mě osobně připadá čistší tam ten setter vůbec nedávat.

Podobný problém je i u kolekcí. Obvykle nechci nechat programátora, aby mi kolekci nastavoval přímo (viz. ClientGroup příklad). Ale u přístupu pomocí vlastností stejně musím mít set metodu, i když opět může být private.

Property přístup je podle mě také o trochu náchylnější na chybu. Představme si, že do objektu přidáme metodu getFullName, která jen zřetězí křestní jméno a příjmení. Když máme anotace nad poli, není tu žádný problém, pokud máme anotace nad metodami, tak si bude JPA myslet, že chceme mít v databázi sloupeček FULL_NAME a ošklivě nám vynadá. Budeme to muset vyřešit dobře mířenou anotací @Transient.

Specifickou kapitolou jsou netriviální get a set metody. V set metodách můžu mít validace vstupních hodnot, v get metodách vracet defenzivní kopie. U přístupu přes pole to není problém. Ale pokud používám přístup pomocí vlastností tak se mohou dít ošklivé věci. Validační kód se bude volat při každém načtení z databáze, což může mít na výkonnost dopad jen malý. Horší je to s defenzivními kopiemi. Ty mohou ovlivnit mechanismus detekce změn. Pokud budu například vracet defenzivní kopii kolekce, Hibernate bude přesvědčen, že se mu změnil obsah kolekce a pokaždé danou kolekci z databáze smaže a vloží ji tam znovu. A to i v situaci, že jsme danou instanci vůbec nezměnili! To může mít na výkonnost dopad dost ošklivý.

Teď mi zrovna došlo, v čem je problém. V podstatě obvykle potřebujeme, aby entita měla dvě rozhraní. Jedno pro programátory, druhé pro perzistenci. To je přesně to, co mi zajistí mapování přes pole. Říkám tím, že ORM je taková chytřejší serializace po které chci aby mi uložila stav objektu. U klasické Java serializace si taky nikdo nestěžuje, že narušuje zapozdření tím, že nastavuje pole napřímo. Při přístupu přes vlastnosti na druhou stranu tvrdím, že ORM a programátor jsou si rovni a že by měli používat stejné rozhraní. Někdy to tak být může, ale obvykle tomu tak není.

Předchozí věta by tvořila pěkný závěr článku, naneštěstí ale ještě končit nemůžu. Je jeden konkrétní případ, kdy jsou anotace nad metodami lepší volba. Je to v případě, že načítáme ID u lazy proxy, které ještě není načtené z databáze. Řekněme, že dělám například toto:

clientGroup.getClient(0).getId()

Může se stát, že Hibernate zná jenom ID klientů, kteří patří do dané skupiny, ale ještě nemá načtená jejich data. V tom případe se používá proxy, která zajistí načtení dat, až když jsou potřeba. Když používám přístup pomocí polí, Hibernate musí všechny informace o klientovi načíst, i když mě zajímá jen ID. Neví totiž, že metoda getId() jenom vrací klíč. Neví jestli náhodou v této metodě nečtu třeba jméno. Nemá šanci to poznat. Teoreticky by se mohl podívat do kódu, ale to by už bylo příliš mnoho magie. Na druhou stranu pokud mám nad metodou getId() anotaci @Id, Hibernate ví, že to je ID a může mi ho rovnou vrátit, aniž by musel přistupovat do databáze.

Ale toto je jediný případ, v kterém je přístup přes vlastnosti lepší. Záleží případ od případu, jestli zrovna tuto vlastnost použiji. Dovedu si představit aplikaci, kde budu například ID používat i v UI pro odkazy v tabulce. Dovoluji si ale tvrdit, že i tak by bylo lepší použít nějakou lepší fetch strategii než se prát s anotacemi nad metodami. Jinak to totiž zavání předčasnou optimalizací.

Další čtení:
http://forum.hibernate.org/viewtopic.php?p=2349555&sid=dd846f97d3eb352ed0b8fbe57739801c

http://chstath.blogspot.com/2007/05/field-access-vs-property-access-in-jpa.html

http://shashivelur.com/blog/2009/01/hibernate-direct-field-acess-and-encapsulation/