2007-08-06

Wicket vs JSF

Az elmúlt hónapokban volt szerencsém megismerkedni a Wicket-tel és a JSF-fel, ami két java szervlet alapú Webtechnológia azonos elhelyezkedéssel, azonos célkitűzésekkel. A második javafórum-os összeröffenésen -amin sajnos nem tudtam részt venni- is volt egy Wicket előadás.

A JSF a J2EE szabvány része a Wicket pedig egy SourceForge-os projekt, ami éppen nemrég csatlakozott az Apache Foundation-höz. A Wicket magát a konkrét implementációt is jelenti egyben, míg a JSF csak egy specifikáció, amelynek létezik egy referencia implementációja és több valódi implementációja. A valódi implementációk közül a Tomahawk-kal találkoztam, ami szintén az Apache-hoz fűződik.

A Wicket egy HTML markup-ot használ, amibe wicket-es tag-eket kell beleírogatni, amit aztán renderelésnél kicserélget szerveroldalon igazi HTML komponensekre. (Hasonlóan a Dojo-hoz, csak az kliensoldalon cserélget.) A JSF pedig klasszikus taglib működésű.

A JSF-hez a Facelet-eket is használtuk, ami annyit tud, hogy modulonként lehet összeállítani az oldalakat. Emellett még a standard taglib-et használtuk ahol tudtuk.

Ahelyett hogy hosszasan értekeznék róla, inkább kiválasztok néhány kritériumot és azok szerint hasonlítom össze a két versenyzőt:

HTML Elemkészlet: Milyen előregyártott elemek vannak.
Wicket: Elég szegényes, csak az alapvető form komponensek vannak meg. Rendezhető táblázat, fa nincs. Update: viszont sokféle komponens található itt: Wicket extensions
JSF: A referencia implementáció elég szegényes, a Tomahawk-ban már valamivel több lehetőség van, de több implementációból talán össze lehet szedni értelmesebb komponenseket. Ha más nem, fizetős implementációkból. A Tomahawk megvalósításai hagynak kívánnivalót maguk után. Konkrétan a tree2-vel találkoztam, amiben pl. nem létező feature, hogy a megjelenítésnél a fa bizonyos ágai legyenek lenyitva. Programozni kell hozzá. Általában elég sokat kellett programozni használható komponensek kialakításához ami roppant időigényes és bizonyos esetekben -amikor a business logikával kellene igazából foglalkozni- elkeserítő feladat.

DHTML lehetőségek: Ez nagyjából annyiból áll, hogy lehet-e komponensekhez javascript-eket beszúrogatni, lehet-e a komponensekre hivatkozni.
Wicket: Lehet, bár néha kicsit trükkös a Javascriptek oldalba ágyazása.
JSF: Az alap implementációnál problémás, mert maga határozza meg a komponensek id-it. Tomahawk-nál létezik a forceId, amikor mi adhatjuk meg az id-t. Ez nagyjából elégséges a DHTML-ezéshez.

Logika bővíthetőség: Mennyire lehet beavatkozni a keretrendszer működésébe.
Wicket: Elég jól bele lehet, szükség esetén akár a keretrendszerbe is bele lehet matatni.
JSF: Nem nagyon lehet beavatkozni, mivel a JSF motor az alkalmazás hatáskörén kívül esik, ráadásul az oldal életciklusa merev és teljes gáz, bizonyos esetekben nem felel meg az elvárásoknak. Megvan a helye a validációknak, modellbe érték visszaírásoknak, ettől nem lehet eltérni.

AJAX: Mindkettő az Ajax előtti időkből gyökerezik, szóval az ezirányú támogatás elég toldozás-foldozás jellegű, bár állítólag a JSF-nek is van Ajax-os megvalósítása és a Wicket is úgy reklámozza magát, hogy Ajax-os. Who knows...
Wicket Update a kommentek közül tapasztalt Wicket-es embertől: "Szerintem iszonyat jól használható a beépített Ajax támogatás, gyakorlatilag 0 sor javascripttel lehet szép ajaxos működést írni."

Adatmodell-prezentáció híd: A modellt valahogy bele kell pumpálni a html elemekbe.
Wicket: Java-ban történik ami fölöttébb kényelmes, nagyban megkönnyíti pl. a hibakeresést. Sajnos követni kell az oldal hierarchikus felépítését. Pl. ha egy text input egy-két frame-en belül van, azt a modellben úgy kell felépíteni. Általában sok anonymous inner class-t használunk Wicket adatmodell leírásához. Viszonylag egyszerű a különböző validációs logikák beépítése.
JSF: XML-ben van leírva, és emellett java bean-eket kell gyártani hozzá. Az így gyártott modell némileg könnyebben leválasztható, de többet kell írni és ott van az a fránya köztes XML és a JSF életciklus ami néha bekavar... Ha sikerül az XML-t hibamentesen leírni és nincsenek extra igények akkor meglepően hamar és könnyen működnek az összetolt részek. Amint dinamikus működésre van szükség, pl. egy mező validációs szabályai függenek egy másik mező értékétől -csőstől jönnek a gondok.

Hibakeresés:
Wicket: Elég részletes hibaüzeneteket írogat ki és a java használat miatt is egyszerű a hibák megtalálása. Nehezebb hibázni, mert minden java IDE eleve kiszűr sok szintaktikai hibalehetőséget. Sok hiba a komponens hierarchia be nem tartásából adódik. Nem mellékes, hogy a Wicket oldalak alapjában véve egyszerű HTML-ek, amelyek kapásból megjeleníthetőek egy egyszerű HTML böngészőben mindenféle szerver nélkül.
JSF: Általában a hibák indirekciója jelentkezik, ha jelentkezik. Rosszabb esetben csak üresen jelenik meg a kontroll, vagy szétcsúszva jelenik meg az oldal. Lehet találgatni hogy hol volt egy esetleges elírás, hiányzó vessző az XML-ben.

Modularizáció, újrafelhasználhatóság: HTML oldalrészek újrafelhasználhatósága.
Wicket: A beépített fragment mechanizmus használható. Jóval többet várnék.
JSF: A facelet elég telitalálat, nagyon jól használható. Az egyik legjobb dolog a JSF-ben, bár nem a JSF része. Kicsit szószátyár, de megbocsátható.

Grafikus dizájnolhatóság:
Wicket: Mivel sima (X)HTML, céleszközökkel igen jól dizájnolható. CSS, képek használhatóak.
JSF: Nem sima HTML, viszont egyre több JSF céleszköz van amivel WYSWYG módon szerkeszthető. Ezekkel az eszközökkel nekem még csak drótmodellt sikerült eddig összeraknom. CSS, képek viszont szintén használhatóak.

I18n: Természetesen támogatott mindkét frameworknél.

Oldalakon vezérlő logika: Ha ismételgetni vagy opcionálisan akarunk megjeleníteni HTML részeket.
Wicket: Nem támogatja, mert alapelv, hogy az oldalon ne legyen B logika. (De mi újság a prezentációs logikához tartozó vezérlő szerkezetekkel?) Végülis meg lehet szokni nélküle. A fragment mechanizmust kell használni, ezenkívül van még egy egyszerű de elég jól használható iterator szolgáltatás.
JSF: Több szinten is támogatja, már a standard taglibek miatt is, de sajnos nem mindig jól működik együtt a többféle technológia, ami néha nagyon megnöveli a szopásfaktort.

Szerverterhelés: Ezt csak úgy érzésre tudom mondani, hogy kb ugyanott lehetnek ebben a kérdésben. A Wicket-nek inkább több memóriára van szüksége, mert fenn kell tartania a kérések során a memóriában a java komponens hierarchiát, a JSF pedig újraépíti az adatmodellt minden egyes kérésnél, ami fokozott számítási igénnyel jár, viszont elvileg kevesebb memóriát igényel. A wicket-nél ügyelni kell a szerializációra, mert egy rosszul felvett mező könnyen felránthat pár megabájtot a session-be. A Wicket-nél szintén ügyelni kell az inaktívvá vált kliensekre, akiknek a Java komponens hierarchiáját valamikor el kell dobni a memóriából. Mindkettő cluster-ezhető.

Dokumentáció:
Wicket: elég jó doksi van hozzá.
JSF: van hozzá mindenféle írás, de pl. a Tomahawk-hoz egy félig írt Wiki, amiben sokszor inkább a problémákat részletezik.

Melyiket használnám a következő projektben?
Nagyon enyhén a JSF felé dől a mérleg, de biztos hogy utánanéznék valami igen jól kidolgozott megvalósításnak. A Wicket sem rossz, úgy érzem kb. egy szinten vannak, de a JSF-ben -akkor is ha talán több vesződéssel jár- több a lehetőség. Viszont ha kevés lenne a dinamikus form-jellegű tartalom az oldalakon akkor Wicket-et használnék, mert az közelebb áll a HTML-hez, könnyebb dizájnolni. Ha sok a logika, egymásba ágyazódás, form elemek újrafelhasználása, akkor pedig a JSF-et választanám. Egyébként pedig messze nincs még ez a meccs lejátszva és ha valóban modern és dinamikus webalkalmazást kellene csinálni, akkor valószínűleg nem ezek közül választanám ki a keretrendszerét.

Update 2007.12.11: Találtam egy ilyet (wicketstuff.org) és egy elég kimerítőnek látszó összehasonlítást különböző webes framework-ökről. Ha majd lesz időm, átnézem ezeket. Addig is, aki beleolvasott, írjon róla.

4 megjegyzés:

cserepj írta...

Én adtam elő a jum-on... Pár dologgal vitatkoznék:)

"Wicket: A beépített fragment mechanizmus használható. Jóval többet várnék."

Jóval több is van. Panelek, Borderek, komponens class hierarchiák. Rengeteg újrafelhasználható komponenst írtunk az elmúlt másfél évben.

"Rendezhető táblázat, fa nincs."

wicket-extensions csomagot nézd meg, ott van minden ami kell, egy jól kitalált SortableDataProvider absztrakcióval, DetachableModel-ekkel, stb.

"Mindkettő az Ajax előtti időkből gyökerezik, szóval az ezirányú támogatás elég toldozás-foldozás jellegű"

Szerintem iszonyat jól használható a beépített Ajax támogatás, gyakorlatilag 0 sor javascripttel lehet szép ajaxos működést írni.

tvik írta...

Helló!
"Jóval több is van. Panelek, Borderek, komponens class hierarchiák."

Valószínű, hogy nem teljeskörűek az ezirányú ismereteim, de amit nagyon hiányoltam az az, hogy máshol előre definiált paneleket nem tudtam úgy beépíteni, hogy a markupot használom dinamikus vagy statikus paraméterek átadására. Facelet-tel nagyon jól meg lehet ezt oldani az ui:param tag alkalmazásával. Wicket-ben nem találtam ilyen lehetőséget. Az is fontos, hogy minél kevesebbszer kelljen két helyen párhuzamosan foglalkoznom az oldal felépítésével. Wicket-ben ugye többnyire a HTML-ben és a Java kódban is fel kell építenem az oldalhierarchiát, ami 2+x -szeres munka, ahol x a szopásfaktor.

"Rengeteg újrafelhasználható komponenst írtunk az elmúlt másfél évben."

Ez azt jelenti, hogy szoktál fejleszteni a Wicket-hez és commit-olni az Apache-os codebase-be?

"wicket-extensions csomagot nézd meg"
Kösz! Valóban, ezt nem ismertem.
Legyen is itt a link: Wicket extensions

"Szerintem iszonyat jól használható a beépített Ajax támogatás, gyakorlatilag 0 sor javascripttel lehet szép ajaxos működést írni."

Nyilván szubjektív, hogy mit érzek toldozás-foldozás jellegűnek. Tényleg lehet dinamikusan cserélődő paneleket, dinamikusan töltődő combobox-okat írogatni Wicket-ben és nem is rosszul. A típusfeladatokat könnyű megoldani, van amire külön komponens is létezik. Talán amire én gondolok az már kicsit az Ajax-on túlmutat. Egy olyan framework-kel lennék nagyon elégedett, amivel egy Google Calendar-hoz hasonló dinamikus webalkalmazás fejlesztésének nyugodt lelkiismerettel neki lehet vágni.

Van egy olyan perverz igényem, hogy leküldeném a kliens logikát (vagy legalábbis egy bootstrap kliens logikát) a böngészőbe javascript-ben és úgy tekintenék rá, mint egy távoli vastagkliensre. Azt hiszem a Google Web Toolkit pont ezt csinálja.

cserepj írta...

"a markupot használom dinamikus vagy statikus paraméterek átadására."

Aha, ez szerintem koncepciponális hiba. Model a kulcsszó wicket-ben mindenre. Na inkább mesélek, hogy én milyen stuktúrára jutottam így a másfél év alatt és maximum megérted egyből:)

Vannak a Page-eim. Igazából csak 1 db-nak van markupja, az összes többi belőle öröklődik és ez a markup nagyon egyszerű - egy border vár magába amin belül egy content komponens kap helyet. Plusz a page-nek lehet egy model objektuma. Ennyi.

A Border-t az Application-öm egyik factory metódusa gyártja ami megkapja a konkrét Page örökös példányt és ez alapján tud gyártani neki saját Border-t (pl egy BlogPage-nek más Border objektumot gyárt, mint egy NewsPage-nek, stb). Minden layout és .css hivatkozás és oldalszerkezet az adott Border-ben van leirva.

A Border-en belül bármilyen komponens lehet - általában van is.

A Border a page szintjén kap egy content-et. Ezt mindig az adott Page örökös gyártja le - megintcsak egy factory metódussal. Én úgy alakitottam ki a kis házi framework-ömet, hogy az ős page osztályomnak csak PageParameters-es public konstruktora van, és az utódoknak egy metódus felüldefiniálsával van módjuk az átadott GET paraméterek beparse-olására és ez alapján egy objektum elhelyezésére a Page modeljében. Majd a content factory metódus már a Page modeljében talált objektum alapján késziti el az adott komponenst a content számára.

A Model pedig "lecsurog". Ha egy olyan komponens (panel a leggyakrabban) kerül a content helyére amelyik nem használja (ilyen is lehet), akkor persze nincs is rá szükség, de általában azért van.

"Ez azt jelenti, hogy szoktál fejleszteni a Wicket-hez és commit-olni az Apache-os codebase-be?"

Nézd meg a www.szeretgom.hu-t. Az egész wicket-ben készült. Egyedül. Esténként, hétvégente, az elmúlt másfél évben. A wicket-users levlistát olvasom, néha írok is, JIRA-ban is találsz pár bug reportot tőlem, de többre nincs időm. Itthon egy wicket tanfolyam összerakásán szórakozom üzleti célból, de még nem vagyok kész vele.

Amúgy a wicket-es fejlesztés nem áll másból, mint újrafelhasználható komponensek gyártásából. Egyszerűen nekiállsz úgy gondolni a UI-ról mint objektumokról (nekem ez 1999 óta a vesszőparipám, azóta kerestem , hogy hogyan lehet szépen OO szerint fejleszteni webet - és a wicket-ben ezt találtam meg).

"Van egy olyan perverz igényem, hogy leküldeném a kliens logikát (vagy legalábbis egy bootstrap kliens logikát) a böngészőbe javascript-ben és úgy tekintenék rá, mint egy távoli vastagkliensre."

Aha, értem - nekem ez a fajta megközelités nagyon idegen. Lehet, hogy a mindenféle JS XSS vulnerabilityk miatt, vagy csak mert nagyon idegenkedem a javascripttől... de erre talán valóban a GWT modellje illeszkedik jobban.

A wicket kicsit másról szól - valódi OO webfejlesztésről. Én pl most ott tartok, hogy van egy ContentPanel nevű komponensem ami bármit meg tud jeleniteni ami az alkalmazásban a Content nevű ősosztályból származik. Ha felmész a szeretgom.hu-ra, akkor bármilyen tartalomtipusra kattintasz is, egy ContentPanel-t látsz magad előtt. A menük, a dobozok mind-mind egy-egy panelban vannak, csináltam még Layout paneleket is amiket csak fel kell paraméterezni komponens Class-ok tömbjeivel és automatikusan GridLayout szerűen példányositja és elrendezi azokat a megfelelő struktúrában. Van saját BBLabel meg BBMultiLineLabel komponensem amivel gyakorlatilag a Wiki kódok értelmezésén át a BB kódokig mindent át tudok forditani HTML-re ami a BBLabel modeljében stringként el van tárolva (és ami model lehet mondjuk egy CompoundPropertyModelben eltárolt Content-nek a getBody() metódusa által visszaadott String is egy "body" id-jű komponens esetén).

No lehet nem vagyok túl összeszedett igy hajnal 1-kor, de a beirasodbol elegge az jott le nekem, hogy csak a felszint kapargattag egy kicsit ezzel a keretrendszerrel kapcsolatban, mi viszont gyakorlatilag túl vagyunk 3 komoly projekten vele (egy hitel frontend alkalmazás az egyik hazai kerbankban, egy időnyilvántartó rendszer ami lassan projekt és resource management eszközzé növi ki magát, meg a fent emlitett otthoni pet projektem amiből lassan egy teljesértéku ujrahasznalhato web-cms kezd kinőni).

tvik írta...

"a markupot használom dinamikus vagy statikus paraméterek átadására."
"Aha, ez szerintem koncepciponális hiba."


Mármint koncepcionális hiba ha Wicket-ben így akarom használni. Mindenesetre JSF-ben ez a koncepció, hogy a markup-ban paraméterezünk. Szubjektíve nekem az utóbbi tetszik jobban. Aztán ettől még JSF-ben is meg lehet csinálni azt szimpatikus model leképező szerkezetet amit írtál.

"hogyan lehet szépen OO szerint fejleszteni webet"
Egy vélemény valakitől, akitől sokat tanultam annó: Az Objektum Orientáltság nem minőségi jelző, hanem csak egy tulajdonság. Ráadásul nem a Java az egyetlen (és talán nem is a legjobb) eszköz OO-ságra. Ha úgy veszem egy Facelet-es JSF oldal is objektum orientált, csak nem java osztályokkal van leírva, hanem markupban, dependency injection segítségével. (Na jó, kicsit meredek megközelítés.) Másrészről az I/O és a rendszer felé közeledve egyre nehezebb fenntartani az objektum orientáltságot. Lényeg, hogy fontosabb hogy jól használható legyen valami, mint hogy "szép OO" legyen.

A Szeretgom-ot nézegettem annó és tetszik, gratulálok hozzá! A Wicket-tel én is egy üzleti projektben dolgoztam, de többet nem írhatok róla.