Category Archives: Uncategorized

Dva druhy kódu

Dnes budu zase psát o takové samozřejmosti, že ani nevím jestli s tím mám někoho obtěžovat. Navíc už jsem to před rokem předváděl na jedné konferenci. Možná ale nepatříte mezi těch deset šťastlivců, kteří mě tam viděli, tak to asi přeci jen napíšu. Začněme mojí oblíbenou ukázkou kódu:

public class PureJdbcBankDao implements Bank {
	public void setBalance(String accountNumber, BigDecimal balance) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = ConnectionFactory.getConnection();
			ps = conn.prepareStatement("UPDATE ACCOUNT SET BALANCE = ? WHERE ACCOUNT_NUMBER = ?");
			ps.setBigDecimal(1, balance);
			ps.setString(2, accountNumber);
			ps.execute();
		} catch (SQLException e) {
			throw new ApplicationException("JDBC failure", e);
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					// what to do here?
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// what to do here?
				}
			}
		}

	}

Je to metoda pro zápis do databáze pomocí čistého JDBC. Toto je nádherná ukázka míchání dvou druhů kódu. Jednomu druhu říkám hezky česky „business kód”. To je kód, který je užitečný pro zákazníka. V našem příkladu po nás někdo chce, abychom změnili hodnotu v databázi. To obvykle děláme pomocí SQL příkazu, který vidím jenom na jednom řádku. Zbytek je „infrastrukturní kód”. Tak říkám kódu, který někdo udělat musí, ale zákazníkovi je v podstatě k ničemu. V našem příkladě to jsou všechny řádky kromě jednoho. Ano opravdu, zákazníkovi je naprosto jedno, že potřebuji připojení do databáze, je mu dokonce jedno, že ho musím po sobě zavřít, on po mě chce abych něco zapsal do databáze. Popravdě řečeno, často po mě nechce ani to, chce jen, aby jeho důležitá data byla dobře uložena.

Ale zpátky k věci. Když to přeformuluji tak mohu říci, že business kód je ten, co dělá něco zajímavého pro zákazníka, infrastrukturní kód je ten, který zajímá jen programátora. Samozřejmě potřebujeme oba druhy, je ale důležité si uvědomit který je který a přistupovat k nim rozdílně. Úplně nejdůležitější je držet oba druhy odděleně. Pokud máte JDBC kód v business vrstvě nebo nedej bože v kontroleru, tak vám nepomůže ani svěcená voda. Pokud ho máte schovaný v DAO vrstvě, tak jste v trochu lepší situaci. Ale i tak je obtížné takový moloch testovat a měnit. Představte si, že bych si vzpomněl, že potřebuji transakce. Musel bych upravit všechny metody v DAO vrstvě. To nezní jako dobrý nápad.
Existují i další argumenty proč infrastrukturní kód nepsat. Nejenže je takový kód nečitelný, on je navíc náchylný na chybu. Když náhodou zapomenu zavřít PreparedStatement nemusí to nějaký čas vadit. Po změně databáze ale můžu začít dostávat veselé chyby a může mi trvat pěkných pár dní než najdu jejich zdroj.

Já jsem obecně přesvědčen, že programátoři, kteří píší kód pro zákazníky, by se měli infrastrukturnímu kódu co nejvíce vyhýbat. Myslím si že je mnohem lepší psát kód takto:

public class JdbcBankDao extends SimpleJdbcDaoSupport implements Bank {

	public void setBalance(String accountNumber, BigDecimal balance)
	{
		getSimpleJdbcTemplate().
			update("UPDATE ACCOUNT SET BALANCE = ? WHERE ACCOUNT_NUMBER = ?", balance, accountNumber);
	}
}

Nejen, že rovnou vidím, co daná metoda dělá, já tam ani nemám moc co zkazit. Téměř všechen infrastrukturní kód zmizel. Samozřejmě že tam stále je, ale napsal ho za mě někdo jiný. V tomto případě autoři Springu. Ano mohl jsem si napsat vlastní framework, ale tím bych si moc práce neušetřil. Navíc bych do něj musel přidat podporu transakcí, podporu testování a podobně. Takže bych víc času strávil vývojem frameworku než něčím, co přináší zákazníkovi užitek.

Příklad s JDBC je samozřejmě trošku extrémní, málokdy se nám stane, že bychom motali JDBC kód s business kódem. Často ale vyvíjíme jiné typy infrastruktury a často nás ani nenapadne, že bychom to dělat neměli. Nebo nás to napadne, ale najdeme si nějakou výmluvu. Ze své praxe pamatuji několik případů, které jsem spáchal já nebo některý z mých kolegů.

  1. Asi nejčastější jsou všelijaké implementace vyrovnávací paměti (cache). Znáte to, máte číselníková nebo jiná málo se měnící data v databázi. Místo toho abyste je četli při každém dotazu tak si je přednačtete do mapy a pak je už jen taháte z paměti. Klasické míchání infrastrukturního a business kódu a také klasický kandidát na vlastní framework popřípadě knihovnu. Přitom stačí vhodně použít cache přes AOP (spring-modules nebo AOP cache).
  2. Načítání konfigurace je také oblíbené. S nástupem Springu už se s tím tak často nesetkáte, ale doby kdy si každý implementoval svoji variantu konfigurační knihovny neminuly zas tak dávno. Občas ještě v business kódu tu a tam zahlédnu načítání properties souboru a vytahování příslušné hodnoty.
  3. Logování je další klasický případ. Zde bych udělal výjimku z pravidla a řekl bych, že míchání logování a business kódu není na škodu, někdy může být i užitečné. Logy mohou pěkně zastupovat komentáře. Když ale říkám že logování samotné škodlivé není, psaní si vlastní knihovny na logování už škodlivé je. Myslím si, že zrovna logovacích knihoven máme v Javě dost.
  4. Skoro vždy se setkáme s vlastními utility třídami. Tedy třídami, které usnadňují věci, které v Javě nejsou zrovna jednoduché. Ať už se jedná o práci s časem a datem, kopírování input streamu do output streamu, načítání obsahu souboru do stringu a podobně. Ano, standardní knihovny jsou v tomto ohledu neohrabané, to ale neznamená, že si to musíme psát sami. Jakarta commons, Joda nebo i Spring nám v tomto ohledu rozhodně dokáží pomoci.
  5. Jednou jsem strávil krásný týden implementací skoro transparentního šifrování dat na úrovni Hibernate. Tzn. v Javě se s daty pracovalo normálně, ale i při ukládání a načítání do databáze se data automagicky šifrovala a dešifrovala. Měl jsem z toho projektu docela radost. Tu mi zkazily dvě věci. Týden po tom, co jsem to dopsal jsem zjistil, že už podobné řešení existuje. Druhou vadou na kráse bylo, že kolegové začali přes Hibernate dávkově zpracovávat desetitísíce záznamů a moje geniální knihovna na to nebyla stavěná a dost celé zpracování zpomalovala.
  6. Jsem si jist, že další příklady z praxe si doplníte sami.

Já jsem přesvědčen, že v dnešní době už člověk sežene knihovnu skoro na všechno. Pokud má to štěstí a knihovna mu umožní zbavit se infrastrukturního kódu, měl by ji použít. Pokud štěstí nemá a musí si opravdu napsat infrastrukturní kód, měl by ho důsledně oddělit od business kódu. Ale jak říkával kolega, každý, kdo se rozhodne napsat si vlastní knihovnu, by měl před tím desetkrát oběhnout barák, aby si to dobře rozmyslel. Ono to totiž není o tom ji jen napsat. Ono je potřeba ji zdokumentovat, otestovat, verzovat, donutit kolegy aby se ji naučili, dávat si pozor jestli máme dobře nadefinované API a spoustu dalších věcí.

Podle mě je jen jeden případ, kdy se vyplatí psát si vlastní knihovnu. A to v případě kdy do ní dávám kód specifický pro daného zákazníka. Například nějaké specifické výpočty, které chci sdílet mezi různými moduly, kód pro volání jeho backendu a podobně. Ale i tak je potřeba počítat s tím, že údržba takové knihovny zabere neuvěřitelné množství času a vaši kolegové z jejího používaní nebudou moc nadšení.

Takže abych to shrnul. Ať už píšete cokoliv, je dobré uvědomit si, který typ kódu to je. Pokud se jedná o business kód, tak je vše v pořádku. Pokud zrovna píšete infrastrukturní kód a není to hlavní náplní vaší práce (zdravím chlapce ze Sunu), zamyslete se nad tím, jestli je to opravdu potřeba. Zamyslete se jestli to už náhodou někdo nevyřešil za vás. Já vím, naučit se novou knihovnu je mnohem menší legrace než si ji napsat. Ale připomíná mi to jedno staré rčení, které říkalo něco v tom smyslu, že “Půl roku v laboratoři vás dokáže uchránit od deseti minut v knihovně.”

Praktický API Design

Dnes budu psát o knize Practical API Design od Jaroslava Tulacha. Pomiňme její kvalitní zpracování, které se jen tak nevidí, zajímavý je obsah.

Na začátku je tam na můj vkus docela dost filozofování, ale možná to ke knize podobného zaměření patří. Zabývá se totiž pohledem na návrh API v Javě z trochu vyššího hlediska. To znamená, že se nebabrá v detailech, jako například správné pojmenování metod a rozdělení balíků. Kouká se na to víc shora. Tzn, jak dělat API tak, aby přežilo alespoň pár verzí. Dočtete se co dělat a co nedělat, na co si dát pozor. Autor se prostě pokusil o nemožné, zaznamenat na papír a předat své dlouholeté zkušenosti z návrhu NetBeans API.

Kromě toho je tam také hodně zajímavých myšlenek, které vás donutí se zamyslet. Třeba tvrzení, že krása kódu je věc sice pěkná, ale v podstatě neužitečná. Zní to jako samozřejmost, ale poprvé jsem to takhle natvrdo napsané uviděl až v této knize.

Nejvíc mě zaujala strana 173, která se zabývá tím, co o metodě řeknou její modifikátory. Tzn. věci jako public, final, abstract a podobně. To je věc, která mi do té doby nedošla. Pokud totiž chceme aby měla metoda jeden jediný účel, připadají v úvahu jedině následující kombinace:

  • public final – Metoda je tu k tomu aby ji někdo volal
  • protected abstract – metoda je to k tomu, aby ji někdo zastínil (naimplementoval)
  • protected final – metoda má být volaná podtřídami

Všechny ostatní kombinace, které obsahují public nebo protected mají víc významů, takže by se jim člověk měl vyhýbat. Například public se dá jak volat tak zastínit, takže není moc jasné, co je její správné použití. Jen pro úplnost upozorňuji, že private a (package) nás u API nezajímá.

A tady s dostáváme k věci, na kterou je třeba u knihy upozornit. Psal ji člověk, který se dlouhá léta zabývá návrhem API pro jiné programátory a to navíc pro Javu na desktopu a to ještě navíc v dynamickém prostředí, kde se moduly za běhu magicky načítají do paměti a zase se z ní vyhazují. Jeho styl myšlení a případy užití jsou tedy o hodně jiné než u mě. Já jsem zvyklý na serverovou Javu, která je zatím dost statická a navíc moji spotřebitelé jsou hlavně koncoví zákazníci. (více viz. v sesterském článku). Nejenže řeším úplně jiné problémy, některé rady jsou pro mě dokonce chybné!

Například stránka 221, kde autor řeší vzájemnou závislost listeneru a sledovaného objektu. Objekt v tomto případě drží odkazy na listenery a když se s ním něco stane, dá jim vědět. Autor tvrdí, že by objekt měl na své listenery odkazovat jen slabou (weak) referencí. Tak mohou být listenery uvolněny z paměti, když už nejsou potřeba, ale objekt samotný žije dál.

V případě NetBeans je to asi užitečná rada. K čemu držet v paměti listener, který sleduje změny v editačním okně, když leží v modulu, na který už se nikdo neodkazuje a tedy ho ani nepotřebuje. Tím, že editační okno drží na listener odkaz, znemožňuje odstranění celého modulu z paměti.

Když se ale na danou radu člověk podívá z mé serverové perspektivy, tak je to naprosto zvrhlé. Mám často listener, který na startu aplikace zaregistruji a pak už mě nezajímá. On dělá něco užitečného, může být třeba součástí složitého auditovacího modulu. Často je ten listener jediným pojítkem mezi daným modulem a zbytkem aplikace. Rozhodně nechci aby mi auditovací modul přestal fungovat, jen proto, že garbage collector uvolní listener z paměti. Tady vidíme, že rada která je naprosto legitmní pro NetBeans nemusí být platná pro server. Na to je potřeba dát pozor.

To je jen jeden aspekt. Navíc jsem přesvědčen, že „obyčejní“ programátoři jako já moc API nepíší. Původně jsem to chtěl na tomto místě víc rozebrat, ale věnuji tomu speciální článek.

Takže podle mého názoru je kniha hodně užitečná buď pro lidi, kteří opravdu píší knihovny, což není můj případ, nebo pro lidi kteří se rádi zamýšlí nad tím jak dělat software, což můj případ je. Je na vás, abyste se rozhodli, jestli do těchto skupin patříte. Pokud ano, rozhodně si ji nenechte ujít. Pokud ne, radši si znovu přečtěte Java Efektivně.

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.