Méně vrstev je někdy lépe

Přečetl jsem si článek Populární anti-patterny a chtěl bych v tomto článku ukázat, že to s dnešními moderním webovými frameworky a „čistotou“ aplikace není tak špatně.

Nejdříve bych rád řekl, co považuji za čistý návrh aplikace: je to taková architektura, ve které se lze snadno orientovat, a která nám umožní „snadno“ a „rychle“ provádět změny. Proto dvě aplikace s naprosto stejnou architekturou mohou být různě „čisté“.

Při tvorbě aplikací se používají tzv. návrhové vzory (např. Core J2EE Patterns). Jejich primárním cílem je pojmenovat a doporučit opakující se „vzory“. Je samozřejmé, že se jedná jen o doporučení a snad žádná aplikace je nevyužívá úplně všechny.

Jedním ze základních vzorů je tradiční Model-View-Controller. Tento vzor rozděluje aplikaci do vrstev. Každá vrstva se stará o svoji část a využívá k tomu ostatní vrstvy. Jak přibývaly vrstvy (vždy mně rozesměje spojení třívrstvá architektura, běžná aplikace má desítky vrstev), rostla pracnost při úpravách, které jdou napříč několika vrstvami. Při implementaci nového kódu je tak nutné v nejlepším případě upravit datový model, upravit controller a vytvořit GUI. Výsledkem bylo, že u větších projektů jsou náklady na vývoj zbytečně vysoké.

U některých „správně“ vrstvených projektů, se kterými jsem se setkal, si vývojáři připadali jako cvičené opice – při vytvoření nové funkčnosti, museli vytvořit mnoho kódu, který byl jen variací na ostatní objekty dané vrstvy (např. nová třída, která jen dědila od rodiče, ale neobsahovala vlastní kód). Architekturu dané aplikace, přestože používala mnoho vrstev, jsem vůbec nepovažoval za čistou.

Otázkou tedy je, jak vytvářet vrstvené aplikace a přitom eliminovat opakující se množství kódu. Řešením jsou aspekty (řešené pomocí anotací), POJO s různými interceptory a rozumné výchozí hodnoty. Díky nim můžete používat vrstvy a přitom je vlastně nevytvářet. Podívejme se tedy na některé vrstvy a na jejich dnešní podobu v moderních frameworcích, jako je např. Seam spolu s Hibernate.

Datový model a databázový přístup

Základem je normální Java objekt (tzv. POJO). Ten má různé relace s jinými objekty. Tyto relace podporují automatické načtení objektů a není tudíž nutné používat zvláštní API. Typickou implementací takového systému je Hibernate. Hibernate řeší DataSource pro připojení k databázi, DAO pro načtení objektů z DataSource, TransferObject a/nebo BusinessObject.

Můžeme tak snadno změnit typ databáze a způsob „mapování“. Protože se jedná o POJO objekt, lze snadno vytvořit tzv. „počítané“ položky (např. DPH když známe sazbu a částku) prostým vytvořením tzv. getteru. Je také možné přidat validační anotace, které provedou kontrolu položek před jejich uložením do databáze. Ty samé anotace je pak možné využívat i ve view vrstvě (např. v JSF).

Jediné, co proto tedy musíme udělat, je vytvořit POJO.

CRUD neboli EntityHome

Protože potřebujeme objekty vytvářet, číst, upravovat a mazat (CRUD), potřebujeme vrstvu, která nám to umožní. Když použijeme Seam, vytvoříme ji takto:

@Name("personHome")
public class PersonHome extends EntityHome<Person>{}

Můžeme pak volat metody personHome.persist(), personHome.remove() apod. Abychom nemuseli pokaždé vytvářet nový a v podstatě prázdný EntityHome, můžeme vytvořit továrnu, která vytvoří implicitní EntityHome a pokud je u POJO objektu přítomná anotace (např. @Home(PersonHome.class)) vrátí odpovídající instanci. Tuto vlastnost si ovšem musíme doprogramovat sami.

ValueList Handler neboli Query

Kromě načtení objektů z relace potřebujeme i další operace, jako je načtení všech objektů daného typu, jejich stránkování, filtrace, řazení a další. Vrstvu můžeme postavit na prostředcích, které nám pro tyto účely nabízí Hibernate. Protože potřebujeme umožnit konfigurovat více věcí (podle kterých položek řadit, jak filtrovat apod.), přijdou ke slovu opět anotace. Seam nabízí jednoduchou implementaci EntityQuery, která podporuje jen stránkování. Je možné ji rozšířit a přidat podporu dalších funkcí.

Data Transfer Object a Transfer Object Assembler

Někdy potřebujeme pracovat s daty, která vlastně v databázi neexistují přímo – jako jsou různé součty, agregační funkce apod. Protože objekty ukládané do databáze jsou vlastně jen POJO, můžeme si vytvořit vlastní objekty, ty správně naplnit a případně vytvořit potřebné navazující objekty.
K tomu můžeme použít např. i ResultTransformer.

Akce

JSF umožňuje snadno volat metody POJO objektu, a tím umožňuje tvořit akce, které jsou nezávislé na view vrstvě. Jeden z problémů je, že pokud budeme mít rozšiřující validátory v akci, musíme použít FacesContext pro jejich propojení s položkami formuláře. Tato nevýhoda se dá nicméně snadno obejít. Přesto je důležité si dávat pozor, která část kódu patří do view vrstvy a je specifická pro daný způsob zobrazování, a která část je obecná.

View vrstva

Jako view vrstvu v případě Seamu slouží JSF s Facelets. Jedná se o komponenty, které můžeme propojit s POJO objekty, EntityHome, apod. Umožní nám to používat jednoduché prvky typu editace čísla, tak i s pomocí Facelets snadno vytvářet složitější komponenty typu detail faktury, editace adresy apod. Seam také podporuje využití validací, které jsou definované u POJO objektu.

Aspekty

Aspekty nám umožňují sémanticky definovat vlastnosti daného prvku a ten pak využívat v různých vrstvách (viz výše uvedené validace). Zároveň s podporou dnešních IDE, umožňují snadné doplňování kódu a orientaci (kde všude se používá dané anotace).

Myslím si také, že některé návrhové vzory jsou používané i na místech, kde nejsou potřeba (např. Data Transfer Object) a při jejich použití by se měl mnohem více zapojit zdravý rozum.

10 thoughts on “Méně vrstev je někdy lépe”

  1. No tak ste zjevne nepochopil co to znamena tri vrstva aplikace. Zname na to totiz, ze je zde databazovy server, aplikacni server a klient. Pak sou zde jeste aplikace jednovrstve aplikaci, ktera ma databazovy motor primo v sobe, nebo dvoj vrstve kde se aplikace pomoci nejakeho jazyka (treba SQL) dorozumiva primo s databazovym serverem.

    I jednovrstva aplikace muze pozivat MVC a k tomu business vrstvu a persistentni, nebo komunikacni vrstvu. Nicmene pokud se vsechno spousti jednim procesem a aplikace obhospodaruje i fyzicky pristum k datum, tak se jedna o aplikaci jednovrstvou.

  2. Zdravím,

    samozřejmě vím, co je obvykle míněno třívrstvou architekturou. Jen se mi zdá trošku zvláštní rozdělovat vrstvy jen podle toho, že běží v jiném adresním prostoru (a případně na jiném stroji).

    A co takováto aplikace, kolik má vrstev:
    SQL – aplikační server – JMS – webový frontend – identity a access management server – webový prohlížeč

    Že by šestivrstvá architektura? :-).

    Jen jsem chtěl dát najevo, že rozdělení na jednovrstvou, dvouvrstvou a třívrstvou architekturu není úplně přesné. Protože technicky je vlastně úplně jedno, zda SQL server běží v paměti aplikačního serveru nebo ne – na architekturu ani výkonnost to vlastně nemá vliv (rozhodně ne negativní). Zvykem přeci je, aby do SQL přistupoval jen aplikační server.

    Také chápu proč toto rozdělení vzniklo – dává se zákazníkům najevo, že je použit SQL server a že můžou k aplikaci přistupovat po síti přes aplikační server a nikoliv přímo do databáze.

    Nicméně toto nebylo hlavním sdělením článku. A jen mne mrzí, že takový drobný vtípek odvedl pozornost 🙁

  3. Ne porad je to trivrstva archytektura. Prave adresni prostor je tim podstatnym. Protoze musi dochazet ke komunikaci za hranice tohoto prostoru.

    To o cem mluvite vy, se dneska nazyva spise aspekty, nez vrstvami.

    Takze SQL neni podstatnou podminkou pro urceni ze se jedna o vicevrstvou aplikaci. SQL muzete pouzivat jako dotazovaci jazyk i na embended databaze, vse bezi v jednom adresnim prostoru a taky kdyz se vam zbori databazove rutiny zbori vam to celou aplikaci. Podstata vezi v tom, ze je to skutecne nasazeno samostnatne.

    View, persistence a dalsi vnitrni vrstvy, jsou porad vrstvou aplikacni. Paklize jsou data pro zobrazeni predana uzivateli treba ve forme HTML, tak klientem te aplikace neni HTML, ale Webovy prohlizec, ten tvori druhou vrstvu. No a pokud nejsou data ukladana primo aplikaci, ale jsou predavana databazovemu stroji, ktery se o jejich fyzicke ulozeni stara, tak je tam treti vrstva.

    Takze pri programovani webove aplikace programujete z 99% pouze jedinou vrstvu a to aplikacni. Ostatni vrstvy jiz pouzivate od treti strany a ke komunikaci pouzivate specializovany jazy (s databazi SQL, s prohlizecem HTML). Nicmene v konecnem dusledku je to aplikace trivrstva.

    U vas je zjevne ze jste nepochopil podstatu tohoto fraze „trivrstva aplikace“.

  4. Adresni prostor neni tim podstatnym.
    Podstatne pr urceni vrstvy je, jakou plni ulohu v aplikaci a zda je mozne s malymi upravami (vetsinou konfigurace) zmenit neco z toho…

  5. Petre, nepodeziram te jako Lukas, ze jsi nepochopil podstatu „trivrstve architektury“, ale je to skutecne tak jak pise. Pokud mluvime o vrstvach aplikace nad ramec trivrstve architektury, tak se skutecne bavime o architekture stredni/aplikacni vrstvy. Ta se uplne zakladne deli na view, business a data access vrstvu, ale je samozrejme na kazdem architektovi kolik vrstev si tam navrhne ;-).

  6. 4ja: No jenze tady neni rec o navrhovych vrstvach v aplikaci. Ale o tri vrstve aplikaci. To je imho terminus technikus. A znamena to presne to co sem napsal.

  7. Vau, tak to potom jeste musite brat v potaz aplety ve webovem prohlizeci, ktere uz tak jednoznacne nejsou 🙂
    Ne, ale vazne. Trochu se tim vytraci smysl tohoto clanku. Sice nejsem az takovej znalec, ale myslim, ze vytvorit aplikaci, ktera by pri vetsich zmenach nesla pres vsechny vrstvy, nelze.
    Me se docela osvedcil facade pattern, kde jsem schopen co nejvice odstinit od sebe jednotlive casti. Nejvetsi cast pak zpet spada do business logiky a „nerozhazuje vsechny sve vlastnosti“, ale hezky spojuje a nabizi jen to, co skutecne potrebuji. S tim remote interfacem se snazim byt docela opatrny 🙂

  8. finc: aplety jsou zcela jednoznacne. Paklize jsou aplety stazene na klienta a cela apliakcni logika je provozovana na klientovi a pokud si tam i ukladaji data, nejak lokalne, budou jednovrstvou aplikaci. Pokud ty aplety budou mit svou vlastni logiku ale komunikovat pomoci nejakeho jazyka s databazi na serveru, bude to aplikace dvojvrstva. Pokud ty aplety budou slouzit jenom jako klienti aplikace jejiz logika je provozovana na serveru a ten pak bude komunikovat s databazi bude to aplikace trivrstva.

    Je zcela nepodstatne jakou technologii je tvoren klient, nebo databaze. Stejne tak je nepodstatne jakou technologii pouzivate pro vyvoj logiky aplikace. Jsou zde data, vykona logika a zobrazeni to je trojvrstva aplikace. Vse je to mozno nasadit samostatne v samostatnem adresnim prostoru.

    Vrstva autentizacni, logovaci, nebo jakakoli jina neni nic jineho nez podmnozina vrstvy vykone. I kdyz zacnete honosne kazde tride rikat ze je to samostatna vrstva, neziskate tristavrstevnou aplikaci.

    Word je prikladem jednovrstevne aplikace. Sdileni dat za behu aplikace je slozite. Kazda aplikace si ridi pristup sama, chcete-li pristoupit k souboru musite, pozadat druhou aplikaci ktera tento soubor vlastni o jeho uvolneni.

    Dvouvrstvou aplikaci je treba ucetnictvi Pohoda od spolecnosti Stormware. At zu s MsAccess databazy nebo s MsSQL databazi nemaji aplikacni server. To znamena, ze existuje centralni uloziste dat, ze ktereho jsou data nacitana, ale operace s nimy jsou vykonavany jiz primo klienty instalovanymy, spustenymi a spravovanymi samostatne. Synchronizace klientu je pak mozna na urovni dat, nikoli pak na urocvni operaci (tedy bez sloziteho programovani).

    A konecne je zde trivrstva aplikace, tou je treba slavny Google. Spousta uzivatelu maji plocheho klienta (webovy prohlizec). Googl ma apliacni server, ktery je slozity (nebochybne rozdeleny do vice slozitych vrstev, slouzici k autentizaci, logovani a kdo vi cemu jeste) a pak ma jiste nejake databazove stroje, se kterymi tato aplikace pracuje.

    jednovrstva aplikace: ma zpravidla mnohokrat spusteny proces zobrazeni dat, proces vykone logiky i proces spravy dat
    dvouvrstevna aplikace: ma zpravidla mnohokrat spusteny proces zobrazni dat, proces vykone logiky ale pouze jediny proces spravy dat.
    trivrstevna aplikace: ma zpravidla mnohokrat spusteny proces zobrazbrazeni dat, ale proces vykone logiky a spravy dat spusteny jen jednou.

  9. No ze vam tak skacu do debaty, ale toto (pomerne) caste nedorozumeni o tom, co je to vlastne vrstva je mozna dano nasim materskym jazykem. V anglictine se casto setkavam s delenim na tiers a layers. A pak mame klasickou 3-tier (3 vrstvou) aplikaci a business logic tier (vrstva) je deleny na layers (vrstvy 🙂 ).

  10. Upřímně, stále si myslím, že je vrstva jako vrstva. Nejedná se o dva různé druhy vrstev, ale jen o specializaci těch základních.

    Takže máme tyto vrstvy:

    • datová vrstva
      • úložiště dat
      • dotazovací systém
      • síťový přístup
    • aplikační vrstva
      • napojení na datovou vrstvu
        • JDBC driver
        • Hibernate
      • aplikační logika
      • napojení na view vrstvu
    • vizualizační vrstva
      • akce pro JSF
      • JSF
      • servlet server

    A mohli bychom pokračovat dále do hloubky …

    Na druhou stranu, myslím, že tady teď všichni slovíčkaříme. Je přeci jedno jak se tomu bude říkat, když všichni víme o co jde 🙂

Napsat komentář: Lukas Benda Zrušit odpověď na komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *