Ottimizzare le applicazioni Sencha tramite Lazy Loading

Ottimizzare le applicazioni Sencha tramite Lazy Loading

Sencha ExtJs è uno dei framework leaders per la realizzazione di applicazioni web nel mondo enterprise e non solo. Negli anni il framework si è evoluto in modo importante e continuativo, arrivando ad offrire un’architettura strutturata, completa ed estremamente performante. Tale architettura si basa su alcuni riferimenti in grado di indirizzare lo sviluppatore nella realizzazione di un’applicazione, favorendone gli standard, la scalabilità e lo sviluppo in team. Talvolta, però, questo forte indirizzamento può sembrare eccessivo e divenire una criticità poiché non permette di raggiungere scopi non esageratamente complessi sulla carta. Un esempio in questo senso è il caricamento dinamico (o lazy loading) di parti di codice che, per svariate ragioni, potrebbe essere utile ottenere “on demand” o a seguito di una certa logica. Ciò nonostante, se conosciuta a fondo, l’architettura di ExtJs può risultare piuttosto flessibile. Questo articolo si pone l’obiettivo non solo di mostrare una soluzione funzionante al problema del caricamento dinamico del codice, ma anche di mostrare la flessibilità che un framework come Ext può offrire nell’implementare soluzioni anche complesse. Architettura di un’applicazione ExtJs L’architettura di ExtJs si basa su alcune milestones che permettono ad uno sviluppatore di mantenere precisi standard e regole nello sviluppo, rendendo l’applicazione facilmente scalabile e manutenibile. • Workspace e packages. Un progetto Ext è composto da un workspace all’interno del quale risiedono: il core del framework, da 1 ad n applicazioni e, opzionalmente, delle librerie (packages) condivise tra le applicazioni stesse. Grazie al command line tool fornito da Sencha (Sencha Cmd) la creazione e la gestione di queste entità risulta estremamente semplice. • Object Oriented. Tutto il codice di Ext è orientato agli oggetti. Come nei principali linguaggi di programmazione lo standard vuole che sia definita una classe per ogni file e che tali classi siano raggruppate in directory che ne costituiscono il namespace. • Facile da debuggare. La struttura descritta al punto precedente rende il debug del codice molto snello e semplice. • Ottimizzato per la produzione. Terminato lo sviluppo si potrà facilmente realizzare una production release, ottimizzata e sicura. Grazie al Sencha Cmd infatti tutto il codice distribuito nel workspace ed utilizzato dall’applicazione verrà unificato ed oscurato, compattando in un unico file di appena 1,5 MB (~) tutta la logica dell’applicazione. • Single Page Application. L’architettura è basata sulla single page application, approccio ormai utilizzato dalla maggior parte delle applicazioni web, che permette di avere la massima esperienza utente, il miglior approccio per sistemi responsive ed il minimo uso della rete, in quanto solo i dati viaggeranno tra front-end e back-end. Punti di forza e criticità Dall’elenco precedente appaiono chiari i punti di forza dell’architettura: l’esperienza utente è ai massimi livelli con tempi di risposta minimali, niente lag ed approccio completamente responsive; allo stesso tempo c’è un disaccoppiamento completo tra le tecnologie di front-end e di back-end che permette di isolare lo strato della presentazione da quello della gestione dei dati. Inoltre si può ancora aggiungere come l’approccio proposto sia in grado di sfruttare la cache del browser, rendendo tutti i caricamenti successivi al primo molto leggeri, fino al rilascio successivo. Come ogni approccio presenta tuttavia anche alcuni aspetti negativi, che è importante analizzare e tenere in considerazione in modo da essere pronti ad affrontarli. • Per applicazioni molto grandi caricare all’avvio tutto il codice in memoria potrebbe risultare pesante, specie su browser o macchine non moderne. • Lavorando sul cloud ed appoggiandosi ad un tool per realizzare l’applicazione, risulta molto difficile scrivere estensioni dedicate a particolari clienti, situazione che potrebbe portare lo sviluppatore a scrivere montagne di “if”. • Da un punto di vista puramente commerciale, potrebbe essere poco vantaggioso permettere a clienti che hanno acquistato solo una parte del prodotto di scaricarlo interamente; ciò nonostante è importante ricordare come sia sempre il back-end a fare sicurezza, mentre il front-end gestisce i privilegi solo a scopo di “user-experience”. • Se si dovessero rilasciare aggiornamenti molto piccoli ma con una frequenza elevata, la cache del browser, basata su un unico grande file, risulterebbe poco utile. Packages Lazy Loading Pressoché tutte le criticità indicate precedentemente trovano risposta nella possibilità di caricare parti dell’applicazione dinamicamente o distintamente dal core. La chiave è dunque cercare di aggiungere la funzionalità di caricamento dinamico, cercando, allo stesso tempo, di mantenere tutti i vantaggi che un’architettura come quella di Sencha è in grado di offrire. Migrazione ad ExtJs 6 Il punto di partenza è l’ultima versione del framework. Con il rilascio della versione 6, Sencha non ha solamente permesso di realizzare applicazioni in grado di renderizzarsi su qualsiasi tipo di device, ma ha anche offerto una gestione molto più completa e flessibile di workspace e packages, permettendo, tramite Sencha Cmd, di realizzare build in javascript anche dei singoli packages oltre che delle intere applicazioni. Tali build sono assolutamente compatibili con un’applicazione Sencha già avviata e di conseguenza si prestano ottimamente allo scopo del lazy loading. Soluzione La soluzione consiste nella realizzazione di 2 classi, in grado di inserirsi nella posizione corretta del workflow applicativo e di gestire il download dinamico del codice contenuto nei packages specificati. Il codice sorgente delle classi citate è disponibile online: https://github.com/IbuildingsItaly/extjs-lazy-loading Tali classi cercano di offrire un’interfaccia semplice ed astratta per poter raggiungere i seguenti obiettivi: • Caricamento di packages all’avvio in files separati, indicandoli staticamente oppure dinamicamente introducendo una propria logica • Possibilità di gestire contenuti variabili in base all’utente loggato effettuando il download di packages diversificati • Possibilità di avere il lazy loading di un package solamente quando il proprio contenitore diventa visibile per la prima volta Ibuildings.lazyloading.Loader E’ una classe singleton che, se richiesta, è in grado di interporsi tra la logica di bootstrap ed il launch dell’applicazione, scaricando i packages necessari sin dall’avvio. Il suo utilizzo è molto semplice e tutto concentrato all’interno della classe Application (vedi Rif. 1). Analizzando il contenuto della classe si possono notare 3 punti cruciali: • La classe Ibuildings.lazyloading.Loader è richiesta come prima classe nelle requires, in modo da permetterle di entrare subito in azione grazie alla sua natura di singleton. • I packages richiesti staticamente posso essere indicati all’interno dell’array packages e configurati a dovere con informazioni quali il nome, la presenza/assenza di codice css dedicato, le classi da richiedere per lo startup (utile per la modalità sviluppo) ed i path alle directory con le build. • I packages richiesti dinamicamente, invece, possono essere indicati tramite il metodo loadPackages. L’output di tale metodo dovrà essere del tutto simile all’array descritto in precedenza in quanto i 2 verranno uniti insieme; la differenza principale è la possibilità di introdurre in questo metodo una qualsiasi logica applicativa. Ext.define('Lazy.Application', { extend: 'Ext.app.Application', name: 'Lazy', requires: [ 'Ibuildings.lazyloading.Loader', ], packages: [{ name: 'Financial', containsCss: true, requires: [ 'Financial.view.widget.Chart' ] }], loadPackages: function(){ var qs = Ext.Object.fromQueryString(location.search.substr(1)); if(!qs.cust){ qs.cust = “Ibuildings“ } return [{ name: 'Customer' + qs.cust, requires: [ 'Customer' + qs.cust + '.view.contact.Form' ] }]; }, launch: function () { } }); //application.js È importante notare come l’introduzione del Loader non modifica in alcun modo il normale funzionamento dell’applicazione. Il metodo launch così come il rendering del Viewport avverranno comunque a caricamento dei packages completo, in modo da garantire l’utilizzo di questi ultimi in qualsiasi fase del flow applicativo. Ibuildings.lazyloading.Panel Questa classe rappresenta un pannello semplice che può essere inserito in qualsiasi punto dell’applicazione come i normali pannelli. Esso deve essere configurato con le informazioni relative ad un package (simili a quanto visto nel punto precedente) ed eseguirà il download dello stesso la prima volta che verrà visivamente attivato. Di conseguenza il contenuto del package sarà veramente in lazy loading e, nel caso in cui l’utente non dovesse mai passare da quel pannello, non verrebbe mai scaricato, lasciando più leggera l’applicazione. items: [{ xtype: 'lazyloading', title: 'Administration', iconCls: 'fa-cog', module: 'Administration', mainClass: 'Administration.view.project.List', containsCss: true }], createPanel: function(){ Ext.create('Ibuildings.lazyloading.Panel', { title: 'Administration', iconCls: 'fa-cog', module: 'Administration', mainClass: 'Administration.view.project.List', containsCss: true }); } //Uso del pannello LazyLoading L’uso è assolutamente semplice (vedi Rif. 2) e permette all’applicazione di non avere alcun tipo di errore nonostante la classe richiesta non sia ancora disponibile. Inoltre, se necessario, lazyloading resta sempre un pannello e di conseguenza eredita tutte le configurazioni tipiche dei pannelli (nell’esempio si vede l’uso delle proprietà title ed iconCls). Pro e Contro Possiamo riassumere il contenuto di questo articolo elencando i pro ed i contro dell’approccio proposto. Essendo una soluzione totalmente non invasiva ed opzionale, i contro sono limitati alle poche operazioni extra necessarie per farne il setup, mentre i pro rappresentano effettivamente i vantaggi funzionali raggiunti. Pro Contro Caricamento dinamico di packages, all’avvio o a run time Necessità di richiedere nell’applicazione tutte le classi utilizzate da un package e definite al di fuori Miglior uso della cache del browser Necessità di compilare prima il singolo package e poi l’applicazione Miglior suddivisione del progetto per lavoro in team Attualmente la soluzione funziona in modalità development e production, ma non in testing Possibilità di filtrare il proprio codice secondo qualsiasi logica applicativa Miglior uso della memoria Maggior semplicità nel distribuire aggiornamenti di librerie usate da applicazioni multiple Demo Funzionante http://lazyloading.ibuildings.ws/Lazy

Realizziamo qualcosa di straordinario insieme!

Siamo consulenti prima che partner, scrivici per sapere quale soluzione si adatta meglio alle tue esigenze. Potremo trovare insieme la soluzione migliore per dare vita ai tuoi progetti.