5. Introduction
IN YOUR ZONE
5
•Modern Web Applications common characteristics:
• Interactive – constant feedback
• Limit full-page reloads – fluid experience
• Asynchronous – AJAX
• Manage data – caching & prefetching
•Spectrum of Web Applications
• Static sites
• Server rendered
• Hybrid design
• Single-Page Interface
Richer experience
6. Navigation
IN YOUR ZONE
6
•Navigation challenges:
• Browser’s history mechanism
• Deep linking
• Bookmarks
•Approaches:
• HTML5 History API
• Libraries like BBQ can help with Browser compatibility
7. Navigation
IN YOUR ZONE
7
•Harmony with the browser
•The URL matters
• Specific resource
• Application state
•Progressive enhancement – modifying URLs
• When the application loads
• When the user activates a link
8. Navigation
IN YOUR ZONE
8
•Browser History and the Back Button – how they work?
• Fragment Identifier (hash - #):
http://spi-site.com/LonelyPage#layout=details&id=4
•jQuery Back Button & Query (BBQ) plug-in
• Responding to User Actions – hashchange event
9. Navigation
IN YOUR ZONE
9
•Animating screen transitions
• Layout Manager – central coordinator
10. Navigation
IN YOUR ZONE
10
•HTML5 History API
• 'pushState' adds to history
• Going back fires 'popstate‘
•Modernizr – feature detection
• Exposes boolean properties
• Places CSS classes on HTML element
11. Module Communication
IN YOUR ZONE
11
•Preferably loosely-coupled
• Publish/Subscribe
• Events through callbacks
•Can also use direct method calls
12. Module Communication
IN YOUR ZONE
12
•Direct Method Invocation
• Easiest to understand and to implement
• Easiest to follow when tracing code paths
• Best used when:
• there are only 2 objects interested in communication
• readability and simplicity are more important than coupling and
flexibility
•Events through callbacks
• Powerful way to reduce coupling
• Best used when it is unacceptable for the sender and receiver to know
more about each other than the message they are passing
13. Module Communication
IN YOUR ZONE
13
•Publishing and Subscribing
• Best used when multiple subscribers are needed for a single message or
the same message needs to be sent from multiple publishers to a single
subscriber
14. Data Management & Caching
IN YOUR ZONE
14
•Maintainability - centralized data access
•Performance
• Eliminating unnecessary data calls to the server enables the browser to
process other tasks
•Scalability
• Unnecessary calls to the server require additional server-side resources,
which can negatively impact the scalability of the application
•Browser support - generic JavaScript object caching mechanism
15. Data Management & Caching
IN YOUR ZONE
15
•The amount of data you elect to cache/prefetch should be based on:
• the volatility of the data
• the likelihood of the user accessing that data
• the relative cost to get that data when the user requests it.
16. Data Management & Caching
IN YOUR ZONE
16
•Data Manager
• Performs data requests and manages interactions with the data cache
• Isolates the data cache
17. Data Management & Caching
IN YOUR ZONE
17
•Data Cache
• Internal to the data manager
• dataStore object is scoped to the page
• Allows the caching strategy to evolve independently without affecting
other JavaScript objects that call the data manager
18. Data Management & Caching
IN YOUR ZONE
18
•Caching with Local Storage
• Hard limit of 5Mb per origin
• Name/value pairs stored as strings
• Monitor changes with the 'storage' event
19. Summary
IN YOUR ZONE
19
•Implementing Navigation
•Module Communication
•Data Management
•Data Caching
20. Remus-Constantin Langu | Senior Developer
Remus.Langu@endava.com
Skype remus.constantin.langu
thank you
IN YOUR ZONE 20
21. Resources and Further Reading
IN YOUR ZONE
21
• The Single Page Interface Manifesto: http://itsnat.sourceforge.net/php/spim/spi_manifesto_en.php
• Project Silk: Client-Side Web Development for Modern Browsers: http://msdn.microsoft.com/en-us/
library/hh396380.aspx
• BBQ plug-in: http://benalman.com/projects/jquery-bbq-plugin
• Modernizr: http://www.modernizr.com
• Publish/Subscribe pattern: http://msdn.microsoft.com/en-us/library/ms978603.aspx
• jQuery UI Widgets Events: http://msdn.microsoft.com/en-us/library/hh404085.aspx#Events
• Client Data Management and Caching: http://msdn.microsoft.com/en-us/library/hh404101.aspx
• HTML 5 Web Storage: http://dev.w3.org/html5/webstorage
• The Past, Present & Future of Local Storage for Web Applications: http://diveintohtml5.info/storage.html
Hinweis der Redaktion
Bine ati venit la aceasta prezentare.
Titlul prezentarii din aceasta seara este “Single-Page Interface Challenges in Modern Web Applications”.
Continutul ei va cuprinde o serie de practici si de tehnici de abordare a provocarilor pe care le impune modelul ‘Single-Page Interface’ unei aplicatii web, pe care eu personal le-am invatat dintr-un proiect (Silk Project) dezvoltat de catre o echipa de la Microsoft Patterns & Practices.
Inainte de a trece la agenda acestei prezentari mi-ar face placere sa incep cu o scurta prezentare personala.
Numele meu este Remus-Constantin Langu, lucrez la Endava de aproape 4 luni, ca senior developer. Inainte am mai lucrat vre-o 5 ani pe solutii enterprise la o alta firma. Sunt crestin-ortodox, casatorit, cu 2 copii momentan si am 27 de ani.
Aceasta este agenda pentru seara aceasta:
Vom incepe cu o scurta introducere pentru a defini putin contextul in care se plaseaza subiectul prezentarii.
Apoi vom vedea care sunt provocarile de navigare si cum le putem aborda.
Vom continua cu o abordare a comunicarii dintre module;
Pe urma, vom trece la definirea unei strategii de acces la date;
Si in final vom incheia cu un scurt rezumat.
Plaja de aplicatii web moderne este larga, dar totusi toate aceste aplicatii au niste caracteristici de baza comune.
Aplicatiile web moderne sunt in primul rand interactive, si pentru a oferi utilizatorilor o experienta placuta si captivanta ele tind sa ofere un feedback constant la actiunile utilizatorilor prin mesaje, animatii, efecte, prin reimprospatarea automata a datelor pe ecran, s.a.
Aplicatiile web moderne incearca sa limiteze sau chiar sa evite pe cat mai mult posibil reincarcarea completa a paginilor, tocmai pentru a pastra utilizatorul in context si pentru a-i oferi o experienta fluida in timp ce isi desfasoara activitatea.
Pentru a evita reincarcarea completa a paginilor, aplicatiile web moderne sunt asincrone si folosesc Ajax pentru a incarca dinamic datele necesare, fragmente de pagina sau alte resurse necesare.
Aplicatiile web moderne au o strategie de gestiune a datelor, atunci cand e cazul, au un mecanism de caching si de preincarcare a datelor tocmai pentru a sprijini performanta pe partea de client. Acest mecanism permite interfetei cu utilizatorul sa raspunda imediat la actiuni fara a mai fi necesar un apel la server pentru date. Ca urmare un alt beneficiu direct ar fi cresterea scalabilitatii aplicatiei, prin minimizarea impactului asupra resurselor de pe server.
In functie de gradul de interactivitate pe care il ofera, aplicatiile web pot fi grupate in patru categorii:
Site-uri statice care contin pagini HTML statice ce nu ofera utilizatorilor nicio experienta interactiva, si in care navigarea intre pagini se face cu reincarcarea completa a paginilor;
Server rendered in care paginile sunt ansamblate dinamic pe server, iar pe client se fac unele validari sau simple efecte vizuale; De asemenea trecerea intre pagini se face cu reincarcarea completa de catre browser a paginilor;
Cu design hibrid care este similar modelului anterior dar care foloseste foarte mult cod JavaScript pe partea de client pentru a oferi utilizatorilor o experienta placuta si captivanta; Acest tip de aplicatie cuprinde portiuni in care schimbarea interfetei cu utilizatorul se face fara reincarcarea completa a paginii dupa modelul ‘Single-Page Interface’;
Single-Page Interface in care, doar o singura data la accesarea sitului, are loc o reincarea completa a paginii principale de pe server, in rest navigarea si incarcarea datelor se face fara o reincarcare completa.
Poate cele mai mari provocari pe care le prezinta sablonul ‘Single-Page Interface’ intr-o aplicatie web sunt cele legate de navigare, cum ar fi:
Gestiunea mecanismului istoric al browser-ului, astfel incat butonul ‘Back’ din sectiunea de navigare sa functioneze cum trebuie;
Furnizarea accesului direct la un anumit aspect sau la o anumita stare a paginii (‘Deep linking’);
Implementarea ancorelor care sa permita utilizatorilor sa insemneze (‘Bookmark’) aplicatia astfel incat aceasta sa se arate intr-o anumita stare specifica.
Din fericire, toate aceste provocari pot fi abordate folosind functionalitatile pe care le ofera browser-ele moderne in acest scop (‘HTML5 History API’) sau profitand de avantajele pe care le furnizeaza unele biblioteci JavaScript (‘Back Button & Query‘ jQuery plug-in) pentru imbunatatirea progresiva a modului de gestiune a navigarii de catre browser.
Pentru a suporta sablonul SPI, aplicatia web trebuie sa trateze acele interactiuni ale utilizatorului care in mod normal ar cauza o cerere la server si o reincarcare completa a paginii. Modul in care aceste interactiuni sunt manipulate atat pentru hyperlink-uri cat si pentru butoane difera in functie de comportamentul fiecaruia.
Aplicatiile web care aplica acest sablon, partial sau complet, folosesc pentru crearea tranzitiilor intre pagini cod JavaScript, care suprascrie actiunile de navigare implicite, ale utilizatorului pentru a le controla. Totusi, chiar daca aplicatia preia responsabilitatea acestor actiuni, ea trebuie sa ajute browser-ul sa inteleaga detaliile importante ale acestora, pentru ca el sa se comporte in continuare la fel.
Asadar este nevoie de un parteneriat intre aplicatie si browser, care este usor de implementat daca cunoastem cum functioneaza browserul. Cooperarea dintre aplicatie si browser se poate face cu ajutorul URL-urilor, dintre care unele pot fi statice si nu se pot schimba in timpul unei sesiuni, definind calea de acces catre o resursa specifica, iar altele pot fi modificate dinamic in functie de context, definind calea de acces catre o anumita stare a aplicatiei.
SPI poate fi privit ca un ‘progressive enhancement’, adica ca o strategie de web design care sa maximizeze functionalitatea si experienta pe care o poate oferi un site, atat utilizatorilor care folosesc browsere moderne cu JavaScript activat, cat si celor care folosesc browsere mai vechi sau cu JavaScript dezactivat.
Intr-o aplicatie traditionala, browser-ul stie singur cum sa isi gestioneze in mod adecvat lista de istoric si comportamentul pe baza acestei liste. De fiecare data cand este instruit sa navigheze la un anumit URL unic, el inregistreaza adresa ca o noua intrare in lista de istoric. Actiunile de inapoi si de inainte din sectiunea de navigare a browser-ului, nu fac altceva decat sa sugereze browser-ului sa incarce URL-ul corespunzator din lista de istoric.
URL-urile pot contine un identificator de fragment (hash – partea de dupa caracterul de delimitare #). Acesta poate reprezenta numele unei locatii din pagina (numele unui element ancora), folosit pentru deep linking si bookmarking, sau poate reprezenta o valoare care corespunde unei stari a paginii.
Majoritatea URL-urilor din istoric fac ca browser-ul sa realizeze o reimprospatare completa a paginilor la accesarea lor. Totusi, daca un URL adaugat in istoric este identic cu URL-ul precedent, cu exceptia identificatorului de fragment, atunci browserul nu va realiza o reimprospatare completa a paginii cand utilizatorul va apasa butonul de inapoi.
Plug-in-ul BBQ pentru jQuery ofera aplicatiilor web dinamice suport pentru pastrarea functionalitatilor actiunilor de inapoi si inainte din browser, suport pentru gestionarea hash-ului, parsarea si imbinarea valorilor din identificatorului de fragment, deserializarea lui in obiecte javascript, s.a.
Aplicatiile care au nevoie ca sa pastreze un istoric al actiunilor utilizatorului, fara o reincarcarea completa a pagini, pot folosi evenimentul hashchange (din HTML5). Acesta este folosit pentru a raspunde la actiunile utilizatorului. El se lanseaza atunci cand utilizatorul da click pe un link care contine un identificator de fragment sau cand window.location este setat programatic din cod (cu pushState, de exemplu).
Daca browser-ul nu ofera suport pentru acest eveniment, atunci plug-in-ul BBQ stie sa il simuleze, ajutand astfel la compatibilitatea intre browsere (http://caniuse.com/hashchange).
Daca tranzitiile intre diferite stadii ale aplicatiei se face cu ajutorul animatiilor, pentru a oferi utilizatorilor o experienta fluida, atunci este util sa existe un modul comportamental central – layout manager, care pe langa gestionarea navigarii, sa coordoneze si aceste animatii.
HTML5 defineste, pe langa evenimentul hashchange, si un mecanism de gestiune a istoricului din browser, fara a utiliza identificatorul de fragment, adaugand in window.history metodele pushState si replaceState.
Pentru a determina daca un browser suporta mecanismul istoric din HTML5, se poate folosi o biblioteca javascript gen Modernizr. Aceasta biblioteca de detectare a trasaturilor de HTML5 implementate de browser ruleaza la incarcarea paginii pentru a construi un obiect javascript cu rezultate si pentru a adauga clase CSS pe elementul html.
In ce priveste comunicarea dintre modulele aplicatiei exista mai multe optiuni de implementare, fiecare cu avantajele si dezavantajele ei:
Comunicare directa;
Comunicare indirecta prin evenimente.
Aceste optiuni de comunicare ne permit sa controlam complexitatea aplicata pe interfetele obiectelor si pe implementare, si de asemenea ne permit sa controlam nivelul de cuplaj pe care obiectele il au.
Majoritatea aplicatiilor folosesc mai mult decat o singura forma de comunicare, deoarece fiecare optiune are avantajele si dezavantajele ei. Responsabilitatea programatorului este sa gaseasca balanta potrivita in functie de aplicatie.
Un obiect care apeleaza metoda unui alt obiect are nevoie de o referinta directa la acel obiect si din aceasta cauza, aceasta forma de comunicare este potrivita atunci cand in comunicare nu sunt implicati mai mult de doi participanti.
Un aspect foarte important aici este ca in functie de directia apelului, putem ajunge la niste dependinte incorecte. De exemplu, daca un modul gestioneaza alte module intr-o relatie de tip parinte-copil, atunci ar fi de preferat ca modulele copil sa nu referentieze modulul parinte. Pentru o comunicare bidirectionala este foarte util sa folosim evenimente.
Evenimentele permit unui obiect sa comunice cu alte obiecte fara a avea o referinta directa la ele. Acestea permit reducerea cuplajului intre module, fara a sacrifica comunicarea dintre ele, dar realizarea conexiunilor trebuie facata de catre alt cod, de regula de catre codul care creeaza modulele. Ca o alternativa se poate folosi sablonul Publica/Subscrie care se bazeaza pe un broker pentru gestionarea acestor conexiuni.
Sablonul Publica/Subscrie (Pub/Sub) ofera un mecanism de comunicare decuplata intre obiecte printr-un broker – un obiect intermediar. In forma sa cea mai generala, acest model de comuncarea cuprinde urmatoarele componente:
Publicatori – rol de expeditori in comunicare
Abonati – rol de receptori in comunicare
Subiecte – reprezinta contractele dintre participantii la comunicare.
Sablonul cuprinde 2 faze. Prima faza, de abonare, in care obiectele se aboneaza pentru a primi notificari in legatura cu informatii despre anumite subiecte. A doua faza este faza de publicare, cand publicatorii furnizeaza informatii despre anumite subiecte. Infrastructura de comunicare a acestui sablon poate fi implementata in diferite moduri. In functie de situatie, mesajele pot fi transmise sincron sau asincron.
Ar fi de preferat ca acest sablon sa fie folosit pentru acele mesaje globale la nivel de aplicatie pentru care modulele trebuie sa reactioneze, astfel incat aplicatia sa aiba flexibilitate, dar in acelasi timp sa isi pastreze interfetele si implementarile cat se poate de simple.
Incetinirile sau intarzierile rezultate in urma incarcarii datelor sau a salvarii lor pot avea un impact negativ asupra experientei utilizatorilor. De aceea, o strategie de gestiune a datelor pe partea de client este esentiala pentru succesul unei aplicatii web si mai mult de atat, ea va raspunde unor preocupari fundamentale cum ar fi:
Mentenabilitate - un simplu obiect javascript folosit pentru accesul centralizat al datelor este usor de intretinut;
Performanta - cu ajutorul cache-ului se pot elimina apeluri neutile la server pentru a permite browser-ului sa proceseze alte sarcini;
Scalabilitate - cu ajutorul cache-ului se pot evita apeluri repetitive, la server, pentru aceleasi date, apeluri care pot avea un impact negativ asupra scalabilitatii aplicatiei;
Alegerea unui mecanismului de cache generic, independent de caracteristicile unui browser specific, va permite aplicatiei sa poata fi rulata si pe browser-e mai vechi.
Mecanismul de acces a datelor si de gestiune a cache-ului poate fi implementat printr-un modul de infrastructura – Data Manager, care poate fi privit ca o interfata intre partea de client si partea de server.
Cantitatea de date aleasa pentru cache/prefetch ar trebui sa se bazeze pe urmatorii factori:
Volatilitatea datelor;
Probabilitatea de accesare a datelor de catre utilizator;
Costul relativ pentru a obtine acele date atunci cand utilizatorul cere aceasta.
Modulul de gestiune a datelor – Data Manager este responsabil pentru efectuarea cererilor de date si pentru gestionarea interactiunilor cu cache-ul de date.
Modulele din aplicatie sunt cuplate cu modulul Data Manager, la creerea lor, prin intermediul unei functii sendRequest definite in optiunile din interfata. Aceasta metoda permite decuplarea unui modul de o anumita sursa de date.
Abstractizarea implementarii accesului la date imbunatateste testarea aplicatiei prin faptul ca permite programatorului sa testeze cererile de date si cache-ul de date in izolatie.
Prin izolarea cache-ului in interiorul modului de gestiune a datelor, solicitantii de date pot beneficia pe deplin de cache, fara a mai
avea o alta dependinta si a implementa cod suplimentar pentru aceasta.
Mecanismul de cache foloseste URL-urile ca chei de stocare.