neděle 8. ledna 2012

Nepoužívejte Mapu ani String v rozhraní vašich tříd

Když se zpětně dívám, za APIs které jsem vytvořil, dochází mi, že jednou z největších chyb bylo použití tříd ze standardního SDK v jejich rozhraní. Použití tříd, jako java.lang.String java.util.Map apod., bylo samozřejmě dané mojí leností zavádět si speciální typy vyjadřující danou entitu. V budoucnu jsme platil za tuhle lenost velkou cenu.

Použití Mapy

Použití Mapy se mi hodilo pro reprezentaci jednoho řádku, který vracelou jedno vzdáleného API.

    public void processRow(java.util.Map row) {
        ...
    } 

Na první pohled jednoduché použití, ale... Za několik týdnu broušení objektů nad touhle reprezentací řádku jsem potřeboval rozšířit informace, které by o sobě řádek mohl prozradit. Potřeboval jsem metadata k jednotlivým sloupcům, ba co hůře, potřeboval jsem kontrolovat jestli je to řádek originální a nebo synteticky vytvořený. Problém byl na světě. Do Mapy totiž žádnou metodu nepřidáte. Musel jsem pracně předávat metadata jinou cestou. Pokud šlo o typ řádků testoval jsem typ na speciální implementaci Mapy, kterou jsem musel vytvořit. Poučení pro příště, mate-li v API java.util.Map pravděpodobně je něco špatně. Čest výjimkám potvrzujícím pravidlo.

Použití Stringu

Měl jsem třídu, která vyjadřovala kontext aktuálně přihlášeného uživatele. Identifikátor uživatele byla prostý java.lang.String přestože se jednalo o číselný identifikátor. Opět chyba, za kterou bych si dal rákoskou přes prsty.

    public String getUserId() {
        ...
    }

Co čert nechtěl, původní reprezentace se změnila z čísla opravdu na řetězec. Ve všech navázaných API byl String a na místech, kde bylo potřeba rozeznat původní číslo a nově řetězec, se muselo provést rozpársování. Správné řešení bylo použití hned od počátku objekt reprezentující uživatelův identifikátor.

    public UserIdentifier getUserId() {
        ...
    }

Další typické zneužití java.lang.String občas přichází v podobě konstant, které by bylo možné vyjádřit výčtovým typem. Mimochodem doporučuji přečíst poměrně kontroverzní, ale poučný článek Stefana Schmidta Never, never, never use String in Java (or at least less often :-).

Stejný problém představují tyto typy na místě návratových hodnot. Občas si dokonce pomůžeme například polem a nebo zavedeme nějaký tuple. Opět se toho vyvarujte. Sváže vám to do budoucna ruce, API nebude přehledné a těžko se vám bude rozšiřovat s ohledem na zpětnou kompatibilitu.