Elméleti kérdések
A napokban kedvet kaptam egy kicsit elmélyedni az aktuális webes, illetve kifejezetten php alapú technológiákban és csak úgy passzióból elgondolkodtam pár dolgon. Ezekkel kapcsolatban szeretnék most egy kis diskurzust generálni, hátha felmerül egy-két érdekes ötlet.
Amennyire én látom még mindig az MVC/HMVC mintára épülő megoldások, illetve a különféle template enginek viszik a prímet. Néhány nagy és népszerű, illetve kismillió kisebb keretrendszer létezik, de nagyjából mind egy kaptafára készül (zend, symfony, yii, laravel stb.).
A php esetén ma már szinte kizárólag class alapú (OOP szerű) megvalósítást látni, bár igen gyakran különféle non-oop helper csomagok is aktív használatban vannak még a legnagyobb rendszereknél is. Ami önnmagában nem is lenne baj, de néhány példakódot, tutorialt átnézve sokszor felesleges bonyolításnak tűnt egy-egy megoldás.
Az alapvető kérdésem az, hogy tényleg nem lehetne ezt egyszerűbben és hatékonyabban? Ezen a kérdésen elgondolkodva arra jutottam, hogy az alapvető probléma még mindig a szerver és kliens oldali kódok elkülönítésének és egyben összehangolásának kérdése. Ma már a kliens oldali javascriptek és a html5 nyújtotta új lehetőségek is legalább olyan komplex kódokat igényelnek mint a szerver oldali alkalmazáslogika.
A két oldal összekapcsolása során felmerült bennem egy kulcskérdés:
- A kliens, vagy a szerver oldal határozza meg a tartalmat?
Első megközelítésben, mivel a szerver oldalon tároljuk a tartalmakat, nyilván a szerver mondja meg, hogy mik ezek. A kliens oldal (view) csak megjeleníti. A gyakorlatban viszont ez nem igaz.
- Ha a view-ban (templateben) mondjuk a főmenüt szeretnénk megjeleníteni, akkor a view honnan tudja, hogy van-e egyátalán főmenü? Ha meg van (mert maga a fejlesztő tudja), akkor mondjuk egy szimpla iteráció tényleg annyi elemet ad-e vissza amennyinek a templateben helye van? Vagy pedig a view mondja meg, hogy márpedig itt 5db főmenü elemnek van hely és a szerver oldal vagy ad annyit, vagy nem?
Végső soron arra jutottam, hogy a web esetén a view határozza meg a tartalmakat, a különféle layoutokat és a különböző helyeken különféle kontrollereket kellene megjelenítenie, egy oldalon akár többet is. A szerver oldalnak annyi a feladata, hogy a view számára biztosítja a kért kontrollert. A kérdés ezen a ponton viszont az, hogy minden egyes kontrollerhez valóban szükséges-e saját view - snippet - készítése (MVC szerint), vagy jobb megoldás lenne csupán egy előre meghatározott és dokumentált hard-coded markup visszaadása (pl.: return '<a href=""></a>'), amit mondjuk MVC esetén bizonyos esetekben a (html) helperek csinálnak.
A fenti elgondolás alapján azért keresgéltem is egy picit és rátaláltam a liftweb nevezetű scala alapú projektre. Ebben pont a fenti (view-first) megközelítést alkalmazzák és amennyire látom elég nagy sikerrel.
Az utolsó kérdésem a jelenlévő php gurukhoz egyrészt az, hogy php alapon van-e már view-first kezdeményezés, illetve ha nincs akkor miért nincs?
ps.: A topicot egyelőre csak elméleti vitaindítónak szántam, tisztában vagyok vele, hogy a hatékony munkához jelenleg egyértelműen valamely kész framework esetleg CMS használata a célravezető. Itt most inkább arra vagyok kíváncsi, hogy legalább gondolatban el tudunk-e szakadni a mainstream MVC standardoktól és el tudunk-e képzelni új logikát php alapon? És nem, nem a kereket akarom újra feltalálni, sokkal inkább a hiperhajtóművön gondolkodom, bár egyelőre kétségtelenül kerék formája van :)
■ Amennyire én látom még mindig az MVC/HMVC mintára épülő megoldások, illetve a különféle template enginek viszik a prímet. Néhány nagy és népszerű, illetve kismillió kisebb keretrendszer létezik, de nagyjából mind egy kaptafára készül (zend, symfony, yii, laravel stb.).
A php esetén ma már szinte kizárólag class alapú (OOP szerű) megvalósítást látni, bár igen gyakran különféle non-oop helper csomagok is aktív használatban vannak még a legnagyobb rendszereknél is. Ami önnmagában nem is lenne baj, de néhány példakódot, tutorialt átnézve sokszor felesleges bonyolításnak tűnt egy-egy megoldás.
Az alapvető kérdésem az, hogy tényleg nem lehetne ezt egyszerűbben és hatékonyabban? Ezen a kérdésen elgondolkodva arra jutottam, hogy az alapvető probléma még mindig a szerver és kliens oldali kódok elkülönítésének és egyben összehangolásának kérdése. Ma már a kliens oldali javascriptek és a html5 nyújtotta új lehetőségek is legalább olyan komplex kódokat igényelnek mint a szerver oldali alkalmazáslogika.
A két oldal összekapcsolása során felmerült bennem egy kulcskérdés:
- A kliens, vagy a szerver oldal határozza meg a tartalmat?
Első megközelítésben, mivel a szerver oldalon tároljuk a tartalmakat, nyilván a szerver mondja meg, hogy mik ezek. A kliens oldal (view) csak megjeleníti. A gyakorlatban viszont ez nem igaz.
- Ha a view-ban (templateben) mondjuk a főmenüt szeretnénk megjeleníteni, akkor a view honnan tudja, hogy van-e egyátalán főmenü? Ha meg van (mert maga a fejlesztő tudja), akkor mondjuk egy szimpla iteráció tényleg annyi elemet ad-e vissza amennyinek a templateben helye van? Vagy pedig a view mondja meg, hogy márpedig itt 5db főmenü elemnek van hely és a szerver oldal vagy ad annyit, vagy nem?
Végső soron arra jutottam, hogy a web esetén a view határozza meg a tartalmakat, a különféle layoutokat és a különböző helyeken különféle kontrollereket kellene megjelenítenie, egy oldalon akár többet is. A szerver oldalnak annyi a feladata, hogy a view számára biztosítja a kért kontrollert. A kérdés ezen a ponton viszont az, hogy minden egyes kontrollerhez valóban szükséges-e saját view - snippet - készítése (MVC szerint), vagy jobb megoldás lenne csupán egy előre meghatározott és dokumentált hard-coded markup visszaadása (pl.: return '<a href=""></a>'), amit mondjuk MVC esetén bizonyos esetekben a (html) helperek csinálnak.
A fenti elgondolás alapján azért keresgéltem is egy picit és rátaláltam a liftweb nevezetű scala alapú projektre. Ebben pont a fenti (view-first) megközelítést alkalmazzák és amennyire látom elég nagy sikerrel.
Az utolsó kérdésem a jelenlévő php gurukhoz egyrészt az, hogy php alapon van-e már view-first kezdeményezés, illetve ha nincs akkor miért nincs?
ps.: A topicot egyelőre csak elméleti vitaindítónak szántam, tisztában vagyok vele, hogy a hatékony munkához jelenleg egyértelműen valamely kész framework esetleg CMS használata a célravezető. Itt most inkább arra vagyok kíváncsi, hogy legalább gondolatban el tudunk-e szakadni a mainstream MVC standardoktól és el tudunk-e képzelni új logikát php alapon? És nem, nem a kereket akarom újra feltalálni, sokkal inkább a hiperhajtóművön gondolkodom, bár egyelőre kétségtelenül kerék formája van :)
Nyilván a view mondja meg,
A kliens és a szerver oldali kód egyáltalán nincs elválasztva ezekben a megoldásokban, a kliens kódját a szerver generálja le. Nézz egy kicsit jobban utána a REST service + single page javascript application fogalmaknak, ott pl teljesen el van választva a kettő. A szerver tényleg adatot szolgáltat a kliens meg megjeleníti az adatot valamilyen formában. Én most jelenleg azt csináltam egy projektnél, hogy a kliens kizárlóag - szerver szempontjából - statikus fájlokból áll. Szóval a böngészőben fut. Aztán ez csatlakozik egy másik subdomain-en lévő REST service-hez, amitól elkéri az adatokat.
Hogy is van ez?
Rosszul fogalmaztam a kliens/szerver kérdéskörben. Inkább arra gondoltam, hogy melyik hol fut?
Nagyon (tényleg nagyon!) leegyszerűsítve adott egy html és egy php fájl. A html a view, a php a szerver oldali kód. A html-t a designer, a php-t a fejlesztő hozza létre. Egy egyszerű példa, sima link:
html:
<a href="csoport/kategoria/termek/10001/leiras">Termék 1 leírás</a>
Ezt nyilván így nem teheti bele a desinger, mert majd a php kód mondja meg, hogy milyen termékek vannak, így ehelyett pl.:
<a href="<?=productManager->GetInfo(10001)?>"><?=productManager->GetNameInfo(10001)?>"</a>
Ez még mindig nem jó, mert az 10001-es azonosítót sem ismerjük, így a html markupban kb. ennyi lehet:
<?=productManager->GetProductLink()?>
Így viszont a html markup átkerül a php oldalra. Ha csak nem csinálunk egy view fájlt külön ehhez a linkhez:
<a href="<?=$link?>"><?=$display?></a>
És ha jól gondolom ezzel el is értünk a jelenleg általánosan elterjedt MVC megvalósításhoz. A view így már tényleg view és csak a megjelenítéssel foglalkozik. Az adatok meg jönnek a modellból, a controller alapján.
A gondom ezzel annyi, hogy így minden egyes generált adatmegjelenítéshez önálló view szükséges. Ami még nem is lenne akkora baj, de ezzel a módszerrel nem készíthető önálló design, mert akkor még nincs $link és $display változó.
Ezen a ponton meg már jönnek is a különféle template enginek, amik megoldják a dolgot, de egy újabb felesleges réteget jelentenek. Ezért kérdeztem, hogy ezt tényleg nem lehet egyszerűbben? És tényleg kérdezem, mert magam sem tudom, csak úgy érzem rossz ez az út, bár kétségtelenül általánosan elfogadott jelenleg.
Ezen a ponton meg már jönnek
Nem felesleges az a réteg. Azért kerül oda, mert az választja el azt, ami a kliensen fut, meg azt, ami a szerveren. A html generálását általánosan kétféleképpen lehet megoldani: dom fa építésével, vagy sablonozással. A dom fa építést pl a laconic használja. Én jobb szeretem az ilyen megoldásokat, mint a sablonokat, de ez ízlés kérdése... A sablonos megoldás olyan szempontból jó, hogy meg tudod mondani, hogy a designer milyen fájlokhoz nyúlhat hozzá. A dom fás megoldás abból a szempontból jó, hogy könnyen módosítható, kiterjeszthető, mert szét tudod darabolni factory method-okra. Többmindent lehet vele, mint sablonokkal. Ezért van az, hogy a sok marha nekiállt sablonnyelveket fejleszteni, mint mondjuk a smarty, amivel több funkciót bele lehet tenni a sablonokba. Sokkal több értelme van magát a php-t használni ilyen célra. Szóval maga a réteg nem felesleges, ami felesleges benne, hogy emiatt külön sablonnyelveket alkotnak, amiket aztán - jobb esetben - befordítanak php-re, ami maga is egy sablonnyelv, és jobb IDE-kben pl működik a kódformázás és kódszínezés is hozzá, tehát sokkal használhatóbb...
Ha a linkes példádat nézzük, oda kell egy view helper, ami linkeket állít elő, aztán ő tudni fogja, hogy egy product adataiból hogyan kell linket csinálni. Szóval annak ismét csak semmi köze a model-hez.
Template vs. DOM
Azt nem fejtetted ki, hogy a DOM manipulációt hogyan valósítod meg? Beolvasot a markupot és behelyettesíted a designer példa tartalmait a valódi értékekkel?
No offense, de a helperektől rosszul vagyok. Már amennyiben te is azt érted alatta, hogy van egy rakás php függvény amiket szükség esetén hívhatunk. Ha már ragaszkodunk az OOP felépítéshez, akkor a helpereknek semmilyen létjogosultsága nincs. Ha link készítéshez (illetve különféle markupok generálásához) kell egy helper, akkor már miért nem OOP módon, megfelelően strukturált ős-osztályban kapnak helyet, amiből öröklődik az aktuális view és már meg is lehet hívni osztályon belül ami kell. Vagy egyszerűen egy másik OOP ágból példányosítani a szükséges "helpert" az aktuális controlleren belül.
Vagy csak nekem fura, hogy miközben minden áron OOP-t erőltetünk, azért elég hamar szükségünk van non-OOP "trükkökre" a megvalósításhoz?
Mégvalami: minek példányosítani egy olyan osztályt, amiből a futás során mindig pontosan egyet készítünk? Amíg nincs absztarkt, típusparaméterezett osztálydefinícióra lehetőség php-ban addig a singletonnak semmi értelme. Pláne, hogy valódi singleton sincs :)
liftweb
A liftweb, már amennyit értettem, pontosan ezt csinálja. Megcsinálod a template-et, amit a liftweb parsol, majd feltölt adattal. Ez rengeteg erőforrást igényel.
Persze csak akkor, ha nem
Szerintem a DOM építés nem
Igen.
Ahogy nézem poetro lefordította, hogy miről van szó. Én nem használok sablonokat, főleg nem parsolom be őket, hanem függvényekkel építem fel a dom fát. Ez is erőforrás igényes, de sokkal könnyebb a megfelelő helyen kicserélni így a tartalmat.
Valami ilyesmit képzelj el:
A helper a view-ban lévő újrahasznosítható részek kiemelése valamilyen formában. Lehet függvénybe tenni őket, lehet ős view metódusba, lehet osztályba. Általában az ilyesmit támogatni szokták a sablonrendszerek, a legtöbbje bővíthető valamilyen formában.
Mert a példányokat könnyebb cserélni, mint a statikus osztályokat.
És a template?
Ezek szerint nincs működő design-od előzetesen, nincs előzetesen tesztelhető templated? Vagy ha van is ilyen, azt te kézzel "átfordítod" soronként DOM generálásra? Ha új arculatra van szükség, akkor kezded előröl?
Körülbelül fél óra egy ilyet
Btw. ha ez a fél óra annyira számítana, akkor írnék egy parsert vagy egy xsl-t, ami átfordítja nekem. Valahogy eddig úgy vettem észre, hogy nem ez szokott a szűk keresztmetszet lenni fejlesztési időben... Sokkal több idő elmegy az általános dolgok fejlesztésére, meg kigondolására.
Azt nem fejtetted ki, hogy a
Én kódból, deklaratívan építem fel a fákat, amiket aztán szabadon lehet manipulálni, és a végén szerializálni.
A php esetén ma már szinte
Mivel ez a megközelítés elterjedt a Design Pattern-ek miatt is, és mert áttekinthető jól szervezhető kódot eredményez. Ha mélyebben érdekelnek az OOP előnyei akkor érdemes utánaolvasni.
Nem lehet, hogy azok a kódok egy nagyobb rendszer részei? A példák általában nem tudnak elég mélyek lenni, mert akkor senki sem olvasná el őket, inkább csak szemléltetnek egy megközelítést.
Mit jelent az egyszerűbb, és mit jelent a hatékonyabb? Kinek a szemszögéből hatékonyabb és egyszerűbb?
Mivel a szerver rendelkezik a tartalommal, ezért a szerver határozza meg. Az, hogy a tartalom hogyan jelenik meg, és milyen egyéb módosítások történnek rajta az már lehet a kliens feladata is.
Hát onnan, hogy kap-e főmenüt a szervertől. Ha nem kap, akkor nincs, ha kap, akkor van. Azt hogy az egyes eseteket hogyan kezeled a view rétegedben teljesen egyéni probléma.
Az már régen rossz, ha vannak ilyen korlátozások. A view-nak ezeket kezelnie kell. Vagy megjeleníti mindet (ideális eset), vagy amennyiben tényleg nyomós ok van, akkor levágja akkorára az adathalmazt, amennyi neki elegendő (messziről kerülendő).
Rossz következtetésre jutottál. A view a megjelenítést határozza meg, amihez a tartalmat a model biztosítja. Az, hogy a modelbe hogyan kerül az adat, és a model hogy kerül a view-höz pedig a controller feladata.
Nem a viewhoz kell controller, hanem a modellekhez kell több view. És a view határozza meg a markupot, ami ideális esetben egy vagy több template.
Mivel az alkalmazásnak működnie kell, és csak másodsorban megjelennie valahogy (legalábbis szerintem). Azaz azzal nem vagyunk előbbre, ha jól néz ki, de nem tudunk vele semmit se csinálni. Előbb működjön jól, aztán nézzen ki jól.
Kicsit tényleg kevertem a dolgokat
- controller: vezérlés, működési logika
- modell: adat és tartalom réteg
- view: tartalom megjelenítő markup, modell alapján, kontrollerhez rendelve
Viszont ezt nem értem egészen:
- nem a viewhoz kell controller?
- hanem a modellhez view?
- és a view markup egy vagy több template?
Akkor a controller mihez kell?
Ha jól értem:
1. controller < modell //a controller betölti a szükséges modellt
2. controller > view[n](modell) //a controller betölti a szükséges view-t és átadja a modellt
3. view > html markup //a view megjeleníti az adatokat a markup alapján
De hogy jön a képbe a template, illetve a layout? Mert elvileg a view-t még meg kellene jeleníteni az aktuális layout megfelelő helyén. Hogy is van ez pontosan?
A view-first megoldás egyátalán nem a kinézetről szól. Nézd meg a liftwebet, ha részletesebben érdekel. Röviden arról van szó, hogy előbb elkészítünk egy oldalt és azt mondjuk meg, hogy melyik részén melyik controller jelenjen meg. Nem úgy mint az MVC esetén ahol (route alapján) lényegében 1 controller van betöltve és különféle trükkökkel tölthetünk be továbbiakat. Szerintem több fantázia van benne mint az MVC-ben, csak a scala-tól egyelőre irtózom :)
De hogy jön a képbe a
A template, ahogy a nevében is benne van egy sablon, hogyan jelenítse meg a view az adatokat. Sok framework esetében a view rész ekvivalens a template kezelővel.
A layout, szintúgy a neve elég beszédes, a felépítést adja meg, egy váz, hogy mi hova kerüljön. Egy controller egy metódusa betölthet több view-t is, azokat megfelelően elhelyezve a layoutban.
Ha rendesen építed fel az alkalmazásod, akkor nem kell 'trükközni'. Pl. mikor van szükséged egy view-ből egy másik controller metódusának hívására?
Szinte mindig
Például amikor a nyitólapon szeretném megjeleníteni a legfrisebb híreket, a legújabb felhasználókat, a legújabb ajánlatokat stb. Vagy itt a fórum mellett a jobb oldali sávban a friss blogmarkok, a könyvajánló, cikkajánló stb. Itt például van egy fórum kontroller, egy blog kontroller, egy könyvajánló kontroller stb. De pl. ugyanígy a minden oldal tetején megjelenő menu controller, vagy a login box/user panel.
Egy weblap jellemzően több részterületről jelenít meg tartalmakat és ebből csak egy a középső tartalom. A részterületeknek meg azért illik saját controllert készíteni szerintem.
Például amikor a nyitólapon
A jobb oldali sávban a friss blogmarkok, a könyvajánló, a cikkajánló, fent a navigáció, ezek közös elemek, az oldal globális részeinek tekinthetőek. A képlet egyszerű: készítesz egy ApplicationController-t, amely ezeket az elemeket rakja ki, illetve a layout-ot beállítja, a többi controllered (ArticleController, BookController, stb), ebből származnak le. Ebben nincs semmi trükközés, nem kell keresztbehívkálni trükkökkel a controllereket.
Mit is jelent ez pontosan?
Ráadásul az ApplicationController hogyan "rakja ki" ezeket az elemeket, mikor a származtatott osztályok funkcióit kell meghívni? Vagy az ApplicationController tartalmazza a származtatott osztályok hívásait? Így nem borul fel a logikai sorrend egy hangyányit?
Egyébként az általam boncolgatott kérdést már nálam okosabbak is feltették többször és erre készült a view-first megoldás, de php vonalon is a HMVC architekrura. Vagy említhetném a MOVE elgondolást is:
MVC is dead, it's time to MOVE on
Úgyhogy szerintem lenne még min gondolkodni az általánosan elfogadott sztenderdek mellett, mert úgy tűnik valós problémáról van szó.
(A témát is pont ezért nyitottam, de úgy látszik itt is inkább a mainstream tanultak köszönnek inkább vissza új gondolatok helyett. Mondjuk nem kell nagy jóstehetségnek lenni ahhoz, hogy bátran kijelentsem, néhány év múlva a mai standard MVC, HMVC, view-first stb. megoldásokat fel fogja váltani valami egészen új, de gondoltam akár mi is kitalálhatnánk valamit, csak úgy passzióból. :) )
Ha jól értem ez azt jelenti,
A template-eket, layout-okat, azok elemeit szét lehet szedni akárhány részre/komponensre. A termékeknél olyan layout-ot állítasz be ami a legújabb híreket rakja ki, a híreknél olyat ami a legújabb termékeket.
Az adatok szolgáltatása nem a controller, hanem a model felelőssége. Például van egy ProductModel-ed, az ApplicationController-ből nyugodtan lekérheted tőle a legújabb termékeket.
Egyébként értem amit mondasz, fejlesztettem ilyen módon működő rendszert, logikusabbnak is találom (viszont elég erőforráspazarló), viszont a hagyományos MVC keretrendszerekkel is meg lehet szépen csinálni mindent trükközés nélkül, ha tudod minek hol a helye.
Layout és a view nem ugyanaz
Nálam annyi layout készül ahány formában megjelenhet az oldal.
Ha ez egyik layout például tartalmaz egy felső menü és egy jobb oldali sávot az új termékekkel, ami a termékoldalon jelenik meg, akkor a termék megjelenítő oldal esetén ez a layout jelenik meg és a tartalom maga a termék adatlapja lehet. De a layout a tartalmon kívül meghív 2 komponenst, amiből az egyik a felső menüt, míg a másik a jobb oldali sávot jeleníti meg.
Aztán van egy másik megjelenítés, ahol mondjuk a felső menü szintén elérhető, de a jobb oldali sáv teljesen más dolgot tartalmaz (pl: hírlevél feliratkozás doboz), és a tartalom pedig egy CMS bejegyzés. Akkor létrehozok egy másik layoutot, ahol a tartalom magát a CMS bejegyzést tartalmazza (eddig teljesen megegyezhetne az előzővel), de a felső menüt és a jobb oldali sávot már egy másik 2 komponens jeleníti meg. Illetve mivel a felső menü ugyanaz, akkor azt ugyanaz a komponens végzi
Mindkét esetben a tartalmat megjelenítő controller (action) dönti el, hogy melyik layout legyen betöltve. De a központi tartalmat mindkét esetben egy controller vagy action jeleníti meg.
Viszont ha feliratkozás történik, akkor simán csak visszatöltöm az oldalt, mert maga a feliratkozó komponens úgyis "dolgozik", de mivel jött adat a számára, ezért a feliratkozás megtörténik (elmegy a feliratkozást megerősítő email, az oldalon már nem a form, hanem a feliratkozást megköszönő szöveg jelenik meg.) Vagy ha hiba van, akkor megjelenik a form, de a hiba üzenet is. Tehát teljesen külön működhet az oldal többi funkciójától. A fő funkció pedig a termék adatlap vagy CMS bejegyzés.
Layout és a view nem ugyanaz
néhány év múlva a mai
Az MVC egyidős a grafikus felülettel, 40 éve itt van, én nem temetném. Az, hogy a weben egy torz formáját használják, nem a modell hibája.
Backbone.marionette-nél ezt
Épp most írtam egy ilyen
a controller betölti a
Azt érdemes tudni, hogy az eredeti MVC-modellben a nézet direktben olvashatja a modellt. A vezérlő feladata a felhasználói interakció hatására a modell módosítása.
Elmlékedj egy kicsit ezen, mert szerintem sok kétséged feloldja.
A probléma
Ma már a kliens oldali
Például
http://net.tutsplus.com/tutorials/html-css-techniques/25-html5-features-tips-and-techniques-you-must-know/
Persze itt nem arra gondolok, hogy lehetőségek tárháza nyílt meg, inkább arra, hogy a technológia fejlődésével a kliens oldal is egyre összetettebb és így egyre nagyobb feladatod jelent a korrekt megvalósítás.
És akkor ott van még a responsive design is, ami még rátesz egy lapáttal.
Ezek a dolgok sem önmagukban,