Ajax alkalmazások építése – lépésről lépésre

ajaxAz ajaxnak mint technológiának egyik hatása a fejlesztőkre nézve, hogy alaposan át kell gondolniuk eddigi elképzelésüket a webről. Az, hogy a lap újratöltése nélkül is tudunk a kliens és a szerver között adatot cserélni olyan lehetőségeket nyit meg előttünk melyek eddig vagy egyáltalán nem voltak a weben elérhetőek, vagy pedig megvalósíthatóak voltak ugyan, de erősen kérdéses volt, hogy megérik-e a fáradtságot.

Elöljáróban: Ajax alkalmazás vs ajax weblap

Először is különbséget kell tennünk egy ajaxot (is) használó weblap és egy ajax deluxe alkalmazás között.

Egy ajaxot használó weblap annyiban különbözik egy normál weblaptól, hogy bizonyos funkciókat a lap újratöltése nélkül, ajaxxal valósítanak meg, míg más funkciókat a hagyományos módon.

Ezzel ellentétben – legalábbis a saját szóhasználatomban – egy ajax alkalmazás egy asztali alkalmazás szerű, böngészőben futó alkalmazás, egyetlen, folyamatos adatfolyammal, újratöltés nélkül.

Persze ez a két megközelítés csak a két véglet. Praktikusan bármilyen arányban alkalmazható az ajax 0-100%-ig. Ebben a cikkben nem foglalkozom azzal, hogy ezt az arányt mi alapján érdemes meghatározni, részben már írtam róla az előzőekben, ha meg mélyebben bele akarnék menni, az meg egy teljesen külön cikk lenne. Itt, ebben a cikkben egy 100%-os ajax alkalmazás felépítéséről lesz szó.

Tervezés

Jó esetben mindenféle projectet úgy kezd el az ember, hogy készít egy tervet. Mit is fog csinálni az alkalmazásunk? Mondjuk legyen egy feladatkezelő. Kíváncsi lennék arra, hogy ki milyen módszert használ a tervezés legelső fázisában – mármint ha szoktatok egyáltalán tervezni :). A magam részéről kikapcsolom a számítógépet, fogok egy tollat és egy papírt, és elkezdem összeírni, hogy miről is lenne szó. Itt szigorúan kerülöm a technikai részleteket.

Küldetési terv

Előszőr meghatározok egy “küldetési tervet” egy-két mondatban. Mondjuk valami ilyesmit: “A feladatkezelő alkalmas legyen a saját tennivalóim nyilvántartására oly módon, hogy láthassam őket egyrészt projectenkénti bontásban, másrészt az aktuálisan elvégzendő feladatokat napok szerint”.

A küldetési terv megfogalmazása és pontossága döntő kérdés lesz a tervezés és a megvalósítás során. Néha néha előfordul, hogy a megrendelő meg tudja fogalmazni az igényeit. Ha esetleg mégsem, akkor egy sor keresztkérdést kell nekiszegeznünk és más módokon kell kínvallatnunk, hogy – ha esetleg ő maga tudja – akkor megmondja, hogy mit is akar. Ha nem tudja, akkor nekünk kell kitalálnunk, ami erős rizikófaktor lesz egy esetleges árvita során.

Ha a fenti küldetési tervünket kicsit átfogalmaznánk, és mondjuk azt mondanánk, hogy a “saját és a beosztottjaim tennivalóinak nyilvántartására”, akkor ezzel az apró módosítással rengeteg tervezési és megvalósítási pontban eltérnék az első megfogalmazás pontjaitól. Hogy csak egy leginkább kézenfekvő elemet említsek ha a beosztottak feladatait is nyilván akarjuk tartani, akkor adatbázis szinten biztosan nyilván kell tartanunk, hogy ki hozta létre a feladatot és kinek delegálta, esetleg, hogy hány delegálási szinten futott keresztül, és milyen időpontokkal.

Elvárások / Követelmények

A küldetési terv megfogalmazása után írjuk össze az alkalmazással szemben megfogalmazott megvalósítandó elvárásokat. Elvárásaink a küldetési tervből következnek, így újabb elvárások felmerülésekor mindig meg kell vizsgálnunk, hogy szolgálják-e a küldetési tervünket. Elvárások praktikusan a megvalósítás minden fázisában felmerülhetnek, de minél előbb fogalmazódnak meg, annál fájdalommentesebb lesz a megvalósításuk. Előfordulhat, hogy felmerül valami olyan elvárás ami jogosnak mondható, de nem passzol bele a küldetési tervbe. Mondjuk, hhogy mégis csak kellene a teamtagok feladatainak nyilvántartása is. Ilyenkor módosítani kell a küldetési tervet, aminek általában igen erős fejlesztési idő következményei lesznek.

Példánknál maradva a következő elvárásokat támasztjuk:

  • saját feladatok nyilvántartása
  • projectenkénti bontásban – hierarchikus szerkezetben
  • napi / heti bontásban – lejárat szerint
  • egyszerű kezelhetőség
  • gyors adatbevitel
  • a feladatok kategóriákba sorolhatóak legyenek
  • keresési lehetőségek
  • elérhető legyen a cég belső hálózatán keresztül bárhonnan
  • többnyelvűség
  • priorizáltaóság
  • ha egy faladatot nem végzünk el a megjelölt határidőre, akkor görgesse tovább és jelölje, hogy azzal késésben vagyunk
  • fejlesztési idő 2 hét

Ötletek

A küldetési terv megfogalmazásától a tényleges megvalósításig időről időre fel fognak merülni mindenféle ötletek. Ezeket én külön szoktam gyűjteni két csoportra bontva: technikai jellegű (megvalósítási) ötletek és funkcionális ötletek. Mindig meg kell vizsgálni, hogy az öteleteink szolgálják-e, illetve mennyiben szolgálják a küldetési tervet. Ez alapján első körben lehet őket rangsorolni. Ha egy ötlet megvalósítása mellett döntünk, akkor abból elvárás lesz. Mondjuk feljön egy ötlet, hogy a feladatok ne csak kategóriákba sorolhatóak legyenek, hanem tetszőlegesen címkézhetőek is. Ha elfogadjuk akkor az elvárási listára kerül, ha nem akkor vagy elvetjük, vagy meghagyjuk ötletként.

Technikai elképzelések

Ha elvárásainkat megfogalmaztuk, akkor az első lépés a programozási nyelv(ek) kiválasztása. Itt rengeteg szempont figyelembe vehető, amibe itt nem akarok belemenni, maradjunk abban, hogy az alkalmazást kliens-szerver modellben akarjuk megvalósítani, a szerver oldalon PHP-t, a kliens oldalon JavaScriptet használva, az adatok szerver oldali tárolására pedig MySql adatbázist.

Karakterkódolás

Mivel az elvárások között szerepel a többnyelvűség a fileok és az adatbázis karakterkódolásánál az utf-8 mellett döntünk.

Adatbázis

Mivel adataink egy adatbázisban lesznek eltárolva első körben azt kell eldöntenünk, hogy milyen típusú táblákat használunk. Az InnoDB és a MyISAM a két esélyes versenyző. Általánosságban az alapértelmezett MyISAM megfelelő lesz, de azokban a táblákban ahol szükségünk lesz a tranzakciók kezelésére a InnoDB-t kell választanunk.

Ezek után meg kell alkotnunk az adatbázis szerkezetét. A magam részéről erre a DBDesignert használom. Az elvárások jó kiindulási alapot adnak a tárolandó adatainkkal kapcsolatban. Esetünkben biztosan szükség lesz a feladatokat tartalmazó tasks táblára, egy kategoriák és egy prioritások táblára. Ezek tartalmát és adatkapcsolataikat azt hiszem mindenki ki tudja találni magának.

Futási környezet feltérképezése

Szerver oldal
A szerver oldali futási környezetünk egy Apache 2 szerver, PHP 5 és Mysql 5.
Böngésző
A kliens oldali futási környezetünk természetesen egy böngésző. A böngésző maga bizonyos szempontból megkönnyíti munkánkat, bizonyos szempontból megnehezíti. Mivel a kliens oldalon JavaScriptet akarunk használni számítanunk kell a különböző böngészők eltérő JavaScript megvalósításaival. Itt a 2 hetes fejlesztésre szánt idő, illetve az, hogy a saját belső intranetünkre készült az alkalmazás biztosította számomra azt a lehetőséget, hogy Firefox 2-re optimalizáljam az alkalmazást, és első körben ne kelljen más böngészőkkel foglalkozni. Gyorsan írjuk, hozzá az elvárásokhoz, hogy Firefox 2 támogatás elegendő ha IE nem támogatott külön jutalompontot érdemlünk :).
Monitor felbontás
Futási környezetünkhöz tartozik annak meghatározása, hogy milyen monitor felbontásra optimalizáljuk az alkalmazást.
JavaScript
El kell azt is döntenünk, hogy mennyire függjön az alkalmazásunk általános működése a JavaScript meglététől. Ugye a JavaScript futtathatósága kikapcsolható a böngészőkben, szóval még ha le is korlátoztuk a támogatott böngészőket egyre, még mindig nem lehetünk biztosak a dolgunkban. A feladat természete és a leendő felhasználók miatt nyugodtan mondhatjuk, hogy nem elvárás, hogy az alkalmazás kikapcsolt JavaScript és cookiek esetén is működjön. Puff, még egy elem az elvárások közé.
Mit hová terheljünk?
Kliens-szerver modell esetében mindig meg kell azt is határoznunk, hogy a feladatok mely részét helyezzük a szerver oldalra és melyeket a kliens oldalra. Erről itt.

Alaprajz

Körülbelül itt jutunk el odáig, hogy a kis papírkánkra lerajzoljuk, hogy hogyan kézeljük el az alkalmazásunkat működés közben.

Ajax lap terv

Ez a kis kézzel gyártott screenshot még sokszor előkerül majd a továbbiakban. Első körben abban segít, hogy beazonosítsuk az oldalunk fő elemeit. A rajzunkból egy három oszlopos weblap terve lett, egy fejléccel, egy tasklist blokkal, egy whatsnet blokkal és egy info blokkal.

A fejlécben egyenlőre egy logónk és egy kereső ablakocskánk van.
A tasklist tartalmazza a feladataink project szerinti hierarchikus nézetét.
A whatsnext blokk tartalmazza az aktuális hét feladatait.
Az infóblokk tetején van egy kis naptár az aktuális hónappal, egy részlet blokk egy kiválasztott feladat részletes információival, illetve egy gyorsinfó blokk, amibe azt akarom megjeleníteni, hogy hány feladatom van nyilvántartva, és ebből mennyi járt már le.

Akinek úgy tetszik azt is mondhatnánk, hogy beazonosítottuk a fő objektumainkat.

Cirkulált tervezés és megvalósítás

Ennek a módszernek biztosan van valami hivatalos neve, én jobb híján cirkulált módszernek nevezem. Tekintsük úgy, hogy az alkalmazásunk egy singleton objektum. Ha kicsit elvonatkoztatunk az eredeti problémafelvetéstől, akkor az eddigi (és az ezutáni) lépéseket tekinthetjük úgy, hogy a következőket tettük.

  • beazonosítottuk az objektumot (küldetési terv)
  • meghatároztuk az objektummal szemben támasztott követelményeket
  • öteleteket gyűjtöttünk
  • meghatároztuk a technikai elképzeléseket az objektummal kapcsolatban
  • meghatároztuk, hogy az objektum hogyan viselkedik, milyen eseményekre hogyan reagál (futási környezet és alaprajz)

Ha rápillantunk erre a listára akkor észre kell vennünk, hogy ezeket a lépéseket nem csak magára a teljes alkalmazásra, hanem annak bármely részére alkalmazható.

Szépen fussunk végig ezen a listán minden objektumunkkal. Az egyik objektumunk a tasklist lesz. Küldetési terve a feladatok hierarchia szerinti árázolása lesz. Meghatározhatjuk a vele szemben támasztott követelményeket és szépen a listán végiglépkedve végül eljutunk az objektum specifikációájig. A tasklistünk taskok listája, azaz a következő objektumunk egy task lesz. Küldetési terve egy feladat ábrázolása lesz. Arra nehéz lenne exact választ adni, hogy meddig érdemes az objektumokat bontogatni, de kis gyakorlattal bárki belerázódik.

Amit a magam részéről itt kiemelnék, az az a rész, hogy leírjuk és összegyűjtsük, hogy melyik objektumunk mely eseményekre reagál. Ez az alapértelemezett esemánykezelők regisztrálásakor és az esetleges esemény ütközések kezeléséhez nagy nagy segítség lesz. Erről itt.

Megvalósítás

Ha rászántuk az időt a tervezésre akkor a megvalósítási fázishoz szükséges időn sokat nyerhetünk. Kíváncsi lennék, hogy valaki valaha lemérte-e, hogy a tervezésre fordított idő és a project teljes megvalósításához szükséges idő hogyan viszonyul egymáshoz. Vagyis, hogy egészséges esetben a teljes időráfordítás hány %-a a tervezés. A magam részéről egyre több időt töltök el a terv összeállításával és próbálok egyre később beleugorni a kódolásba.

Szerver oldal

Kliens-szerver modellt megvalósító alkalmazások esetében a magam részéről mindig a szerver oldallal kezdem. Az adatbázis szerkezetét fent már meghatároztuk (és azóta lehet, hogy párszor már módosítottuk is), ezzel megvagyunk. Ha szeretnénk valamilyen keretrendszert használni (és miért is ne tennénk), akkor először azt keltjük életre. A magam részéről ez egy 2 perces CakePHP telepítést jelentett. Ha szükség van valami speciális apache vagy php beállításra, akkor itt egyből azt is megtesszük.

Annak, hogy a szerver oldallal kezdjük több előnye is van. Az egyik, hogy a kliens oldaltól függetlenül működőképessé tesszük az alkalmazásunkat. Ez körülbelül azt jelenti, hogy felépítjük az alkalmazásunk ajax nélküli verzióját. Ezáltal biztosítva vagyunk arról is, hogy a szükséges dolgok működnek, másrészről pedig arról, hogy alkalmazásunk kikapcsolt JavaScript esetén is működőképes marad (ha ez egyáltalán cél volt). A másik az, hogy a kliens oldali megvalósítás során már tényleges adatokkal, tényleges adatkommunikációval dolgozhatunk.

Kliens oldal

A kliens oldali megvalósítás első eleme a megfelelő doctype kiválasztása. Ez is megérne egy külön cikket, röviden a magam részéről attól szoktam függővé tenni, hogy a userek jogosultak-e html beírására vagy nem. Ha nem akkor a strict mellett voksolok, ha igen akkor a loose melett.

Következőként kettészedem a megvalósítandó kliens oldali feladatokat. Egyik csoport a csak kliens oldalon történő feladatok, mint például a tasklistben egy ág lenyitása, a másik a szerver felé történő kommunikációk és válaszok, azaz maga az ajax.

Harmadszor arról kell döntést hoznunk, hogy használunk-e valamilyen JavaScript libraryt, és ha igen melyiket.

A kizárólag kliens oldalon zajló történések megvalósításában nincsen sok különlegesség, ha rendelkezünk a fentiekben összeszedett leírásokkal, akkor tudjuk, hogy milyen eseményekre minek hogyan kellene reagálni, és akkor már nincs is más feladatunk hátra mint a kódolás.

Ajax kommunikáció

Azoknál az eseményeknél amelyek igénylik a szerverrel való kommunkikációt a következő összetevőket kell megvizsgálnunk.

  • Milyen választ várunk a szervertől és milyen formában?
    jóváhagyó válasz
    Ez azt jelenti, hogy a szervertől nem kapunk semmi új adatot, csupán annyit várunk tőle, hogy az indító ajax lekérés sikeresen lefutott-e vagy sem. Ilyen például ha egy taskot törlünk vagy a nevét módosítjuk. Csak annyi jelzést várunk a szervertől, hogy a kérést sikerrel végrahajtotta-e. Nincs szükségünk arra, hogy a szerver visszaadja a task új nevét, hiszen ezzel az adattal a kliens oldalon már eleve rendelkezünk, arra vagyunk csupán kíváncsiak, hogy az adatbázisbeli módosítás sikeresen megtörtént-e. A többi feladatot – a task nevének módosítását, vagy éppen magának a tasknak az eltávolítását a listából már kliens oldalon el tudjuk végezni.

    A jóváhagyó válaszok általában sima szövegként jönnek. Mondjuk siker esetén egy 1-es, hiba esetén egy hibaüzenet.

    tényleges adat válasz
    Ebben az esetben tényleges adatokat várunk a szervertől. Például ha rákattintunk egy feladatra, akkor azt szeretnénk, hogy az infó blokkban megjelenjen a feladathoz tartozó összes részinformáció, azaz, hogy mikor került rögzítésre, mi a határideje, melyik kategóriába tartozik, milyen prioritású, mi az elérési útja a feladatok hiererchiájában, stb. Ezekben az esetekben azt kell figyelnünk, hogy mely adatokkal rendelkezünk már eleve a kliens oldalon. Például a feladat neve biztosan a rendelkezésünkre áll, ezt felesleges újra lekérnünk.
  • Alkalmazható válasz adatformátumok kiválasztása. Ez megint egy olyan kérdés amit érdemes lenni valakien leméricskélnie. Például a válaszul jövő task adatokból egy kis formot állítunk össze. Mi lesz az optimálisabb? Az adatok lekérése json formátumban és a kliens oldalon összeállítani a formot belőlük, vagy pedig eleve xhtml-ben egy formot kapni a szervertől?
    sima szöveg
    a sima szöveg akkor megfelelő, ha valami kódot várunk vissza, amit nem akarunk feldolgozni csak értékelni, vagy valami egyszerű üzenetet, amit szintúgy nem akarunk feldolgozni, csak megjeleníteni

    json
    a json a legideálisabb formátum az adatok fogadására. Kisebb adatcsomagot eredményez mint az xml hasonlóan szervezhető adatformátummal.
    xml
    a magam részéről kerülöm használatát, mivel eléggé vitatható előnyei vannak a jsonnal szemben. Abban az esetben tartom létjogosultnak ha a lekérdezendő adatok már eleve rendelkezésre állnak a szerveren xml-ben, és annak használatával adatbázis lekérést spórolhatunk meg.
    xhtml
    xhtml-t akkor érdemes a szerverről küldeni ha a válasz minden feldolgozás nélkül megjelenítésre kerül, de a sima szöveg formátum nem alkalmas az adatok leírására. Előnye a jsonnal szemben, hogy nem kell feldolgozni, csak megjeleníteni, hátránya, hogy szűkebb körben használható.
  • Küldött adatok formátuma: általában itt sima szövegként küldünk ki mindent, hiszen a szerver többnyire POST vagy GET kérésen keresztül kapja meg az adatainkat.

Ha kitaláltuk az alkalmazandó adatformátumokat, akkor ezek alapján meg tudjuk állapítani, hogy mely válaszokat kell feldolgoznunk és hogyan, illetve melyeket nem kell feldolgozni.

Ha idáig eljutottunk akkor itt sem marad hátra más mint a kódolás.

Végső símítások

Ha túljutottunk a fentieken akkor (ha eddig nem foglalkoztunk vele) nekiláthatunk a design megalkotásán. Közben tesztelés, tesztelés, tesztelés. Később jöhetnek a hibajavítások és fejlesztések összegyűjtése és megvalósítása.

Utolsó helyen, de nem utoljára – a dokumentáció. Ha tervezés során buzgón jegyzeteltünk, a megvalósítás során pedig buzgón kommenteltünk a kódot, akkor van egy jó kiindulási alapunk. Persze senki sem szeret dokumentációt írni, részben vagy teljesen hiányos dokumentációtól viszont már mindenki szenvedett. Szóval ezt mindenkire rábízom. A PHPDoc jó segítséget ad a szerver oldal dokumentálására, a kliens oldalra várom az ötleteket.

6 thoughts on “Ajax alkalmazások építése – lépésről lépésre

  1. Ha szabad egy javaslatot: aztat úgy kell írni, hogy ajaxszal, nem pedig úgy, hogy *ajaxxal.

    Lásd: reflexszel, Marx-szal (ez benne van a 85-ös AkH-ban is mint példa, rákereshetsz).

  2. Nem érdekes, hogy nekem is rögtön szemet szúrt ez az Ajaxxal? Persze attól még lehet valaki nagyon jó programozó, hogy ez a spéci szabály hirtelen nem jutott az eszébe.
    Egyébként én teljesen amatőr vagyok, ráadásul még idős is, de élvezettel olvastam a fenti leírást!

  3. Nagyon frankó ez a leírás, jól illusztrálja a fejlesztési eljárást, kitűnő kiindulópont nem csak ajax-os, hanem bármilyen fejlesztési projekthez! Élvezetes és minőségi tartalom!

  4. Szerintem meg helyes nyelvtanilag az, hogy ajaxxal. Maximum egy kötőjel hiányzik. Mert nem az SZ az utolsó betű, hanem az X. Így lenne “szal” a vége: Ajakszszal. És örüljünk, hogy nem úgy kell írni még mindig, hogy ajaxval.
    És van ennek folytatása is, ahol már végre programozóként lehet olvasni az ajaxról?

  5. egyfelől a konkrét kódrészletek hiányoznak, ahogy az is, hogy a meglévő keretrendszert milyen birkózófogásokkal veszed rá, hogy tudja mondjuk azt amit te szeretnél tőle. és az ajaxszal az valóban úgy írandó hogy ajaxszal 🙂

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöljük.