—U niversità degli Studi di Padova — Dipartimento di Matematica Corso di Laurea in Informatica

Tesi di laurea

Sencha Touch 2 Sistemi di archiviazione dati per applicazioni ibride

Anno accademico 2012 - 2013

Laureando: Relatore: Andrea Rizzi Claudio E. Palazzi Andrea Rizzi: Sencha Touch 2, Sistemi di archiviazione dati per appli- cazioni ibride, 20 agosto 2013 e-mail: [email protected]

Note dell’autore

Il presente documento rappresenta la tesi di laurea dello studente Andrea Rizzi, condotta presso l’Università degli Studi di Padova. La tesi è stata redatta in LATEXcusando lo stile tipografico ClassicThe- sis di André Miede. La vera cosa importante nella scienza non è tanto scoprire nuovi fatti, ma piuttosto nuovi modi di pensarli. — William Henry Bragg (1862-1942)

PREFAZIONE

Il presente documento rappresenta la tesi di fine stage che ho condot- to dal 15 maggio 2013 al 31 luglio 2013, presso l’azienda Soluzioni s.r.l. Lo stage incentrato sul framework Sencha Touch 2, in- novativo strumento per la realizzazioni di applicazioni mobile ibride, è stato strutturato in due parti logiche: un’attività di studio del fra- mework e una di progettazione di una componente, atta a sopperire ad alcune mancanze di Sencha Touch, individuate durante lo studio individuale. Ciò mi ha portato a suddividere la tesi nelle seguenti 4 parti: parte i - introduzione : qui il lettore potrà trovare i dati inerenti lo stage e nello specifico quelli inerenti l’azienda ospite. Sono inoltre riportate delle brevi introduzioni al dominio tecnologico. parte ii - sencha touch 2 : contiene un’introduzione a Sencha Touch e PhoneGap (i framework oggetto dello stage), una serie di considerazioni sul loro utilizzo e le potenzialità derivanti. So- no inoltre presenti una serie di best practice individuate durante l’attività di studio. parte iii - syncengine : fornisce le informazioni legate al proces- so ingegneristico di creazione della componente SyncEngine, richiesta dalla ditta ospite, per soddisfare alcuni requisiti ob- bligatori (non soddisfatti da Sencha) ritenuti importanti ai fini aziendali, per un loro futuro utilizzo del framework. parte iv - appendici : costituisce una raccolta di approfondimen- ti su alcuni temi. Inoltre sono presenti un glossario, la bibliogra- fia e l’indice analitico.

In ultima, il lettore, voglia considerare le seguenti norme tipografi- che usate al fine di rendere la lettura più pratica e facilitare la ricerca di termini importanti:

• le parole in lingua straniera che non fanno parte del nostro quo- tidiano o per le quali si può usare la traduzione in lingua ita- liana (e.g device anziché dispositivo), sono riportate in corsivo. Altri termini di lingua straniera per i quali non esiste una tradu- zione diretta e per cui si usa la lingua originale (e.g. framework), sono trattati come termini normali;

• le parole particolarmente importanti nel contesto sono scritte in grassetto;

v • i termini da glossario sono riportati in blu (solo la prima volta che appaiono nel testo). Una loro definizione è presente nell’ap- pendice “Glossario”;

• tra parentesi quadre sono riportati i riferimenti bibliografici. Di essi è dato un numero identificativo nella bibliografia, e il titolo. Nel formato elettronico, i numeri scritti in verde costituiscono un link alla relativa voce nella bibliografia, a cui si rimanda per maggiori informazioni inerenti la fonte citata. All’interno della bibliografia per le voci inerenti articoli, siti o strumenti presenti nel web, è riportato l’indirizzo URL delle stesse. Nel formato elettronico, la parola URL (scritta in rosso) costituisce un link diretto all’indirizzo riportato affianco;

• in azzurro sono riportati i nome delle sezioni (o dei capitoli) del- la tesi, a cui si rimanda per un approfondimento. Nella versione elettronica tali voci costituiscono un link diretto alla sezione o al capitolo cui si riferiscono;

• ogni immagine è dotata di una didascalia. Per le immagini rica- vate da fonti esterne, e quindi non prodotte da me, è riportato il riferimento bibliografico da cui sono state estratte.

vi La felicità è reale solo quando condivisa. — Nelle terre estreme: 1996 Jon Krakauer

RINGRAZIAMENTI

Sono stati quattro lunghi anni di studio e sacrifici che mai sarei riu- scito a portare a termine se non fosse stato per il costante sostegno dei miei famigliari e dei miei amici. Innanzitutto voglio ringraziare i miei genitori Annarosa e Graziano e mia nonna Rina, non solo per il contributo economico ai miei studi, ma anche per aver sempre creduto nelle mie capacità e per avermi spinto a dare il massimo. Ringrazio i miei fratelli Ilaria, Luca ed Elisa per aver condiviso con me le gioie dei miei traguardi e per l’ironia con cui mi hanno consolato nei momenti più duri. Ringrazio i miei amici, i fratelli che scegliamo in questa vita... per avermi sopportato per tutti questi anni. Per avermi regalato numero- si sorrisi, ricordi e perché no “sani insulti gratuiti”. Perciò non solo un grazie, ma anche un abbraccio a Valentina, Alessandro, Monica, Andrea, Silvia, Francesca, Lisa, Nicola, Luca e Antonio. Ultimi, ma non per importanza, ringrazio Bruno Santo, lo staf di Solu- zioni Software, il professor Claudio Enrico Palazzi e la professoressa Ombretta Gaggi, per avermi guidato con pazienza, simpatia e rispetto durante l’attività di stage.

Grazie a tutti voi.

vii

INDICE i introduzione1 1 informazioni sullo stage3 1.1 Soluzioni Software, profilo aziendale ...... 3 1.1.1 Prodotti ...... 4 1.2 Scopo del tirocinio ...... 4 1.3 Tempistiche di svolgimento dello stage ...... 5 1.4 Pianificazione delle attività ...... 6 1.5 Conoscenze di partenza ...... 7 1.6 Problematiche affrontate ...... 8 1.7 Competenze acquisite ...... 9 2 una panoramica sullo sviluppo mobile 11 2.1 Gli attuali sistemi operativi ...... 11 2.2 Approcci di sviluppo ...... 14 2.3 Validità delle applicazioni ibride ...... 17 2.4 Un’anticipazione delle conclusioni ...... 17 2.5 Dominio tecnologico ...... 18 2.5.1 HTML5 ...... 19 2.5.2 JavaScript ...... 20 2.5.3 CSS3 ...... 20 2.5.4 ...... 20 3 ambiente di lavoro 23 3.1 Strumenti utilizzati ...... 23 3.2 Best practice di configurazione ...... 26 3.3 Riferimenti utili ...... 27 3.4 Valutazione finale degli strumenti ...... 27 ii sencha touch 2 29 4 introduzione 31 4.1 Sencha Touch ...... 31 4.1.1 Le basi del framework ...... 31 4.1.2 Le componenti principali ...... 32 4.2 PhoneGap ...... 33 4.2.1 Cos’è PhoneGap ...... 33 4.2.2 Funzionalità e dispositivi supportati ...... 34 4.2.3 Sistema di build delle applicazioni ...... 36 4.2.4 Considerazioni su PhoneGap ...... 36 4.3 Alternative ai framework proposti ...... 37 4.3.1 Framework per lo sviluppo ...... 37 4.3.2 Framework per il porting ...... 38 5 best practice 39 5.1 Come creare un progetto ...... 39 5.2 Considerazioni generali ...... 39

ix x indice

5.3 L’architettura delle classi ...... 40 5.3.1 Ext.define() ...... 41 5.3.2 Namespacing ...... 42 5.3.3 Pre & post-processors ...... 42 5.3.4 Ridefinire un metodo ...... 43 5.4 Come usare le associazioni tra modelli ...... 43 5.5 Un approfondimento sui Proxy ...... 45 5.5.1 Gli store e le loro funzionalità ...... 45 5.5.2 Tipologie di proxy a confronto ...... 46 5.5.3 Server-side Proxy ...... 47 5.5.4 MyApp.Proxy.MyCustomProxy ...... 48 5.6 FireEvent: una gestione intelligente degli eventi . . . . 49 5.7 Gestire il multi-tap ...... 53 5.8 Migliorare le performance di Sencha ...... 55 5.8.1 Quando usare Sencha Touch 2 ...... 56 5.8.2 Viewport dinamico ...... 56 5.8.3 Migliorare lo scrolling ...... 57 6 testare un’applicazione sencha 59 6.1 Considerazioni generali sulla verifica ...... 59 6.1.1 Pratiche avanzate di testing ...... 60 6.2 Strumenti necessari ...... 61 6.3 Syntax check ...... 62 6.4 Unit test ...... 63 6.4.1 Configurare Jasmine per testare Sencha . . . . . 64 6.4.2 Testare gli store ...... 66 6.5 UI test ...... 68 7 sistemi di archiviazione dati 69 7.1 Panoramica sugli store di HTML5 ...... 69 7.2 Utilizzare Web Storage e WebSQL con Sencha . . . . . 70 7.3 Considerazioni sull’uso dei Web Storage ...... 71 7.4 WebSQL e la gestione degli ID ...... 71 7.5 Plugin esterni ...... 72 7.6 Sencha.IO, il cloud service di Sencha ...... 73 7.7 Considerazioni finali sui sistemi di archiviazione . . . 75 8 prototipazione 77 8.1 NotesApp ...... 77 8.2 Analisi dei requisiti ...... 77 8.3 Architettura del prototipo ...... 79 8.4 Sviluppo del prototipo ...... 82 8.4.1 App.js ...... 83 8.4.2 NoteStore ...... 84 9 considerazioni sui framework usati 87

iii syncengine 91 10 analisi del problema 93 10.1 Introduzione ...... 93 indice xi

10.2 Sistema di analisi ...... 93 10.3 Problematiche di sistema ...... 94 10.4 UseCase ...... 95 10.4.1 UC1.0.0.0 ...... 96 10.4.2 UC2.0.0.0 ...... 97 10.4.3 UC2.1.0.0 ...... 98 10.4.4 UC2.1.1.0 ...... 100 10.4.5 UC2.2.0.0 ...... 101 10.4.6 UC2.2.2.0 ...... 103 10.5 Requisiti ...... 104 11 progettazione 107 11.1 Logica di sistema ...... 107 11.1.1 Sistema centrale di gestione ...... 107 11.1.2 Sistema di gestione degli ID ...... 107 11.1.3 Store sincronizzabile ...... 108 11.1.4 AddCommit, UpdateCommit e DeleteCommit . 109 11.1.5 Il problema del multi-tap ...... 110 11.1.6 Composizione del server ...... 110 11.2 Descrizione delle classi ...... 112 11.2.1 CSE1 - Gestione ID ...... 113 11.2.2 CSE2 - Store sincronizzato ...... 115 11.2.3 CSE3 - CRUD ...... 119 11.2.4 CSE4 - Sistema centrale ...... 121 11.2.5 CSIE1 - Multi-tap ...... 122 11.3 Diagramma delle classi ...... 125 11.4 Pattern utilizzati ...... 126 11.5 Diagrammi di sequenza ...... 127 12 analisi del prodotto ultimo 131 12.1 Introduzione ...... 131 12.2 SyncStore, analisi del codice ...... 131 12.3 Modifica del prototipo ...... 139 12.4 Usare il SyncManager ...... 143 13 verifica e validazione 147 13.1 Modalità di testing ...... 147 13.2 Test di unità svolti ...... 148 13.3 Errori rilevati ...... 153 13.4 Requisiti soddisfatti ...... 153 14 conclusioni 155 iv appendici 157 a module pattern 159 b sqlite 161 b.1 Cos’è SQLite ...... 161 b.2 SQLite Manager ...... 163 c test sul websql 165 d le basi di jasmine 169 xii indice

d.1 Come creare una suit di test ...... 169 d.2 Considerazioni aggiuntive sui matchers ...... 170 d.3 beforEach e afterEach ...... 170 d.4 Innestare più blocchi ...... 171 d.5 Spies ...... 172 d.6 Casi particolari: setTimeout e setInterval ...... 175 glossario 183 bibliografia 185 indice analitico 192 ELENCODELLEFIGURE

Figura 1 Soluzioni Software - logo aziendale [44, “Solu- zioni Software s.r.l.” ]...... 3 Figura 2 Soluzioni Software - facciata frontale della se- de di Padova [44, “Soluzioni Software s.r.l.” ].. 3 Figura 3 Resoconto distribuzione dei sistemi operativi mobile [3, “Apple share rebounds in Britain as iPhone 4 pulls in smartphone first-timers” ].... 13 Figura 4 Sencha Touch - logo [24, “Sencha Touch” ]... 31 Figura 5 PhoneGap - logo [17, “PhoneGap” ]...... 33 Figura 6 PhoneGap v2.7.0 - funzionalità supportate [20, “PhoneGap v2.7.0 - feature” ]...... 35 Figura 7 Sencha Touch - associazioni tra modelli [32, “Using Model Associations in Sencha Touch 2 and Ext JS 4” ]...... 44 Figura 8 Sencha.IO - logo [22, “Sencha Docs IO” ].... 73 Figura 9 Prototipo - struttura directory di lavoro [9, “How to create a Sencha Touch 2 app” ]...... 82 Figura 10 UC1.0.0.0 - creazione/caricamento del databa- se all’avvio dell’applicazione ...... 96 Figura 11 UC2.0.0.0 - scelta del sistema di gestione del database: sulle singole tabelle o sul sistema cen- trale ...... 97 Figura 12 UC2.1.0.0 - mostra come l’utente può interagi- re con una tabella selezionata in precedenza . 98 Figura 13 UC2.1.1.0 - mostra come un utente può operare operazioni CRUD su di una tabella selezionata 100 Figura 14 UC2.2.0.0 - il diagramma mostra le funzionali- tà predisposte per il sistema centrale ...... 101 Figura 15 UC2.2.2.0 - funzioni disponibili per la sincro- nizzazione di una tabella a partire dal sistema centrale ...... 103 Figura 16 Diagramma delle classi del sistema di archivia- zione ...... 125 Figura 17 Diagramma di sequenza 1 - creazione si un SyncStore a partire da SyncManager ...... 128 Figura 18 Diagramma di sequenza 2 - procedura di do- wnload ...... 129 Figura 19 Home del prototipo ...... 140 Figura 20 View per l’inserimento e la modifica di una nota 141 Figura 21 View per l’inserimento di un nuovo autore . . 142 Figura 22 TestSuit.01 - test di IndexIDStore ...... 148

xiii xiv Elenco delle figure

Figura 23 TestSuit.02 - test di IndexIDStoreFactory . . . . 148 Figura 24 TestSuit.03 - test di DownloadStoreFactory . . 148 Figura 25 TestSuit.04 - test di CommitStoreFactory . . . . 149 Figura 26 TestSuit.05 - test di AddCommit ...... 149 Figura 27 TestSuit.06 - test di UpdateCommit ...... 150 Figura 28 TestSuit.07 - test di DeleteCommit ...... 150 Figura 29 TestSuit.08 - test di SyncStore ...... 151 Figura 30 TestSuit.09 - test di SyncManager ...... 152 Figura 31 SQLite - logo [28, “SQLite Foreign Key Support” ] 161 Figura 32 Jasmine - logo [14, “Jasmine” ]...... 169 LISTINGS

Listing 1 Esempio creazione di una Ext.Class in Sencha 40 Listing 2 Definire un costruttore per le classi Sencha . . 41 Listing 3 Usare Ext.define() ...... 42 Listing 4 Esempio di associazioni tra modelli ...... 44 Listing 5 CustomProxy ...... 48 Listing 6 Un esempio di uso di MyCustomProxy . . . . 49 Listing 7 Gestione degli eventi - sollevare un evento con fireEvent ...... 50 Listing 8 Gestione degli eventi - controller ...... 52 Listing 9 org.s2.singleEventItem.button.SingleTapButton 54 Listing 10 Usare il SingleTapButton - definire il bottone . 54 Listing 11 Usare il SingleTapButton - listeners ...... 55 Listing 12 Syntax Check - esempio d’utilizzo ...... 63 Listing 13 Template di app-test.js ...... 64 Listing 14 Esempio di run-test. ...... 65 Listing 15 Template per il testing degli store ...... 67 Listing 16 Template per il testing degli store - it di base . 68 Listing 17 Prototipo - codice di app.js ...... 83 Listing 18 Prototipo - codice di NoteStore.js ...... 84 Listing 19 SyncEngine - server: operazione di download . 111 Listing 20 SyncStore ...... 131 Listing 21 Esempio di creazione di un SyncManager . . . 143 Listing 22 SyncManager - uso di createSyncStore() . . . . 144 Listing 23 SyncManager - esempio di utilizzo ...... 144 Listing 24 Module pattern - esempio d’implementazione 159 Listing 25 Esempio database SQLite con utilizzo di forei- gn key ...... 163 Listing 26 Test per la creazione di un WebSQL database ...... 166 Listing 27 Jasmine - creare una test suit ...... 170 Listing 28 Jasmine - uso di beaforEach e afterEach . . . . 171 Listing 29 Jasmine - describe innestati ...... 171 Listing 30 Jasmine - usare le ”spie” ...... 172 Listing 31 Jasmine - usare jasmine.createSpyObj . . . . . 174

xv

Parte I

INTRODUZIONE

In questa parte introduttiva sono riportati i dati ineren- ti l’attività si stage. Si troveranno quindi le informazioni relative all’azienda ospite, al piano di progetto e una bre- ve introduzione al dominio tecnologico in cui si inserisce l’attività.

INFORMAZIONISULLOSTAGE 1

1.1 soluzioni software, profilo aziendale

Figura 1: Soluzioni Software - logo aziendale [44, “Soluzioni Software s.r.l.” ]

Nata nel 1986, l’azienda Soluzioni Software1 s.r.l ha sede a Padova2 e filiali operativi a Pescara e Udine. Specializzata in software per la gestione aziendale delle piccole e medie imprese, l’azienda conta at- tualmente circa 60 collaboratori. É tra i primi partner italiani per SAP, azienda leader mondiale nel campo dei software gestionali.

Figura 2: Soluzioni Software - facciata frontale della sede di Padova [44, “Soluzioni Software s.r.l.” ]

Soluzioni Software S.r.l conta circa 300 clienti distribuiti nei settori dell’industria, della distribuzione e dei servizi, ed è in grado di pro- porre più soluzioni ai propri clienti, in funzione alle caratteristiche aziendali e al mercato in cui esse operano. Di seguito sono riportate alcune informazioni d’interesse riguar- danti l’azienda.

nome : Soluzioni Software s.r.l.; Dati dell’azienda.

indirizzo : Via Dei Ronchi, 21 35127 Padova;

telefono : +39.0498535211;

e-mail : [email protected];

sito web : http://www.soluzioni-sw.it/. 1 In Figura 1 è visibile il logo aziendale. 2 Un’immagine della sede è visibile in Figura 2.

3 4 informazioni sullo stage

1.1.1 Prodotti

Le aree di business in cui opera Soluzioni Software sono:

erp e software gestionale : • AdApta: soluzione proprietaria, disponibile per vari settori verticali, tra cui Manufacturing&Machinery. É una classica soluzione ERP gestionale integrata, dotata di una struttu- ra modulare, le cui basi sono l’aderenza ai più importati standard di mercato e l’indipendenza dall’hardware, dai sistemi operativi e dai linguaggi di sviluppo. • SAP Business One: piattaforma gestionale di SAP, orien- tata per le PMI; costituisce una soluzione semplice ed ef- ficace in grado di gestire le varie aree dell’azienda. Tale prodotto permette di snellire le operazioni giornaliere nel- le aree di amministrazione, vendita, acquisti, magazzino e produzione. • Panthera: primo gestionale di seconda generazione accessi- bile via web browser. Panthera è un’applicazione comple- ta e integrata, nata per fornire alle aziende la flessibilità per rispondere prontamente all’evoluzione delle esigenze aziendali e alle condizioni di mercato.

business intelligence : affrontata tramite BIplus, che permette la convergenza fra Information Managemente Business Intelli- gence nella PMI; BIplus è basato sulla tecnologia Qliktech, che permette al management di disporre di dettagliate analisi su- gli andamenti dei processi, per definire le corrette strategie di business da attuare.

gestione documentale : affrontata tramite ARXivar, con la qua- le è possibile gestire tutta la documentazione e le informazioni aziendali, i documenti e le note, i log, gli allegati, le associazio- ni, i fascicoli, i promemoria, i protocolli, i moduli, archiviare i documenti in modo massivo, stabilire delle liste di distribuzio- ne e condividere in modo ottimale le informazioni all’interno dell’azienda.

1.2 scopo del tirocinio

Da un paio di anni a questa parte il mercato dell’informatica sta spin- gendo sempre più su due concetti essenziali: mobilità e connettività. Ciò soprattutto, grazie alla nascita dei dispositivi tablet e smartpho- Obbiettivo: studio di ne. Per far fronte a queste esigenze, l’azienda mi ha incaricato di Sencha Touch e effettuare uno studio sul funzionamento e le potenzialità offerte dai PhoneGap. framework Sencha Touch 2 e PhoneGap, con uno scopo ben preciso: 1.3 tempistiche di svolgimento dello stage 5

inquadrare i mezzi e i limiti dei sistemi di archiviazione su dispositivi mobili. Difatti l’azienda sembra essere propensa ad un futuro sviluppo di applicazioni ibridi, rivolte in particolare al mercato dei tablet, e che possano aiutare i clienti nell’eseguire operazioni di raccolta ordini e tentata vendita. Un tipico scenario d’utilizzo vede un promotore aziendale recarsi Un ipotetico caso di da un cliente con lo scopo di raccogliere nel proprio tablet gli ordini studio. dello stesso. In un ipotesi pessimistica ciò può avvenire in assenza di connettività ad internet. Il promotore dovrà quindi avere la possibilità di:

• scaricare, preventivamente, il catalogo degli ordini prima di partire;

• raccogliere gli ordini del cliente nel proprio device, senza essere necessariamente connesso ad internet;

• inviare (in un secondo momento, quando avrà nuovamente con- nettività) gli ordini al server.

La tesi che vi accingete a leggere descrive, per l’appunto, tutto ciò che ho appreso durante questo percorso formativo. Lo scopo è du- plice: da una parte cercherò di fornire una visione dettagliata dei framework studiati, osservandone le capacità e i limiti. Dall’altra pro- porrò una soluzione, intesa come progettazione e realizzazione di una componente, atta a sopperire alle necessità aziendali cui Sencha non pone un rimedio diretto e soddisfacente.

1.3 tempistiche di svolgimento dello stage

In questa sezione sono riportate le informazioni legate alle tempisti- che di svolgimento dello stage3:

data inizio : 13/05/2013

data fine : 27/07/2013 (31/07/2013 in caso di contrattempi)

ore totali attività di stage : 320

tempo impiegato per le attività di stage : 8 settimane circa

impegno settimanale : • Nel mese di maggio: 24 ore di lavoro settimanali suddi- vise nei giorni di lunedì martedì e giovedì, per un totale (mensile) di ore di lavoro di 72 ore.

3 Le date e gli orari si riferiscono alla pianificazione preventivata all’inizio dello stage. In corso d’opera possono essere state operate delle leggere variazioni. Nello specifico si conferma che a causa di problematiche personali, ho terminato lo stage in data 31/07/2013. 6 informazioni sullo stage

• Nel mese di giugno: 24 ore di lavoro settimanali suddi- vise nei giorni di lunedì martedì e giovedì, per un totale (mensile) di ore di lavoro di 96 ore. • Nel mese di luglio: 40 ore di lavoro corrispondente ad una settimana piena (esclusi ovviamente sabato e domenica. To- tale ore di lavoro di 152 ore. In caso di problemi è prevista la possibilità di aggiungere 32 ore di lavoro corrispondenti all’ultima settimana di luglio (dal 27/07 al 31/07).

impegno giornaliero : 8 ore

orario accesso ai locali : 9:00 - 14:00

orario uscita dai locali : 13:00 - 18:00

1.4 pianificazione delle attività

Lo stage può essere pensato come suddiviso in due attività principa- li: la parte di studio del dominio tecnologico, e la parte di creazione della componente di sincronizzazione. L’esigenza di quest’ultima, di cui in tale sezione do solo un accenno, è emersa durante l’attività di studio, constatando che il dominio risultava non soddisfare a pieno le esigenze aziendali. Pertanto mi è stata commissionata la creazione di una componente da me nominata SyncEngine di cui darò una tratta- zione approfondita nell’omonima parte. Le modalità con le quali tale componente è stata creata si rifanno a quelle apprese durante il corso di Ingegneria del Software. Alle due attività principali se ne aggiungono due secondarie esegui- te rispettivamente all’inizio e al termine dello stage: la configurazione dell’ambiente di lavoro e la stesura della documentazione. Tutto ciò viene tradotto in dettaglio nel seguente schema: configurazione dell’ambiente di lavoro : ricerca del mate- riale necessario e sua installazione - 8 ore.

prima parte : studio del dominio. • Ripasso delle basi di HTML5, JavaScript e CSS3 - 15 ore; • introduzione da parte del tutor aziendale, al framework Sencha - 15 ore; • studio individuale sul framework Sencha e individuazio- ne delle best practice da adottare nello sviluppo di - 60 ore; • studio del dominio tecnologico e verifica delle competenze acquisite, mediante realizzazione di un’applicazione - minata NotesApp - 20 ore; • studio del framework PhoneGap e porting dell’applicazio- ne NotesApp - 8 ore; 1.5 conoscenze di partenza 7

• studio di approfondimento sugli store di HTML5 - 20 ore; • ricerca e approfondimento di plugin di terzi, per gli scopi aziendali - 5 ore.

seconda parte : realizzazione del SyncEngine. • Studio di fattibilità - 5 ore; • analisi del problema - 35 ore; • progettazione - 30 ore; • sviluppo della componente -20 ore; • verifica - 40 ore; • applicazione della componente SyncEngine al prototipo realizzato durante l’attività di studio - 5 ore.

realizzazione della documentazione finale : stesura di un manuale contenente le best practice apprese durante l’attività di studio, e le conoscenze maturate con la creazione della compo- nente di sincronizzazione. Sarà inoltre predisposta una breve introduzione alla logica di funzionamento di SyncEngine - 30 ore.

Come si osserva, il piano realizzato si attesta perfettamente sulle 320 ore pattuite con l’azienda ospite.

1.5 conoscenze di partenza

All’inizio dello stage, in merito alle conoscenze necessarie e affini con le attività da svolgere, posso dire di aver soddisfatto i seguenti pre-requisiti:

• conoscenza di alcuni strumenti utilizzati, come ad esempio Eclip- se, maturata nel tempo con l’uso dello stesso e mediante la lettura di articoli in internet;

• conoscenza di base delle tecnologie web: CSS3, HTML5, Java- Script e AJAX;

• conoscenza delle tecniche di approccio ingegneristico alla realiz- zazione di software, apprese durante il corso di Ingegneria del Software e maturata mediante lo svolgimento del progetto My- Talk4 dello stesso corso. Ciò include conoscenze sugli strumenti di analisi del problema e comunicazione con il cliente (diagram- mi UML), tecniche di progettazione, verifica e validazione del prodotto software.

4 Applicazione web per il real time comunication mediante libreria WebRTC. 8 informazioni sullo stage

1.6 problematiche affrontate

L’attività di stage mi ha portato ad affrontare diverse problematiche legate principalmente alla non familiarità con i framework utilizzati. Al momento in cui ho iniziato lo stage, non avevo nessuna conoscenza Conoscenze di: mancanti. • Sencha Touch;

• PhoneGap;

• sviluppo di applicazioni ibride.

• sviluppo di applicazioni per Andorid

Inoltre durante lo stage stesso sono emerse le seguenti problemati- che (di cui darò una trattazione maggiore nella seconda e terza parte Problematiche della tesi): emerse. • alcuni problemi legati all’uso degli strumenti di sviluppo come: mancanza di plugin free per Eclipse, in grado di aiutare nella stesura del codice Sencha, oppure problemi di configurazione dei virtual device android;

• errori riscontrati sulla documentazione utilizzata durante lo stu- dio (metodi segnalati come privati nella documentazione Sen- cha che invece erano pubblici e limitazioni di alcuni strumenti non presenti nella realtà). Questi hanno rallentato in parte il lavoro richiedendo una ricerca più attenta e in alcuni casi la verifica pratica di quali fossero realmente le potenzialità dello strumento in esame.

• assenza di informazioni dettagliate sull’uso di alcuni strumenti, nella documentazione di Sencha;

• problemi legati alla mancanza di uno strumento di archiviazio- ne che soddisfacesse le richieste aziendali, e che ha richiesto lo studio e la progettazione di una componente atta a sopperire a tali mancanze;

• necessità di sviluppare un prototipo di applicazione Sencha per testare le funzionalità di PhoneGap, di Sencha stesso (in parti- colare in relazione ai sistemi di archiviazione e di rilevazione della connettività) e del calo di prestazioni di un’applicazione cosi creata su dispositivi di tutte le fasce;

• nella progettazione di cui ho accennato al punto precedente, mi sono scontrato con la particolarità del dominio tecnologico che non essendo del tipo OOP, ha ostacolato in parte l’uso di alcuni pattern di progettazione architetturale e l’impiego delle tecniche tipiche della programmazione orientata agli oggetti; 1.7 competenze acquisite 9

• l’attività di progettazione ha richiesto alcune modifiche a po- steri, dovute all’emergere di nuove potenzialità degli strumenti usati;

• durante la progettazione della componente sono emersi proble- mi legati alla risoluzione dei seguenti punti: – gestione delle chiavi primarie utilizzate in un database di- stribuito su più dispositivi; – gestione dei dati presenti in locale su di un dispositivo e non inviati al server centrale;

• uno dei problemi che più hanno condizionato la progettazione e il successivo sviluppo della componente, è stata la mancan- za delle mutua esclusione in JavaScript, malgrado la possibilità di eseguire più processi paralleli. Ciò ha complicato notevol- mente il lavoro nella gestione degli eventi e nell’interazione che l’interfaccia grafica ha con la logica di sistema.

• problemi legati alla configurazione dell’apparato di test, e alla progettazione di test mirati a rivelare la presenza di errori.

1.7 competenze acquisite

Lo stage mi ha aiutato a consolidare le mie basi di conoscenza sul- le tecnologie web. Inoltre ho imparato ad usare Sencha e PhoneGap comprendendo nel frattempo cosa voglia dire sviluppare applicazio- ni ibride. Ho incrementato la mia conoscenza legata alle competen- ze ingegneristiche sull’analisi delle problematiche e la progettazione di componenti riutilizzabili. Ho incrementato le mie conoscenze su diverse tecniche di analisi (sia statica che dinamica) di applicazioni basate su JavaScript. Ho potuto affrontare e risolvere delle problema- tiche legate alla progettazione di database distribuiti in ambito mobile e non.

UNAPANORAMICASULLOSVILUPPOMOBILE 2

2.1 gli attuali sistemi operativi

Negli ultimi anni la nascita e il diffondersi dei dispositivi touch screen portatili, ha letteralmente cambiato il mercato del settore tecnologi- co, e di conseguenza il mercato dell’informatica. La distribuzione di apparecchi sempre più sofisticati e alla portata finanziaria dell’uomo medio, hanno dato il via ad una spinta competitiva tra i grandi co- lossi del settore, che oggi più che mai cercano di conquistare sempre più l’utenza predisponendo applicazioni e sistemi operativi all’avan- guardia. Ciò che tali strumenti ci permettono di ottenere si si può sintetizzare in due punti:

• applicazioni portabili, che non richiedono l’uso di un dispositi- vo fisso;

• esperienze d’utilizzo più rapide, intuitive e in grado di coinvol- gere l’utente.

In un tale contesto risulta evidente l’interesse che le aziende hanno per il mercato dello sviluppo mobile. Prima di analizzare in dettaglio i processi di creazione di queste app è importante comprendere i sistemi operativi su cui queste si basano. Oggi giorno infatti il mercato dei dispositivi mobili è ricco di alternative e competizione tra le varie case produttrici. Nello specifico troviamo: I principali sistemi operativi per • Android: si caratterizza per la struttura open source (escluse al- dispositivi cune versioni intermedie), e il suo basarsi su kernel Linux. La smartphone e tablet. caratteristica open source ed il tipo di licenza (Licenza Apache) permette di modificare e distribuire liberamente il codice sor- gente. Inoltre, Android dispone di una vasta comunità di svilup- patori che realizzano applicazioni con l’obiettivo di aumentare le funzionalità dei dispositivi. Queste applicazioni sono scrit- te soprattutto con una versione modificata del linguaggio di programmazione Java;

• iOS: sistema sviluppato da Apple come derivazione di UNIX (famiglia BSD) e usa un microkernel XNU Mach basato su Dar- win OS. iOS ha quattro livelli di astrazione: il Core OS layer, il Core Services layer, il Media layer e il Cocoa Touch layer. Il si- stema operativo occupa meno di mezzo gigabyte della memoria interna del dispositivo;

11 12 una panoramica sullo sviluppo mobile

• Windows Phone 8: sistema sviluppato da Microsoft, basato sul kernel Windows NT, lo stesso utilizzato da Windows 8 anche se leggermente modificato in parte. Lo sviluppo di app native per le piattaforme aventi tale sistema, richiede la conoscenza di linguaggi quali il C++ e C#;

• Symbian: è l’erede del sistema operativo EPOC, nella sua incar- nazione EPOC32, creato dalla Psion alla fine degli anni novanta per la sua linea di palmari. Adottato in seguito da Sony Erics- son per il modello P800, arriva alla massima notorietà grazie all’adozione del sistema da parte di Nokia. Ormai altamente superato da Android, iOS e Windows Phone 8, sta andando in rapido declino.

• BlackBerry OS: sviluppato da Research In Motion per la sua li- nea di smartphone BlackBerry, il sistema operativo è attualmen- te alla decima versione (presentata il 30 gennaio 2013). Come il sistema Symbian anche BlackBerry sta conoscendo un periodo di decrescita a causa dell’oligopolio dei colossi del settore.

Il sistema più diffuso Se volessimo definire una classifica dei sistemi operativi più diffusi, è Android, seguito al primo posto troveremo Android, con quote di mercato che in alcu- da iOS e Windows ni Paesi (vedi Germania) superano il 70%. Al secondo posto troviamo Phone 8. iOS e al terzo Windows Phone 8. Appaiono decisamente in declino le quotazioni di RIM e Symbian, praticamente azzerate anche in quei mercati (come quello statunitense) dove fino a non molto tempo fa erano considerati leader. In Figura 3 propongo uno schema riassunti- vo delle percentuali di distribuzione. I dati forniti sono stati ricavati dal gruppo Kantar Group e riguardano un rapporto tra le percentuali del 2012 e quelle del 2013 [3, “Apple share rebounds in Britain as iPhone 4 pulls in smartphone first-timers” ]: 2.1 gli attuali sistemi operativi 13

Figura 3: Resoconto distribuzione dei sistemi operativi mobile [3, “Apple share rebounds in Britain as iPhone 4 pulls in smartphone first-timers” ] 14 una panoramica sullo sviluppo mobile

Nuovi sistemi Inoltre è interessante osservare che in questi primi mesi del 2013 si operativi. è osservato il nascere di 3 nuovi sistemi operativi:

• Tizen 2.0: sistema operativo di Samsung che getta le proprie fon- damenta su quel che rimane di positivo delle esperienze Bada e Meego e nasce principalmente per far fronte a due particolari esigenze createsi in casa del gigante coreano: – dover far fronte all’acquisizione di Motorola da parte di Google, con tutte le conseguenze che ne derivano; – coniugare l’esigenza di creare una piattaforma software user friendly ma capace di poter girare su smartphone, tablet pc e smart TV, settore nel quale Samsung primeggia;

• Firefox OS: è un sistema operativo open source basato su ker- nel Linux sviluppato da Mozilla. L’idea alla base è quella di avere il software disponibile sul dispositivo come una applica- zione web usando le tecniche avanzate di HTML5 e le API del dispositivo per accedere direttamente all’hardware dello stesso con JavaScript;

• Ubuntu Phone OS: sistema operativo basato sulla distribuzio- ne Linux di Ubuntu, la cui interfaccia grafica è pensata per re- galare un esperienza simile a quella della versione PC. Le app su Ubuntu Phone OS possono essere scritte in due modi: in HTML5, nuova tecnologia che permette agli sviluppatori di tra- sferire facilmente un’app scritta per il Web sul telefono, o nati- vamente, cioè scriverla direttamente per Ubuntu Phone OS (o Ubuntu e poi convertirla). I linguaggi supportati, per ora, so- no C/C++, QML e Javascript per l’interfaccia grafica. Inoltre si possono usare nativamente le OpenGL, librerie grafiche che permettono di sviluppare giochi ed effetti tridimensionali.

Un mercato cosi ricco di alternative suggerisce quindi il potenziale vantaggio derivante da un sistema di sviluppo cross-platform. Ciò giu- stifica l’interesse aziendale per le tecnologie che si spingono in tale direzione. Inoltre è interessante osservare come i nuovi sistemi Fire- fox OS e Ubuntu Phone OS abbiano riconosciuto le potenzialità legate allo sviluppo di applicazioni ibride basate sulle tecnologie web.

2.2 approcci di sviluppo

Tipologie di sviluppo Oggi giorno esistono tre modi per sviluppare applicazioni per dispo- mobile. sitivi mobili:

• sviluppo ad hoc di un’applicazione mediante il linguaggio nati- vo;

• sviluppo di una web app fruibile da internet; 2.2 approccidisviluppo 15

• sviluppo di un’applicazione ibrida mediante l’uso delle tecnolo- gie web. Per meglio comprendere le sostanziali differenze esistenti tra que- sti due processi di sviluppo, andiamo a valutarne in dettaglio i pro (segnalati con il simbolo+) e i contro (indicati con il simbolo-): sviluppare con il linguaggio nativo : si tratta di progettare e sviluppare un’applicazione per una piattaforma ben defini- ta, usando il linguaggio nativo predisposto dal produttore (e.g. Java per piattaforme Android). + Comporta la possibilità di ottimizzare l’applicazione, for- nendo una soluzione stabile in grado di sfruttare la batteria e le risorse del device; + per il punto precedente risultano essere la soluzione mi- gliore nel caso di sviluppo di videogiochi; + fatta eccezione per alcune applicazioni, con scopi pretta- mente legati al web, le altre app sono fruibili senza l’obbli- go della connettività; - richiede la conoscenza di ogni linguaggio nativo, corrispon- dente alla piattaforma su cui desideriamo rendere disponi- bile l’app; - sviluppare l’applicativo per più piattaforme comporta un maggior investimento di tempo, denaro e risorse umane, poiché richiede la riscrittura completa del codice; - il look & feel dell’applicativo è vincolato dalla piattaforma per la quale lo rendiamo disponibile. sviluppare mobile web app : comporta la realizzazione di un’ap- plicazione internet-enabled che può essere fruita da un dispositi- vo mobile tablet o smartphone. Tali app sono accessibili tramite il browser del dispositivo e non hanno bisogno di essere scaricate e installate sul dispositivo (permette di minimizzare il TOC). + Con un unico sviluppo si rende disponibile l’applicazione per tutti i device mobili (aventi un browser), e contempora- neamente anche per i dispositivi fissi; + sono immediatamente disponibili agli utenti tramite un browser e non necessitano di essere scaricate ed installate; + sono più facili da aggiornare rispetto alle app con linguag- gio nativo, che richiedono un aggiornamento fisico dell’ap- plicazione installata nel device; + le web app sono facilmente condivisibili tramite un sem- plice link (ad esempio all’interno di un messaggio di posta elettronica o di testo, Facebook o Twitter post) mentre in- vece un’applicazione non può essere condivisa in questo modo; 16 una panoramica sullo sviluppo mobile

- richiedono sempre la presenza di connettività; - sono soggette ai problemi di rete; - sono più lente delle applicazioni con linguaggio nativo. sviluppare applicazioni ibride : si tratta di realizzare applica- zioni con le tecnologie web HTML5, JavaScript e CSS3. Questi strumenti sono comunemente interpretabili da ogni piattafor- ma mobile, ma necessitano di un “nucleo” che permetta loro di interagire con il dispositivo. + Sono presenti diversi framework in grado di facilitarci il lavoro; + permettono di sviluppare cross-platform (multipiattaforma); + se si dispone già di una web application, eseguire il por- ting della medesima su dispositivi mobili risulta semplice e veloce (ma in genere richiede la revisioni dell’interfaccia grafica); + fatta eccezione per alcune applicazioni, con scopi pretta- mente legati al web, le altre app sono fruibili senza l’obbli- go della connettività; - le applicazioni ibride utilizzano dei framework, delle spe- cie di ponti, per interagire con il sistema nativo (e.g. Phone- Gap). Se la piattaforma nativa introduce un aggiornamento con delle nuove funzionalità che si vorrebbero subito sfrut- tare, bisogna invece aspettare anche l’aggiornamento del framework; - l’uso dei framework menzionati al punto precedente com- porta un consumo maggiore delle risorse hardware, con un ovvio degrado (particolarmente visibile su dispositivi di fascia medio-bassa) delle prestazioni. - un’applicazione ibrida può essere testata mentre è anco- ra una web application, dal proprio browser, mediante stru- menti come Jasmine. il porting sulle piattaforme mobili com- porta però la necessità di prendere visione del comporta- mento che l’app ha sulla piattaforma in esame. Quindi più piattaforme supportate comportano maggiori sforzi in fase di testing.

Condizioni per la Come si osserva, entrambi gli approcci di sviluppo presentano di- scelta di un tipo di versi vantaggi e svantaggi. Principalmente la scelta è condizionata sviluppo. da: • scopo e tipo di applicazione; • targhet dell’applicazione (inteso come piattaforme su cui render- la fruibile); • tempi e risorse aziendali spendibili nella creazione dell’app. 2.3 validità delle applicazioni ibride 17

2.3 validità delle applicazioni ibride

Quando ci proponiamo di realizzare un’applicazione ibrida, è eviden- te che il punto centrale al quale siamo interessati (il vero vantaggio d’implementazione) è il cross-platform. Sviluppare per diverse piatta- forme, contenendo le spese e apprendo le porte a più utenza possibile, è sicuramente un obbiettivo importante per ogni azienda informatica. Ciò che bisogna domandarsi è: l’applicativo sarà usabile malgrado la non ottimizzazione del codice? L’utente moderno è sempre alla ricerca di applicazioni stabili che riescano a compiere il proprio dovere senza influire troppo sulla bat- teria e regalando un esperienza immediata e veloce. Per meglio capire l’applicabilità di tali applicazioni nel contesto di sviluppo aziendale, rifacciamoci al caso di studio proposto alla sezione “Scopo del tiroci- nio”. Nell’esempio proposto sono presenti i seguenti punti essenziali: Considerazioni sul caso di studio. • la tipologia di device ai quali siamo interessati sono i tablet. Di- spositivi decisamente più potenti degli smartphone, e aventi un display più grande: buono per applicazioni con un interfaccia più elaborata;

• l’ambito applicativo è quello dei gestionali. Ciò da una parte suggerisce la necessità di una certa quantità di memoria, ma dal- l’altra ci assicura l’assenza di effetti grafici (a meno di particola- ri richieste dell’utenza) tali da comportare un uso spropositato dell’hardware disponibile.

Queste considerazioni hanno portato l’azienda ospite a pensare che un approfondimento del dominio tecnologico costituisca un buon investimento, poiché le applicazioni ibride potrebbero (nel caso in esame) costituire una scelta valida tra le metodologie di sviluppo.

2.4 un’anticipazione delle conclusioni

Nel mio continuo leggere articoli sull’argomento, al fine di capire realmente quanto tali strumenti siano affidabili e da considerarsi co- me una soluzione valida, mi sono imbattuto in un articolo il cui au- tore, Daniele Pizzoni, sottolinea i difetti legati al calo di prestazioni Le applicazioni facendo le seguenti conclusioni: ibride inducono un calo delle Quindici anni fa Java promise di essere il linguaggio che prestazioni. avrebbe risolto definitivamente il problema di cui ci stiamo oc- cupando, in modo non ibrido ma universale: scrivi una volta ed esegui dappertutto. A quindici anni di distanza, nonostante Swing possa in teoria produrre applicazioni esteticamente indistinguibili dalle native su Mac, PC, Linux, Java è molto utilizzato sui server e quasi 18 una panoramica sullo sviluppo mobile

nulla sui client. Ironicamente viene usato per uno scopo antipo- dale (dall’altra parte del cavo) rispetto a quello per cui era stato concepito. I motivi sono gli stessi che stiamo dibattendo qui: una idea bella in teoria che in pratica non funziona abbastanza bene da essere praticabile.

[...]

A volte la ricerca di un silver bullet nasce da ottime intenzio- ni. La tecnologia serve a eliminare il lavoro noioso. Il problema è che le applicazioni ibride nascono con una buona idea per risol- vere il problema sbagliato: ”Come fare meno fatica?” invece che ”Come consegnare il miglior prodotto?”. I prodotti di eccellenza richiedono più lavoro. Richiedono dedizione, attenzione al detta- glio, e la messa in discussione delle proprie capacità abituali. Le scorciatoie sono solo una distrazione.

tratto da [4, “Applicazioni ibride per iphone, android e blac- kberry” ]

Le applicazioni Sotto questo punto di vista, non posso che essere d’accordo. Gli ibride velocizzano i strumenti di cui mi accingo a parlare, nascono con lo scopo di fa- tempi di sviluppo, a cilitare il lavoro di sviluppo e di assicurare all’azienda che gli usa, discapito delle performance. una maggior copertura dell’utenza, con un ovvio aumento (potenzia- le) degli introiti. Tuttavia ciò si ripercuote come un vantaggio per chi vende e non per chi compra. Con questo non voglio bocciare tali tecnologie ma ci tengo a sot- tolineare che per il momento, esse non possono essere pensate come una risposta standard per ogni richiesta del mercato delle mobile ap- plication. In linea generale, e come riproporrò nello conclusioni (con prove a conferma di ciò), questo approccio è valido solo per svilup- pare applicazioni per device di fascia medio-alta e nello specifico per tablet.

2.5 dominio tecnologico

Come già detto, alla base dello sviluppo di applicazione ibride c’è la conoscenza delle moderne tecnologie web. Nello specifico JavaScript e HTML5 vengono usati per sviluppare interamente l’applicazione, mentre i fogli di stile CSS3 sono usati per definire il look & fell. Dovendo comunicare con un server è importante avere una buona conoscenza anche della tecnologia AJAX. Anche se i framework di sviluppo ci permettono di sviluppare molto più velocemente usan- do strumenti più evoluti, una conoscenza di base di questi strumenti risulta essere indispensabile. 2.5 dominio tecnologico 19

2.5.1 HTML5

HTML (HyperText Markup Language) è un linguaggio per la costru- zione di ipertesti, ed appartiene alla famiglia dei linguaggi SGML. L’HTML5 (sua ultima evoluzione) è un linguaggio di markup per la strutturazione delle pagine web. Lo sviluppo venne avviato dal grup- po di lavoro Web Hypertext Application Technology Working Group (WHATWG) (fondato nel 2004 da sviluppatori appartenenti ad Ap- ple, Mozilla Foundation e Opera Software) che si pose come obiettivo quello di progettare specifiche per lo sviluppo di applicazioni web, fo- calizzandosi su miglioramenti e aggiunte ad HTML e alle tecnologie correlate. Attualmente HTML5 è ancora in fase di sviluppo. Il World Wide Web Consortium ha annunciato che la prima versione dello standard sarà pronta per fine 2014 e l’.1 per il 2016; la prima Candidate Recommendation è stata pubblicata dal W3C il 17 Dicembre 2012. Caratteristiche introdotte dall’HTML5: Feature di HTML5.

• vengono rese più stringenti le regole per la strutturazione del testo in capitoli, paragrafi e sezioni; • vengono introdotti elementi di controllo per i menu di naviga- zione; • vengono migliorati ed estesi gli elementi di controllo per i mo- duli elettronici; • vengono introdotti elementi specifici per il controllo di contenu- ti multimediali (tag

2.5.2 JavaScript

JavaScript è un linguaggio di scripting client-side comunemente usato nella realizzazione di siti web e web application. Sviluppato nel 1995 da Netscape (a cui successivamente si aggiunge Sun Microsystems), nasce con il nome LiveScript e viene standardizzato per la prima vol- ta tra il 1997 e il 1999 dalla ECMA con il nome ECMAScript. L’ulti- mo standard, di marzo 2011, è ECMA-262 Edition 5.1. È anche uno standard ISO. Contrariamente a quanto suggerisce il nome, JavaScript non è un sottoinsieme del linguaggio Java. Infatti mentre quest’ultimo è un linguaggio orientato agli oggetti, JavaScript non lo è. JavaScript supporta gli oggetti ma non le classi. Esso non permette l’utilizzo ne dell’ereditarietà ne del polimorfismo. Non è possibile definire metodi astratti ne interfacce. Un sistema analogo a quello dell’Information Hiding è definibile mediante il module pattern, di cui si da una rappresentazione in appendice (“module pattern”). A differenza di Java, non richiede la dichiarazioni delle variabili e permette una tipizzazione dinamica. Tra le caratteristiche più utili di JavaScript vi è il Document (DOM), che permette agli script JavaScript di avere accesso ai contenuti e ai widget del documento HTML in cui sono contenuti.

2.5.3 CSS3

Il CSS (Cascading Style Sheets o Fogli di stile) è un linguaggio in- formatico usato per definire la formattazione di documenti HTML, XHTML e XML ad esempio in siti web e relative pagine web. Un foglio di stile è un insieme di regole che indicano il tipo di formatta- zione da applicare. Essi consentono di avere il pieno controllo degli aspetti visivi delle pagine web separando presentazione da struttura. Ci sono tre diverse versioni:

css1 : completamente supportato da quasi tutti i browser a partire dalla versione 4 (Netscape) o 3 (Internet Explorer);

css2 : supportato bene da FireFox, Opera e IE 7 (con qualche proble- ma in IE 6);

css3 : poco supportato da tutti i browser (Chrome e ).

2.5.4 AJAX

AJAX (Asynchronous JavaScript and XML) è una tecnologia per lo sviluppo di applicazioni web interattive (Rich Internet Application). Il vantaggio derivante dall’uso di AJAX sta nella possibilità di aggiorna- re dinamicamente la pagina web (con cui lo script interagisce) senza 2.5 dominio tecnologico 21 chiedere il ricaricamento della pagina stessa. Ciò è possibile proprio perché le richieste inoltrate in background al server sono asincrone. AJAX è una tecnica multi-piattaforma utilizzabile cioè su molti si- stemi operativi, architetture informatiche e browser web, ed esistono numerose implementazioni open source di librerie e framework. La tecnica AJAX utilizza una combinazione di:

• HTML (o XHTML) e CSS per il markup e lo stile;

• DOM () manipolato attraverso un lin- guaggio ECMAScript come JavaScript o JScript per mostrare le informazioni ed interagirvi;

• l’oggetto XMLHttpRequest per l’interscambio asincrono dei da- ti tra il browser dell’utente e il web server. In alcuni framework AJAX e in certe situazioni, può essere usato un oggetto Iframe invece di XMLHttpRequest per scambiare i dati con il server e, in altre implementazioni, tag

Quando si inietta tale tag, il browser effettua una richiesta per all’url e include la risposta, come se si trattasse di qualsiasi altro tipo di JavaScript include. Passando un callback all’url, stiamo dicendo al server domainB che vogliamo essere avvisati quando il risultato sarà ritornato, e che per farlo dovrebbe richiamare la nostra funzione di callback con i dati che dovrà restituirci. JSON proxy si occupa automaticamente di tutto questo. Egli si crea una funzione di callback temporanea, che aspetta (per conto del proxy) di essere chiamata. Quindi, quando ciò avviene, inserisce i dati nel proxy, facendo sembrare il tutto come se si trattasse di un normalissimo proxy AJAX.

ext.data.proxy.rest : è una specializzazione dell’AJAX proxy. For- nisce una mappatura delle operazioni CRUD in relazione ad un RESTful web service.

5.5.4 MyApp.Proxy.MyCustomProxy

Come riportato nell’articolo: [10, “How to implement and use a custom proxy” ], le basi della personalizzazione di un proxy sono semplici e non richiedono grandi sforzi. Per iniziare, è sufficiente scrivere il “define” del proxy assicurandosi di ereditare direttamente (o indiret- tamente) la classe Ext.data.proxy.Proxy. Quindi è necessario creare un alias con cui riutilizzare agevolmente il proxy. A questo punto è possibile aggiungere i metodi o i campi dati necessari al proprio scopo. Per riutilizzare il proprio CustomProxy, sarà sufficiente riferirsi a lui, riportando nel campo proxy (dello store o del model associato) l’alias definito in precedenza. Si ricorda infine che tutte le classi, non appartenenti al set di classi di Sencha, per essere utilizzate devono prima essere incluse. Tale operazione avviene per mezzo del comando “requires”. Come sempre un esempio vale più di mille parole:

Listing 5: CustomProxy 5.6 fireevent: una gestione intelligente degli eventi 49

Ext.define( ’MyApp.proxy.MyCustomProxy’,{ //Importate! extend: ’Ext . data .proxy.Proxy ’,

5 // impostare il proprio alias per un uso piu’ agevole del proxy alias: ’proxy.mycustomproxy’,

... });

Listing 6: Un esempio di uso di MyCustomProxy

1 Ext.define( ’MyApp.model.Image’,{ extend: ’Ext.data.Model’,

//Importante! Aggiungere sempre il require delle proprie classi, non appartenenti al set delle classi di Sencha. requires: [ ’MyApp.proxy.MyCustomProxy’], 6 config: { fields: [ ’name’],

proxy: { 11 //impostare come type del proxy,l’alias dichiarato nel define type: ’mycustomproxy’ } } });

5.6 fireevent: una gestione intelligente degli eventi

In un ottica di programmazione basata su pattern architetturale MVC, la vista è svincolata dal conoscere le regole di business attuate per modificare i dati in relazione al verificarsi di un determinato evento. Infatti dovrebbe essere compito del controller mettersi in “ascolto”, su delle view di cui è responsabile, ed essere pronto a catturare gli eventi sollevati dai componenti delle view. Quindi il controller potrà associare agli eventi il giusto handler, per la risoluzione del medesimo. Sencha permette di gestire tale procedura nel seguente modo: Iter di gestione degli eventi con un 1) si definisce un controller (in generale diciamo uno per ogni controller. view), e si dichiarano le viste su cui dovrà mettersi in ascolto;

2) quindi per ogni evento particolare, legato all’interazione dell’u- tente con un componente della view, si definisce una “delega” in un listener della vista (ciò avviene nella view stessa) il cui compito sarà delegare l’evento ad un handler appropriato. la fun- zione handler avrà poi il compito di sollevare un nuovo evento 50 best practice

(convenzionalmente nominabile come “comamand”) mediante l’istruzione fireEvent. Si osservi che in questa ottica la view non conosce direttamente chi la osserva, il che rende il codice molto più mantenibile. Analoga conclusione vale per il fatto che cosi facendo vi è una completa divisione tra logica e grafica;

3) a questo punto di può tornare sul controller e dichiarare che la view x, su cui il controller è in ascolto, può sollevare l’evento y e che tale situazione si risolve delegando la gestione dell’evento ad una funzione appositamente creata. In linea generale se l’o- perazione riguarda la manipolazione di alcuni dati sensibili, ciò dovrebbe avvenire richiamando i metodi definiti nel model.

Per completezza riporto di seguito un esempio. Esempio di vista con gestione di eventi. Per prima prenderò in considerazione una vista. In merito si osser- vi che:

A) è presente un listener che definisce le associazioni evento-componente- handler;

B) è presente un handler associato all’evento tap del bottone;

C) l’handler non fa altro che sollevare un nuovo evento tramite metodo fireEvent.

Listing 7: Gestione degli eventi - sollevare un evento con fireEvent

//Vista NotesList -> rappresenta una lista di note. contiene un bottone NewNote il cui scopo consiste nell’effettuare una transizione verso la vista NoteEditor

Ext.define( ’NotesApp.view. NotesList ’, { 5 extend: ’Ext.Container’, requires: [ ’Ext .dataview. List ’], alias: ’widget.notesListView ’,

config: 10 { ... items: [ { 15 xtype: ’toolbar ’, docked: ’bottom ’, items: [ { xtype: ’spacer ’ }, 20 { xtype: ’button ’, 5.6 fireevent: una gestione intelligente degli eventi 51

itemId: ’ newButton’, text: ’New Note’, ui: ’ action ’ 25 }, { xtype: ’spacer ’ } ] }, ... 30 ] ...

//Listeners: usato per mettere la vista in ascolto di se stessa.L’idea consiste nel catturare gli eventi del tipo"iterazione dell’utente con le componenti della view" listeners: 35 [ { //componente da"ascoltare" identificato mediante id delegate: ’#newButton’, //tipologia di evento da" catturare" 40 event: ’tap ’, //funzione"handler" per la risoluzione dell’evento fn: ’onNewButtonTap’ }, ... 45 ] },

//------FireEvent------

50 //Handler di#newButton- evento: tap onNewButtonTap: function() { console.log( ’newNoteCommand’); //Sollevol’evento newNoteCommand 55 this.fireEvent( ’newNoteCommand’, this); },

... }); Esempio di Per completare l’esempio, riporto anche il codice commentato del controller. controller. Qui voglio mettere in evidenza i seguenti punti:

A) il controller definisce una lista refs delle viste su cui restare in ascolto; 52 best practice

B) il controller definisce, in una zona detta control, le coppie nome evento - command da richiamare;

C) al termine del listato compaiono i command da richiamare per processare la richiesta inoltrata in principio dall’iterazione uten- te - componente della vista.

Listing 8: Gestione degli eventi - controller

1 //Controller Notes -> controller della vista

Ext.define( ’NotesApp. controller .Notes ’, { extend: ’Ext.app.Controller ’, 6 config: { //refs usato per tracciarei riferimenti nomeVista-aliasUsatoNelController refs: { 11 //stabilisco che questo controller osserva gli eventi lanciati dall’ oggetto xtype= noteListView notesListView: ’notesListView ’, ... },

16 //parte di controller. Per ogni vista gestita dal controller, definisce le coppie nomeEventoDaCatturare- nomeHandlerDelController control: { notesListView: { 21 //definisco la lista degli eventi che possono essere lanciati (mediante fireEvent) dall’ oggetto che sto osservanto( xtype: notesListView) newNoteCommand: ’onNewNoteCommand ’, ... /*this ref automatically creates a getNoteEditor() function in the controller, which we can use to refer to the NoteEditor instance and make it the active View in the application.*/ }, 26 ... 5.7 gestire il multi-tap 53

} },

//------LISTA DEI COMANDI------31 //comando associato all’evento newNoteCommand dell’ oggetto notesListView. onNewNoteCommand: function() { //istruzioni per risolverel’evento. Nel caso, si tratta di istruzioni per creare una nuova nota vuota, ed effettuare uno shift di navigazione, alla view contenentel’editor di note. 36 }, ... });

5.7 gestire il multi-tap

Come si può vedere dall’esecuzione di una qualsiasi app di Sencha, questo sono realizzate in modo tale da non provocare un blocco del- l’interfaccia in seguito all’esecuzione di un comando dovuto alla pres- sione di un bottone. Cosi facendo l’utente ha la possibilità di navigare nell’interfaccia, mentre in background vengono svolte le operazioni da lui richieste. Ciò è possibile mediante un sistema di gestione degli eventi. Infatti quando premiamo, o se preferite, quando eseguiamo un tap su di un Ext.Button, viene generato un evento che sarà cattu- rato da un handler da noi specificato. Questo sistema rende quindi asincrona ogni richiesta da noi fatta al sistema per mezzo di una componente grafica. Un problema legato A questo punto molti sviluppatori non si avvedono di un poten- al multi-tap. ziale problema di stabilità dell’applicativo. Se supponiamo l’utente di turno, per un qualche motivo, inizia a premere ripetutamente il pulsante A, questo provocherà una serie di fireEvent relativi all’e- vento tap che, catturati dall’handler, provocheranno l’esecuzione del blocco di codice designato. A ciò si aggiunge un ulteriore problema: JavaScript non gestisce la mutua esclusione. Non esistono quindi istruzioni atomiche da usare come “barriera di sincronizzazione”. Esempio di Considerando quanto detto, si pensi allo scenario: un bottone A ha parallelismo senza come handler associato una funzione di download che: mutua esclusione.

1) scarica i dati dal server;

2) cancella quelli locali;

3) salva i dati temporanei nello spazio di memoria locale. 54 best practice

In un tale contesto, se l’utente preme ripetutamente A, genererà diverse richieste di download. Un possibile risultato è che due pro- cessi eseguono in successione il passo 1) e il passo 2). A tal punto entrambi avrebbero cancellato due volte l’area di memoria locale, e si appresterebbero a sovrascriverci i dati dalla loro zona di memoria. Ciò provoca di conseguenza una ridondanza nei dati scaricati. Purtroppo l’incapacità di JavaScript di eseguire blocchi di codice in mutua esclusione (si badi bene, semplici barriere di tipo if con variabili booleane non sono sufficiente) rende il nostro codice debole Soluzione: bottoni e potenzialmente pericoloso. Per fortuna, in seguito ad una domanda con singletap. sul forum di Sencha, uno sviluppatore ha definito un Ext.Button in grado di accettare un unico tap in una serie di tap concatenati. Di seguito riportiamo il codice di tale componente.

Listing 9: org.s2.singleEventItem.button.SingleTapButton

2 Ext.define( ’org . s2 .singleEventItem.button.SingleTapButton’, { extend : ’Ext.Button’, xtype : ’stbutton ’,

7 initialize : function() { var me = this;

me.element.on({ scope : me, 12 singletap : ’onSingleTap ’, doubletap : ’onDoubleTap’ });

me.callParent(); 17 },

onSingleTap : function () { this.fireEvent( ’singletap’, this); }, 22 onDoubleTap : function () { this.fireEvent( ’doubletap’, this); } });

Ora invece vediamo come usare tale componente. Per prima cosa creiamo nella nostra vista un bottone avente come xtype, quello del nostro SingleTapButton. Una tale operazione si fa, per esempio, nel seguente modo:

Listing 10: Usare il SingleTapButton - definire il bottone

... 5.8 migliorare le performance di sencha 55

3 { xtype: ’stbutton ’, //ora il nostro bottone accettera’ il single tap. itemId: ’downloadButton ’, iconCls: ’download’, 8 iconMask: true, ui: ’ action ’, scope: this },

13 ...

Il passo successivo prevede di definire l’handler da associare. Con il sistema appreso nella sezione “FireEvent: una gestione intelligente degli eventi”, definiamo nella config della vista, un listener abilitato alla delega dell’evento singletap del nostro bottone:

Listing 11: Usare il SingleTapButton - listeners

1 listeners: [ ...

6 { delegate: ’#downloadButton ’, event: ’singletap’, fn: ’onDownload’ }, 11 ... ]

A questo punto basta definire la funzione onDownload, dalla quale genereremo un evento che sarà catturato da un apposito controller. Nel controller si definirà la parte di logica per la gestione dell’evento. Per prendere nota del dibattito presente sull’argomento nel forum di Sencha, si rimanda all’articolo: [15, “Multiple taps issue - BUG?” ].

5.8 migliorare le performance di sencha

Gli argomenti trattati in questa sezione si basano su di un mio studio condotto principalmente sull’articolo [26, “Sencha Touch Performance Tips and Tricks” ], a cui rimando per un approfondimento. Di seguito intendo trattare unicamente i punti più interessanti comparandoli con delle osservazioni personali emerse durante l’attività di studio e uso del framework. 56 best practice

5.8.1 Quando usare Sencha Touch 2

Come già detto, l’uso di Sencha Touch 2 per la creazione di app ibride necessita di un framework di appoggio (e.g. PhoneGap) per effettua- re il porting dell’app. Ciò comporta un utilizzo di risorse superiore Casi in cui si alle normali app native. Presupponendo che l’obbiettivo sia ottenere consiglia Sencha. un software di qualità (indifferentemente dai tempi e costi di svilup- po) possiamo concludere che Sencha è un’opzione valida solo nella realizzazione delle seguenti tipologie di app:

• applicazioni per la visualizzazione di notizie;

• applicazioni come rubriche o notes, richiedenti quindi una mi- nima quantità di informazioni. Casi in cui si sconsiglia Sencha. Invece se ne sconsiglia l’uso nei casi di:

• videogiochi o applicazioni con particolari effetti grafici;

• applicazioni che richiedono un certo costo computazionale.

5.8.2 Viewport dinamico

Spesso quando si inizia a studiare per la prima volta un linguaggio di programmazione, si è soliti affiancare allo studio teorico, anche la visione di codici sorgenti relativi ad applicazioni scritte da terzi. Cosi facendo ho potuto osservare come molti sviluppatori hanno la tendenza di definire e caricare immediatamente le proprie viste nel Caricamento viewport. Analizzando questa metodologia si osservano i seguenti immediato del vantaggi: viewport - vantaggi. • le viste/panelli sono caricati in memoria e pronti alla visualiz- zazione fin da subito;

• se si hanno poche viste, questo sistema risulta pratico e non comporta nessun degrado delle prestazioni. Caricamento immediato del Ciò però va a fronte dei seguenti svantaggi: viewport - svantaggi. • nel momento in cui le viste che compongono l’app iniziano ad aumentare sensibilmente, si noteranno diversi cali di prestazio- ne: – una risposta più lenta agli eventi associati al tap di un bottone; – uno scrolling più lento delle viste; – nel caso si usi un IDE come Xcode saranno segnalati dei warning legati alla gestione della memoria; 5.8 migliorare le performance di sencha 57

• il tempo richiesto per l’avvio dell’applicazione sarà decisamente maggiore. Ottimizzare i tempi Per far fronte a questi problemi ed operare un’ottimizzazione del- con caricamenti su la gestione della memoria, è consigliabile gestire il caricamento delle richiesta. viste dal viewport dinamicamente e su richiesta. Per fare ciò è ne- cessario predisporre un viewport contenente un’unica vista: l’home dell’applicativo. Quindi si necessità di un controller avente il compito di gestire il caricamento delle viste e la distruzione dei pannelli ob- soleti. Un approccio simile permette di evitare gli svantaggi del caso precedente. Ovviamente però si paga un prezzo:

• il sistema precedentemente descritto ha una complessità legger- mente maggiore;

• il sistema prenderà un po’ più di tempo per la creazione dinami- ca della vista. Stando a dei test condotti dall’autore dell’articolo, le tempistiche si aggirano tra i 40ms e i 300ms.

5.8.3 Migliorare lo scrolling

Per quanto possa sembrare banale lo scrolling di una lista rappresenta una componente importante nell’esperienza d’uso di un applicativo. Si pensi infatti a scorrere una lista in cui si osserva un certo rallenta- mento. Ciò in relazione alle applicazioni native (dove problemi del ge- nere non sono la norma), può risultare snervante e snaturare un con- cetto a cui l’utente moderno non solo è abituato, ma che addirittura da per scontato. Consigli per Le viste implementate mediante Sencha possono soffrire di que- migliorare lo sto problema in diversi casi. Ecco alcuni consigli utili per risolvere il scrolling. problema: sfumature ed altri stili css : è consigliabile cercare di evita- re sia le sfumature che le ombre all’interno delle liste. Piut- tosto è consigliabile usare un colore di sfondo privo di effetti particolari. Ciò contribuisce a migliorare la velocità di scrolling specialmente su iPhone; immagini ad alta risoluzione : se la lista necessita di visualiz- zare delle immagini allora è appropriato assicurarsi che le im- magini non siano eccessivamente grandi. Una risoluzione più bassa possibile contribuisce a migliorare i tempi di caricamento degli elementi; numero di elementi nella lista : un eccessivo numero di ele- menti da caricare comporta un calo delle prestazioni. Poiché generalmente le liste prelevano i dati da un Ext.data.Store, e consigliabile usare la proprietà pageSize dello stesso. Usando 58 best practice

i metodi nextPage e previusPage è possibile caricare i visualiz- zare dinamicamente solo un tot di elementi per volta. Con tale sistema la vista ospitante la lista sarà decisamente più semplice da caricare e lo scrolling (almeno inizialmente, ossia finché non si saranno troppi elementi) risulterà sufficientemente fluido. TESTAREUN’APPLICAZIONESENCHA 6

6.1 considerazioni generali sulla verifica

Purtroppo quando abbiamo a che fare con un programma, spesso ci si ritrova ad affrontare diversi problemi sgraditi, dovuti ad errori di progettazione o sviluppo. Per cercare di mitigare il più possibile tali problemi e effettuare delle correzioni prima del rilascio del software, è importante eseguire una buona attività di verifica. Esistono due La verifica si basa su due tipologie di analisi: tipologie di verifica. statica : è un tipo di controllo basato sulla non esecuzione del codi- ce, e in senso lato può essere applicato a qualsiasi tipo di prodot- to anche non propriamente eseguibile (ad es. la documentazio- ne di progetto). Sono previste, in particolare, due forme di anali- si statica: il controllo manuale (detto altrimenti “desk check”) e il controllo assistito da strumenti automatici. Per quanto concer- ne il desk check, cioè il controllo realizzato unicamente da parte di un agente umano, sono previsti due metodi formali: walkth- rough (esame ad ampio spettro) ed inspection (analisi mirata di una minima parte del prodotto). La seconda forma di analisi sta- tica prevede invece l’utilizzo di strumenti appositi denominati analizzatori statici e può essere svolta in modo semiautomatico senza richiedere necessariamente l’intervento di un umano (e.g. JSLint per prodotti JavaScript). dinamica : si basa su controlli dinamici (altrimenti definiti test) che prevedono l’esecuzione del software in un ambiente controllato e con dati di input specificatamente pensati per testarne le fun- zionalità e l’aderenza ai requisiti, mettendo in luce l’eventuale presenza di malfunzionamenti. Caratteristica fondamentale dei test è la loro ripetibilità, cioè dato lo stesso set di dati in ingres- so e nello stesso contesto di esecuzione, l’output deve essere deterministico e univocamente determinato. Tale proprietà, uni- tamente all’auspicabile utilizzo di un logger che ha il compito di registrare le fasi dell’esecuzione del test, consente di indivi- duare e riconoscere in maniera più agevole i difetti presenti nel prodotto. In base al loro ambito di applicazione, i test possono I test possono essere essere suddivisi in: suddivisi in 5 tipologie. • test di unità aventi come oggetto le singole unità e, oltre al modulo da verificare e ai dati d’esempio, possono coinvol- gere anche componenti attive (driver) o passive (stub) che

59 60 testare un’applicazione sencha

siano in grado di simulare le parti del sistema non ancora disponibili al momento in cui il test viene eseguito; • test di integrazione atti a verificare la corretta interazione e integrazione fra le componenti che costituiscono le parti del sistema e hanno come risultato una build , vale a dire un sottosistema funzionante che può essere eseguito in modo indipendente; • test di sistema, volti a testare il rispetto dei requisiti soft- ware individuati in fase di analisi dei requisiti da parte dell’intero sistema; • test di regressione destinati a rilevare il caso indesiderabi- le in cui una modifica locale destabilizza il resto del siste- ma, si tratta del numero minimo di test necessario per scon- giurare tale eventualità senza per questo dover ripetere in toto i test di unità e di integrazione; • test di accettazione, o collaudo, realizzato sotto la supervi- sione del committente per verificare l’aderenza del prodot- to ai requisiti utente di più alto livello.

Nei paragrafi successivi illustrerò delle soluzioni per entrambe le tipologie di analisi. Prima però desidero che il lettore abbia una co- gnizione maggiore dell’importanza dei test e di come questi debbano (se possibile) essere resi automatici al fine di rendere più pratica e Caratteristiche veloce tale attività. essenziali di un test. In particolare, nell’eseguire i test, è molto importante ricordare i seguenti punti:

• un test è utile solo se rileva degli errori;

• un test deve essere ripetibile;

• è impensabile (nei progetti di grosso calibro) credere di ottenere una copertura del 100% del codice;

La verifica mediante test è un’attività costosa. Per questo è impor- tante cercare di automatizzare le pratiche di testing il più possibi- le, predisponendo per lo sviluppatore un ambiente stabile che gli permetta di verificare il proprio codice dopo ogni modifica.

6.1.1 Pratiche avanzate di testing

Tra le pratiche più usate di test citiamo:

test driven development 1: in sigla TDD (in italiano: Sviluppo guidato dalle verifiche) è un processo di sviluppo del software

1 LA definizione è presa da [36, “Wikipedia - definizione TDD” ] 6.2 strumenti necessari 61

in cui lo sviluppo vero e proprio è preceduto e guidato (dri- ven) dalla stesura di test automatici. Il processo si articola sulla ripetizione di brevi cicli di sviluppo e collaudo (noti come “ci- cli TDD”, TDD cycles) suddivisi in tre fasi successive, sintetiz- zate dal motto “Red-Green-Refactor”. Nella prima (“Red”), il programmatore scrive un test automatico (che necessariamente fallisce) per la funzionalità da sviluppare. Nella seconda, il pro- grammatore scrive la quantità minima di codice necessaria per ottenere il superamento del test. Nella terza, il programmatore ristruttura il codice (ovvero ne fa il refactoring);

behavioural-driven development 2: nell’ambito dell’ingegne- ria del software, il behavior-driven development (abbreviato in BDD e traducibile in Sviluppo guidato dal comportamento) è una metodologia di sviluppo del software basata sul test-driven development (TDD). Il BDD combina le tecniche generali e i principi del TDD con idee prese dal domain-driven design e dal desing e all’analisi orientato agli oggetti per fornire agli svi- luppatore software e ai Business analysts degli strumenti e un processo condivisi per collaborare nello sviluppo software. Per quanto BDD sia principalmente un’idea di come lo svilup- po del software dovrebbe essere gestito sia da interessi di bu- siness e analisi tecniche, la pratica della BDD assume l’utilizzo di strumenti software specializzati per supportare il processo di sviluppo. Sebbene questi strumenti siano spesso sviluppati in particolare per essere utilizzati in progetti BDD, possono essere visti anche come delle forme specializzate degli strumenti che supportano la TDD.

6.2 strumenti necessari

Parte delle informazioni trattate in questo capitolo emergono da uno studio approfondito dell’articolo [5, “Automating Unit Tests” ], il qua- le è stato scritto appositamente per evidenziare le best practice di testing per applicazioni Sencha. Qui è riportata la lista completa de- gli strumenti necessari per una corretta configurazione dell’ambiente di lavoro.

• Node.js: è una piattaforma software usata per costruire delle applicazioni di rete scalabili (generalmente server-side). Node.js contiene una libreria server HTTP, con la quale può avviare un web server senza l’uso di software esterno(e.g Apache);

• JSLint: è un analizzatore statico di codice usato per validare la sintassi JavaScript usata su un determinato codice. Sviluppato

2 LA definizione è presa da [33, “Wikipedia - definizione BDD” ] 62 testare un’applicazione sencha

da era inizialmente fruibile mediante il web. Ora esiste anche una versione offline a linea di comando; • JSHint: è una variazione di JSLint, sviluppata dallo stesso Dou- glas Crockford con lo scopo di offrire un prodotto maggiormen- te personalizzabile. Come JSLint è stato inizialmente predispo- sto per l’uso online. Successivamente è stata sviluppata una sua distribuzione offline come modulo di Node.js; • LintRoller: tool che richiama JSLint e altri validatori per la sin- tassi JavaScript. Permette di validare tutti i file .js presenti in una certa directory; • Jasmine: framework per la creazione di unit test per codice JavaScript. Facile da usare e da eseguire, è ad oggi uno degli strumenti più usati per effettuare test su listati .js; • Siesta:

Purtroppo sottolineo che non tutti gli strumenti elencati sono stati usati durante lo stage. La causa di tale mancanza è da ricercare nel tempo limitato che avevo a disposizione.

6.3 syntax check

La prima tecnica da me presa in considerazione, rientra nel contesto Syntax check è una dell’analisi statica e prende il nome syntax check. Questa tecnica, che tecnica di analisi ritroviamo eseguita automaticamente nei linguaggi compilati (al mo- statica. mento della compilazione), ci permette di rilevare errori sintattici nel codice. JavaScript non essendo un linguaggio che richiede compilazio- ne, non offre la possibilità di individuare gli errori, se non eseguendo il codice stesso. Inoltre si osservi che a molti piccoli errori, è il bro- wser stesso a porre rimedio. Questo infatti è il caso dei “;” presenti al termine delle istruzioni JavaScript: se assenti il browser tenderà ad ignorare il problema. Per offrire uno strumento valido al fine di rileva- re ogni genere di errore, uno sviluppatore della Sencha.inc (lo stesso autore di [5, “Automating Unit Tests” ], Arthur Kay) ha ideato un pro- gramma eseguibile da shell, che data una directory principale e una lista di sotto-directory da escludere durante l’attività di check, si oc- LintRoller si basa cupa di esaminare ogni file con estensione .js usando il già esistente sul tool JSLint. tool JSLint3. Il tool è reperibile su GitHub4 con il nome di LintRol- ler. Prima di usare LintRoller è essenziale l’installazione di Node.js. Quindi si può procedere scaricando lo strumento e inserendolo nel- la directory di lavoro. Per usarlo si dovrà creare un file init.js in cui caricare le impostazioni necessarie per l’uso. Di seguito propongo il listato da me usato per il syntax check del mio applicativo.

3 ListRoller, alla versione attuale, è predisposto anche per usare JSHint. 4 Nello specifico trovate ulteriori informazioni nella voce bibliografica [39, “GitHub - ListRoller” ] 6.4 unit test 63

Listing 12: Syntax Check - esempio d’utilizzo

var LintRoller = require( ’ ./ test/node_modules/lintroller/ LintRoller’); 2 var config = { verbose : false, stopOnFirstError : false,

7 //root da cui avviare il check filepaths : [ ’ ./org/’ ],

12 //lista delle cartelle da ignorare durante il check exclusions : [ ],

//lista dei tool di appoggio per eseguire il check 17 linters : [ { type : ’ jsLint ’ }, { 22 type : ’ jsHint ’ }, { type : ’esprima ’ } 27 ] };

LintRoller.init(config);

Lo strumento usato è valido e funzionante. In pratica costituisce un automatismo basato su JSLint. Si raccomanda tuttavia di utilizzare l’ultima versione stabile del tool. Infatti l’autore sta lavorando allo strumento ancora oggi con l’obbiettivo di migliorarlo ulteriormente.

6.4 unittest

La seconda tipologia di test è atta a rilevare comportamenti anomali nelle componenti che costituiscono l’applicativo, prende il nome di unit test. Questa tecnica si basa sulla seguente considerazione: quan- do scriviamo del codice, lo facciamo sapendo già quali modifiche esso apporterà al sistema nei vari casi di esecuzione. Quindi il blocco di codice da testare avrà un suo valore atteso che non necessariamen- te sarà uguale al suo valore effettivo, ossia quello che rileviamo in fase di esecuzione. Tale anomalia è dovuta ad un nostro errore. I te- st di unità quindi, basandosi su un valore atteso, eseguono il blocco 64 testare un’applicazione sencha

di codice da testare e al termine verificano, con una certa tipologia di comparazione (uguale a, diverso da, maggiore di, ecc...) da noi specificata, se il valore ottenuto è conforme a quello atteso. Creare ed eseguire test di unità per sorgenti JavaScript è un’opera- zione eseguibile con diversi tool. Per la sua semplicità, per la chiarez- za di linguaggio e per le potenzialità offerte (e.g. facilitazioni nel test Jasmine è ad oggi di blocchi asincroni) ho deciso di prendere in considerazione Jasmine. uno dei framework Poiché una trattazione approfondita sulle basi di Jasmine esula dallo più usati per gli unit scopo di questa sezione si rimanda il lettore all’appendice “le basi test su JavaScript. di jasmine” , dove potrà trovare alcuni riferimenti alle funzionalità più interessanti di Jasmine. Di seguito parlerò delle best practice da adottare nel testing si Sencha, dando per scontata la conoscenza di Jasmine.

6.4.1 Configurare Jasmine per testare Sencha

Come prima cosa è importante configurare correttamente l’ambiente di lavoro. Inizialmente bisogna scaricare la versione stand-alone di Jasmine. Quindi si predispone una cartella per i test (/test/unitTest) in cui si dovrà inserire la libreria di Jasmine. Ora è essenziale seguire Jasmine - iter di i punti: configurazione. 1) definire all’interno della cartella /test/unitTest una cartella spec, dove si dovranno inserire i file .js che definiscono le test suit;

2) creare un file app-test.js da mettere nella stessa directory in cui si trova l’app.js dell’applicazione;

3) infine creare un file run-test.html. A questo punto bisogna scrivere il contenuto di app-test.js. Questo file rappresenta il punto centrale per il caricamento delle componenti da testare e per l’avvio del kernel di Jasmine. App-test.js può essere scritto nel seguente modo:

Listing 13: Template di app-test.js

Ext.application({ //elenco di modellie store necessari per il testing //Per esempio: models: [ ’Note’, ’Author ’], 5 stores: [ ’Notes ’],

requires: [ //elenco delle classi richieste perl’esecuzione del test. 10 //Per esempio: ’org . s2 .syncEngine.SyncManager’, ’org . s2 .syncEngine. basicSyncStore .download. DownloadStoreFactory ’, 6.4 unit test 65

’org . s2 .syncEngine. basicSyncStore .upload. CommitStoreFactory ’, ’org . s2 .syncEngine. basicSyncStore .storeCommand. AddCommit’, 15 ’org . s2 .syncEngine. basicSyncStore .storeCommand. UpdateCommit’, ’org . s2 .syncEngine. basicSyncStore .storeCommand. DeleteCommit’, ’org . s2 .syncEngine. basicSyncStore . SyncStore ’, ’NotesApp.model.Author ’, ], 20 //Per evitare la generazione del viewport autoCreateViewport: false,

//nome dell’app 25 name: ’NotesApp’,

//Lancher di app-test. Usare sempre questo template launch: function() { 30 jasmine.getEnv().addReporter(new jasmine. TrivialReporter()); jasmine.getEnv().execute(); } });

In ultima il lettore dovrà prestare attenzione a predisporre il file run-test.html, la pagina da cui eseguire i test:

Listing 14: Esempio di run-test.html

2 NotesApp unit test - Jasmine 7 12 66 testare un’applicazione sencha

17 22 27

Ora l’ambiente è configurato. lo sviluppatore potrà definire spec e metterle nell’omonima cartella definita al punto 1. Per eseguire i test basta richiamare dal browser all’indirizzo localhost il file run-test.js.

6.4.2 Testare gli store

Quando testiamo uno store è sempre molto utile definire una fun- Le funzioni zione per creare lo store, e tramite le apposite funzioni beforEach e beforeEach e afterEach, provvedere alla sua creazione (All’inizio di ogni singolo afterEach aiutano a test) e alla sua eliminazione (alla fine del test). Per rendere meglio riconfigurare le precondizioni di test. questo concetto proponiamo il seguente template: 6.4 unit test 67

Listing 15: Template per il testing degli store

describe("NomeStoreSpec", function() { //classe contenente che definisce lo store 5 var storeCreator = function() { var myoStore = Ext.create( ’AliasStore’); return myoStore; }; 10 //istanza di store usata peri test var store = null;

beforeEach(function() 15 { //ad ogni test creo lo store if (!store) { store = storeCreator(); 20 store.load(); } expect(store).toBeTruthy(); waitsFor(function(){ return !store.isLoading(); },"load never completed", 4000); }); 25 afterEach(function() { store.getProxy().dropTable(); store = null; 30 });

...

//elenco di it() ... 35 });

Per quanto riguarda invece i test da eseguire, si raccomanda di assi- curarsi come prima che lo store sia stato caricato con successo. Quindi si procede verificando che il modello utilizzato dallo store corrispon- da a quello che si è assegnato. Ciò potrebbe sembrare banale, ma è comunque un test da fare, specie per gli store più elaborati da noi ridefiniti. Analogamente è importante osservare che il proxy usato dallo store sia del tipo atteso. Proponiamo di seguito un esempio di come possono essere riportati due it del genere: 68 testare un’applicazione sencha

Listing 16: Template per il testing degli store - it di base

it( ’IndexIDStore caricato con successo’, function() { var isLoaded = store.isLoaded(); 5 expect(isLoaded).toBe(true); });

it("Model dello store valido (type : NOME_MODELLO)",function() { 10 var modelloStore = store.getModel().getName(); var modelloAtteso = ’PATH_COMPLETA_DEL_MODELLO’; //e.g PATH_COMPLETA_DEL_MODELLO=’org.s2.MioStore. MioModello’

expect(modelloStore).toBe(modelloAtteso); 15 });

it("Proxy type di store valido (type : TIPO_ATTESO) ",function() { var proxyTypeStore = store.getProxy().config.type; 20 var proxyTypeAtteso = ’TIPO_ATTESO’; //e.g TIPO_ATTESO=’sql’

expect(proxyTypeStore).toBe(proxyTypeAtteso); });

6.5 uitest

Gli UI test altro non sono che test dell’interfaccia grafica. Il loro compito è assicurarsi che gli elementi sullo schermo si comportino e appaiano come previsto, sia staticamente che dinamicamente. Gli UI test si Gli UI test possono essere dividono in due tipologie: dividono in due categorie. • QA test: simulano le interazioni del mondo reale con l’applica- zione come se effettivamente l’app fosse usata da un utente;

• Component Tests: sono mirati a verificare il comportamento e l’aspetto delle singole componenti grafiche. Generalmente sono quindi usati per il test di piccole porzioni di codice.

Data la natura della componente creata durante lo stage (il Syn- cEngine) non è stato necessario da parte mia, eseguire tale tipolo- gia di test. La componente infatti è esclusivamente di natura logica. Tuttavia per completezza ho ritenuto importante informare il letto- re di questo strumento, essenziale per garantire un test completo di un’applicazione mobile. In merito si rimanda (per una trattazione più approfondita) all’articolo [31, “UI Testing a Sencha App” ]. SISTEMIDIARCHIVIAZIONEDATI 7

7.1 panoramica sugli store di html5

PhoneGap permette alle nostre applicazioni di operare un archivia- zione dei dati usufruendo delle potenzialità dell’HTML5. Quest’ulti- Gli store HTML5 si mo definisce 4 tipologie di store: dividono in 4 tipologie. • Local Storage;

• Session Storage;

• WebSQL Storage;

• IndexedDB Storage;

Le tecnologie Local Storage e Session Storage vengono in genere denominate Web Storage e rappresentano una comune interfaccia di programmazione per le pagine Web. Queste funzionalità costituisco- no un miglioramento dei cookie e sono di dimensioni limitate, che variano da 5 a 10 MB a seconda del browser utilizzato. Non inviano i dati al server, ma archiviano i dati sui computer client locali. Lo- cal Storage è un’archiviazione persistente, mentre Session Storage offre un’archiviazione temporanea. In merito al Session Storage è importante ricordare che i dati cosi Session Storage è archiviati esistono solo nel contesto in cui vengono creati. Tale conte- solo per una sto non si basa solo sul sito remoto (l’URL di navigazione) ma anche memorizzazione temporanea. in base alla tab o alla finestra utilizzata dall’utente. Il Local Storage invece è un oggetto specifico del browser, condivi- so da tutte le istanze (finestre o tab del browser) aperte dall’utente. Più interessante, il WebSQL fornisce un sistema di archiviazione at- traverso la creazione di un mini database in SQLite 3 (per maggiori informazioni su SQLite rimando all’appendice “sqlite”). Durante lo studio effettuato su tale argomento è però emersa una “discrepan- za” tra quanto riportato da libri/siti/forum e quanto effettivamente si può fare nella realtà. La documentazione riporta che, analogamen- te ai sistemi di storage già visti, anche il WebSQL risulta avere un limite di default di 5MB, ma è possibile aumentarlo a piacere im- postando il campo size. Tuttavia contrariamente a quanto riportato nella documentazione reperita, è stato possibile sforare questo limite senza alcun problema. Anche la ridefinizione del campo size di un database, abbassandolo da 5 a 2 MB, non ha comportato problemi di sorta permettendoci di creare database di dimensione superiore. Uno studio ulteriore ha comportato l’individuazione di un sito dove si ac- cennava ad una caratteristica del browser Safari. Questo sembrerebbe

69 70 sistemi di archiviazione dati

essere l’unico ad adottare una vera limitazione sull’uso dei web data- base. Esso infatti richiede all’utente, al momento del superamento dei 5 MB, l’autorizzazione ad espandere la sua dimensione di altri 5 MB, e cosi man mano che si sfora nel size attuale. Considerazione in me- rito ai test apportati (in conferma a quanto qui detto) sono reperibili nell’appendice “test sul websql”. WebSQL è stato Tornando a parlare del WebSQL in sé, si sa inoltre che è stato de- deprecato dal W3C. precato dal W3C in favore dell’IndexedDB. Quest’ultimo però non è ancora supportato da tutti i browser mobile (come evidenziato al sito [6, “Can I use... - IndexedDB” ]). Per maggiori informazioni sui sistemi di archiviazione di HTML5 è possibile consultare le informazioni riportate nell’articolo [11, “HTML5 - Local Storage” ].

7.2 utilizzare web storage e websql con sencha

Sencha Touch 2 implementa già delle funzionalità per rendere il più automatico possibile l’uso dei Web Storage. In linea generale la strate- gia consiste nel creare un Ext.data.Store facente da ponte tra le viste e l’oggetto contenente i dati (proxy), ed un Ext.data.Model che defini- sce la struttura di quest’ultimi. Quando vogliamo creare un sistema di archiviazione con Sencha, dobbiamo prima decidere che tipo di Web Storage usare. La scelta dello store comporta l’uso di un determinato Implementazioni oggetto proxy: Sencha degli store HTML5. • Local Storage: implementato da Ext.data.proxy.LocalStorage;

• Session Storage: implementato da Ext.data.proxy.SessionStorage;

• WebSQL Storage: implementato da Ext.data.proxy.Sql;

• IndexedDB Storage: non implementato da Sencha, poiché tale sistema di archiviazione non è ancora supportato da diversi mobile browser.

Si osservi che l’uso dei proxy si basa su di un interfaccia comune, il che rende pratico e veloce il passaggio da un tipo all’altro. In fa- se di developing si sottolinea l’utilità degli strumenti per sviluppatori presenti su Google Chrome. Andando alla voce risorse sarà possibile esaminare il contenuto dei diversi tipi di storage. In ultima concludo rimandando al riferimento bibliografico [21, “Revisiting the Sencha Touch 2.2 Sql Proxy” ] . Quanto qui riportato si basa in parte sulla lettura di tale articolo, al quale rimando per una trattazione più approfondita dell’argomento. In particolare, il lettore più curioso, potrà trovare un esempio pratico sull’implementazione degli store Sql. 7.3 considerazioni sull’uso dei web storage 71

7.3 considerazioni sull’uso dei web storage

Per lo scopo aziendale (archiviazione permanente senza limitazioni) i Web Storage presentano diversi problemi: Limiti dei Web Storage. • lo spazio di memorizzazione è limitato;

• non si tratta di un database e non dispongono di nessun query language;

• non tutti i device supportano i Web Storage.

Inoltre, pur non essendo un problema per il porting con PhoneGap, si osserva che i Web Storage costituiscono una sorta di miglioramento dei cookies. Ciò implica che una semplice pulizia del sistema, che pre- vede di cancellare tutti i dati di navigazione e dei cookies, comporta la perdita dei dati da noi archiviati. Questi difetti nell’ottica di costruire un database corposo ci porta a scartare l’uso dei Web Storage, più adatti alla memorizzazione tem- poranea di dati non sensibili e il cui quantitativo non supera i 5 MB. L’alternativa presa in esame è quella del WebSQL che se pur depre- cato rappresenta l’unica possibilità offerta da PhoneGap, il compro- messo per sviluppare cross-platform. Nel paragrafo seguente mostrerò come usare questo kit a partire da Sencha. Per il lettore che ha in ani- mo di capire quali funzioni JavaScript, usi PhoneGap per interagire con tale strumento, rimando al riferimento bibliografico [19, ‘Phone- Gap Documentation - Storage” ]. Si osservi che PhoneGap non fa altro che rifarsi al WebSQL richiamandone le funzioni: openDatabase, tran- saction e executeSql. Per maggiori informazioni su WebSQL rimando all’articolo [13, “Introducing Web SQL Databases” ]. Un ultima nota va all’IndexedDB . Questo sistema di archiviazione, come già detto, non IndexedDB. è ancora supportato da tutti i browser. Men che meno dai browser mo- bile. Tuttavia si sottolinea l’esistenza di un plugin che basa l’utilizzo di IndexedDB su WebSQL, per quei browser che non lo supportano [12, “IndexedDB Polyfill over WebSql” ].

7.4 websql e la gestione degli id

Usando i proxy Sql mi sono subito reso conto di una cosa molto particolare: il sistema di gestione degli ID. Quando creiamo uno store associato ad un proxy del genere, Sencha predispone una tabella in un database atta a contenere dei record. In aggiunta (se non esiste già) crea un’ulteriore tabella usata per le indicizzazioni. Ogni model è infatti automaticamente dotato di un campo id (che volendo può Sencha predispone essere rinominato dallo sviluppatore) usato da Sencha per indicizzare una tabella per la quel record nel database. Gli indici sono auto-incrementanti e nella memorizzazione dell’ultimo id usato tabella aggiuntiva citata poc’anzi viene tenuta traccia del più alto id per in ogni tabella corrente per ogni tabella facente parte della base di dati. del database. 72 sistemi di archiviazione dati

In merito però bisogna prestare molta attenzione: questi id non so- no valori stabili, ma chiavi usate da Sencha per gestire in autonomia il proprio database. Nello specifico è emerso un innaturale schema se- condo cui la copia di un record mediante metodo copy(), provoca un cambiamento dell’id presente nel record originale. Data l’importanza del metodo ciò rende in assoluto inadeguato l’uso del campo id come chiave primaria del record, da usare in associazione a dei vincoli re- ferenziali su altre tabelle. Si consiglia quindi di ignorare tale campo, con la consapevolezza che è compito di Sencha gestirlo. Per utilizza- re invece un sistema di vincoli basati su chiavi esterne, è decisamente meglio specificare personalmente un proprio campo da usare come chiave primaria.

7.5 plugin esterni

Quando si usa un framework JavaScript, la scelta di scrivere di no- stro pugno del codice per gestire un sistema di archiviazione, non è propriamente la cosa più sensata da fare. Come prima cosa è meglio operare una ricerca approfondita per verificare l’esistenza di librerie o plugin adatti ai nostri scopi. Purtroppo prima della versione 2.1.0 di Sencha, non esisteva al- cun oggetto che definisse un proxy di tipo WebSQL. Ciò portò molti sviluppatori a scrivere dei propri plugin. In particolare segnalo (per esempio) il plugin riportato sul repository GitHub: [37, “GitHub - Ext.data.proxy.WebSQL” ]. Tuttavia alla data attuale, con la versione 2.2.0 di Sencha, è stato definito un proxy denominato Ext.data.proxy.Sql1. Osservandone il comportamento si conclude che il proxy in questione, per funziona- mento, è analogo a quello del plugin evidenziato in precedenza e al’API di PhoneGap: usa le funzionalità proprie offerte dal WebSQL (openDatabase, transaction e executeSql). Per quanto detto la soluzione migliore per l’implementazione di un database WebSQL si basa sull’uso di Ext.data.proxy.Sql. Tuttavia, per completezza, metto in evidenza l’esistenza di un ulteriore plugin di- sponibile sia per Android, iOS e Windows Phone 8. Esso è reperibile dalla fonte [40, “GitHub - PG-SQLitePlugin-Android ” ]. In linea teorica e stando a quanto dicono gli sviluppatori, il plugin risulta essere deci- samente più interessante di Ext.data.proxy.Sql, fornendo le seguenti Caratteristiche di funzionalità: PG-SQLitePlugin. • permette di posizionare il database sqlite in una posizione ben precisa e configurabile;

• ottimizzazione del batch processing;

1 Si osservi che nella versione 2.1.0 (versione in cui è stata introdotto) era noto come Ext.data.proxy.SQL. 7.6 sencha.io, il cloud service di sencha 73

• nessun limite2 di 5 MB di spazio archiviabile; • utilizzo di SQLCipher per garantire la criptazione dei dati. Purtroppo una sua implementazione eseguita con le best practice riportate nell’articolo [23, “Sencha Touch 2 SQL proxy for SQLite” ], non ha dato esito positivo. Infatti è emerso un bug riscontrato anche da PG-SQLitePlugin altri sviluppatori, legato alla libreria cordova-2.7.0.js e in particolare non può essere al file cordova_plugins.js. Uno studio ulteriore ha evidenziato che la utilizzato a causa di un bug della libreria risoluzione di tale problema è presente tra le issues non risolte del cordova. progetto Cordova. Si suggerisce di riprovare un implementazione con tale plugin solo in seguito alla risoluzione di tale bug.

7.6 sencha.io, il cloud service di sencha

Figura 8: Sencha.IO - logo [22, “Sencha Docs IO” ]

Durante lo studio del dominio tecnologico è emersa un’alternati- va all’utilizzo degli store HTML5. La soluzione è un’API sviluppata dalla Sencha inc. e denominata Sencah.IO3. Il sistema fornisce diversi servizi legati alla condivisione di dati. Un introduzione a questa API è presente in [22, “Sencha Docs IO” ]. Un analisi generale del sistema mi ha portato ad evidenziare 5 tipologie di servizi: Sencha.IO fornisce 5 tipologie di servizi. user services : un sistema di gestione che mantiene una lista degli utenti abilitati all’utilizzo dell’app. Gli utenti autenticati potran- no memorizzare online i propri dati riguardanti l’app. L’auten- ticazione può avvenire per mezzo delle seguenti tipologie di credenziali: • indirizzo e-mail e password; • credenziali di Facebook; • credenziali di Twitter; device services : un sistema di autenticazione basato sul device da cui è eseguita l’applicazione (può tornare comodo per evitare attacchi di tipo spoofing);

2 Si osservi come anche qui viene messo in evidenza la presenza del limite di 5 MB già confutato. 3 In Figura 8 è riportato il logo dell’API. 74 sistemi di archiviazione dati

chanel services : un sistema di messaggistica che permette l’in- vio di messaggi o attraverso canali privati, oppure a tutti gli utenti facenti uso dell’app;

data services : è il cuore del sistema di cloud. Si basa sulla defini- zione di un proxy contenente la logica di gestione della sincro- nizzazione clinet-server. L’utilizzo dello store è totalmente auto- matico e il passaggio da un vecchio sistema di storage a quello fornito da Sencha.IO è veloce (in pratica consiste unicamente nel cambiare la tipologia di proxy e nell’impostare un campo per definire l’utente che esegue l’app). L’archiviazione in locale avviene usando i LocalStorage (quindi si evidenzia il limite dei 5MB). I dati vengono salvati mediante una loro formattazione in JSON. La sincronizzazione effettua simultaneamente il down- load e l’upload dei dati. Si osservi infine che i metodi per opera- re la manipolazione dei dati e la sincronizzazione sono sempre gli stessi utilizzati per lo store. Ciò permette allo sviluppatore di approcciarsi con un sistema di gestione già noto, facilitando cosi l’uso dell’API;

image services : è un servizio per la gestione del resize di imma- gini condivise da più device.

Alla data in cui è stato effettuato lo studio (giugno 2013) Sencha.IO è ancora in fase beta. Le sue funzionalità sono comunque di grande interesse e forniscono servizi utili limitando notevolmente il lavoro dello sviluppatore. Conclusioni su In risposta ad una mia segnalazione sull’esistenza di Sencha.IO, Sencha.IO. l’azienda ha scelto di scartare tale soluzione per gli scopi aziendali. I motivi che hanno portato a tale scelta sono i seguenti:

• il sistema cloud si basa su servers di Sencha.IO. I proxy uti- lizzati dall’API sono privati e di conseguenza è impossibile ri- definire un proprio proxy che rimandi ad un server proprio. Adottare Sencha.IO comporta il vantaggio di facilitare enorme- mente l’implementazione del sistema di sincronizzazione, ma presenta l’enorme svantaggio di legare eccessivamente la nostra applicazione a server esterni;

• l’uso dei LocalStorage ci vincola fisicamente ad usare aree di ar- chiviazione di dimensione pari o inferiori a 5 MB. Inoltre non es- sendo un database di tipo relazionale, risulterebbe impossibile la creazione e l’utilizzo di query di tipo SQL;

• l’invio dei dati non avviene on demand e in maniera slegata dal download dei dati presenti nel server online. Ciò costituisce una limitazione non indifferente nel modo in cui si può operare con il sistema. 7.7 considerazioni finali sui sistemi di archiviazione 75

7.7 considerazioni finali sui sistemi di archiviazione

Sviluppare cross-platform non è una magia. Per farlo bisogna necessa- riamente ricorrere a dei compromessi. Nel caso, PhoneGap richiede allo sviluppatore di usare e sfruttare unicamente le funzionalità di HTML5 e JavaScript. Di conseguenza (e come già detto) l’unica alter- nativa (per quanto riguarda i sistemi di archiviazione) consiste nell’u- sare il WebSQL. Anche se deprecato ormai dal 2010, sia PhoneGap che Sencha hanno continuato ad usarlo fino ad oggi e lo “pubbliciz- zano” come l’unico mezzo di archiviazione web basato su database relazionali. Pertanto si confida che le citate piattaforme continuino a supportarne l’uso, già che le numerose app disponibili ne sfruttano le potenzialità. Per quanto riguarda la perdita dei dati in seguito alla cancellazione dei cookie, ciò non sussiste nel momento in cui trasfor- miamo la web app in una applicazione ibrida. Infatti qui non ci si ap- poggia più alle regole imposte dai browser. Infine l’ipotesi di affidarsi a plugin sviluppati da terzi non risulta essere un idea apprezzabile per i seguenti motivi:

• non si conoscono realmente gli sviluppatori. Non c’è un’orga- nizzazione che garantisce per questi, ma sono semplicemente dei plugin creati da sviluppatori indipendenti;

• il plugin proposto in questa sezione (come alternativa a Web- SQL) non fornisce un approccio multi-piattaforma, ma richiede il caricamento della versione corretta a seconda della piattafor- ma su cui ci si appoggia.

PROTOTIPAZIONE 8

8.1 notesapp

AL fine di comprendere meglio i limiti e le potenzialità del dominio tecnologico è stato creato un prototipo di applicazione seguendo la guida [9, “How to create a Sencha Touch 2 app” ]. L’applicazione altro non è che un editor di note. Per quanto semplice essa permette di prendere in considerazione tutti gli aspetti della programmazione con Sencha, senza richiedere tuttavia troppo tempo. Nello specifico gli Scopo dell’attività di scopi della prototipazione sono: prototipazione.

• imparare le funzionalità degli store, e verificare la capacità di cambiare tipologia di store durante la realizzazione del prototi- po. Nello specifico il prototipo sarà inizialmente basato su Lo- cal Storage. Successivamente si passerà agli store WebSQL. Ciò è particolarmente interessante poiché permetterà all’azienda di capire quali spese (in termini di tempo) sono richieste per ap- plicare una modifica sui sistemi di archiviazione di un’applica- zione già in corso di sviluppo;

• imparare ad usare il sistema MVC. In particolare applicare la best practice basata sulla gestione degli eventi mediante fireE- vent();

• imparare come funzionano le principali componenti grafiche dell’ambiente Sencha;

• imparare le potenzialità dei modelli e dei proxy;

8.2 analisi dei requisiti

Quella che segue è una piccola analisi dei requisiti, condotta al fine di stabilire fin dall’inizio quali punti fosse essenziale trattare con il prototipo. Osservando la seguente tabella si osserverà che i requisiti emersi sono fondamentalmente evoluzioni delle osservazioni fatte al paragrafo precedente. Per motivazioni legate alle tempistiche di stu- dio non è stata condotta nessuna analisi tramite use case (cosa invece che si vedrà nell’analisi del SyncEngine). L’unico strumento usato, è stato una discussione creativa con il tutor aziendale. I requisiti quindi sono:

77 78 prototipazione

Requisiti Descrizioni

RO1.0.0 il prototipo deve inglobare l’uso degli store; RO1.1.0 il prototipo deve usare almeno due store; RO1.1.1 tra gli store utilizzati deve esserci al- meno un vincolo di tipo referenzia- le (e.g. la tabella note potrebbe essere associata a degli autori); RO1.2.0 il prototipo deve permettere la visione di almeno due tipologie di store; RO1.2.1 in una prima versione gli store utiliz- zati saranno associati a proxy di tipo LocalStorage. Successivamente si ado- pererà una modifica per associarli ai proxy Sql; RO1.3.0 almeno uno dei modelli usati deve avere dei validatori tali per cui sia ri- chiesto l’inserimento obbligatorio del valore per la creazione del record; RO2.0.0 il prototipo deve far uso di un siste- ma di gestione degli eventi basato su controller; RO3.0.0 il viewport deve contenere più di una vista e l’applicativo in se deve uti- lizzare delle meccaniche animate per la transizione da una vista all’altra, cosi da poter testare quanto tali ani- mazioni influiscano sulle prestazioni generali; RO4.0.0 il prototipo deve far uso delle com- ponenti grafiche più usate in una normale applicazione mobile; RO4.1.0 vi deve essere almeno un button; RO4.2.0 vi deve essere almeno una list con re- lativa associazione ad un modello da cui prelevare i dati; RO4.3.0 vi deve essere almeno una toolbar, po- tenzialmente usabile come menù della vista corrente; 8.3 architettura del prototipo 79

RO4.4.0 vi deve essere almeno un fieldset con- tenente degli oggetti per operare degli inserimenti di dati; RO5.0.0 deve essere prevista almeno una vi- sta per l’inserimento dei dati. Quanto meno la vista per l’inserimento delle note;

La guida scelta mostra già un approccio in grado di soddisfare mol- ti dei requisiti sopra riportati, per gli altri è stato sufficiente prendere visione della documentazione di Sencha e del manuale [1, “Sencha Touch 2 - Up and Runnig” ], usato in particolar modo per le view e per prendere visione dei proxy.

8.3 architettura del prototipo

Con riferimento alla guida citata all’inizio del capitolo, l’applicativo è stato strutturato nel seguente modo: view : al fine di soddisfare il requisito RO3.0.0, l’applicativo è stato dotato di 3 viste, entrambe caricate nel viewport al momento della creazione. Ciò avviene nel lancher di app.js. La directory view contiene anche la definizione di un oggetto picker usato per visualizzare una lista a scomparsa, contenente i nomi e i cognomi degli autori registrati nell’applicazione. In dettaglio le view sono: • NoteList: caricata come home dell’applicazione, contiene una toolbar (requisito RO4.3.0 soddisfatto) avente riportan- te il titolo dell’applicazione. Nella zona centrale è presente la lista delle note (requisito RO4.2.0 soddisfatto), in cui l’e- lenco dei dati è ottenuto associando la lista allo store No- teStore. La vista contiene anche una toolbar nel foot dove sono presenti due bottoni (requisito RO4.1.0 soddisfatto): quello per creare una nuova nota e quello per creare un nuovo autore; • NoteEditor: contribuisce al soddisfacimento del requisito RO5.0.0 e permette di definire una vista contenente il field- set (soddisfacimento RO4.4.0) per l’inserimento di una nuo- va nota. Nella vista sono presenti 3 componenti per l’inse- rimento di dati: una textbox per il titolo della nota, una textarea per il contenuto della nota ed infine una combo- box per la selezione dell’autore associato. Nella vista sono presenti anche 3 bottoni: salva nota, torna indietro e elimi- 80 prototipazione

na nota corrente. Questa view è accessibile in due modi dalla vista NoteList: – premendo il pulsante per l’inserimento di una nuova nota; – selezionando una nota presente nella lista. L’ultima modalità in particolare permette di modificare una nota già esistente. Quindi NoteEditor sarà caricata con la fieldset già popolata con i dati della nota selezionata; • NoteAuthor: contribuisce al soddisfacimento del requisito RO5.0.0 e rappresenta la vista per l’inserimento di un nuo- vo autore nel sistema. La struttura è di per se simile a quel- la di NoteEditor, con la differenza che non è stato predispo- sto nessun bottone per l’eliminazione di un autore. Inoltre nella vista è presente un bottone per la visualizzazione del picker AuthorPicker; • AuthorPicker: si tratta di una componente grafica definita estendendo Ext.picker.Picker. Lo scopo è quello di visualiz- zare la lista, intesa come coppie di nomi - cognomi, degli autori registrati nel sistema.

model : al fine di soddisfare i requisiti legati all’uso degli store (quindi il requisito RO1.0.0), sono stati definiti due modelli di dati in associazione al requisito RO1.1.0. Entrambi presentano dei validatori in conformità al requisito RO1.3.0. Nello specifico sono stati definiti i seguenti modelli: • Note: è il modello che rappresenta la struttura di una ge- nerica nota. Nello specifico stabilisce che ogni nota deve avere 5 campi dati: – noteID: campo di tipo string obbligatorio. Usato come chiave primaria (sintetica); – title: campo obbligatorio di tipo string. Contiene il ti- tolo della nota; – narrative: campo opzionale contenente di tipo string, contenente il testo della nota; – dataCrated: campo dateTime contenente la data di crea- zione della nota. – author: chiave esterna obbligatoria. Contiene l’identifi- cativo del autore della nota; • Author: è il modello usato per definire un autore. Il model- lo stabilisce una struttura basata sui dati: – authorID: chiave primaria (sintetica) di tipo string; – name: campo string contenente il nome del autore; 8.3 architettura del prototipo 81

– surname: campo string contenente il cognome del au- tore

store : le caratteristiche d’implementazione degli store sono dovu- te al soddisfacimento dei requisiti della famiglia RO1.0.0. Nello specifico osserviamo la presenza di 2 store (RO1.1.0), entrambi aventi (nella prima implementazione del prototipo) dei proxy di tipologia LocalStorage. Successivamente sono stati modificati in Sql osservando come il cambiamento di un proxy (in un proget- to già in corso di sviluppo) sia un’operazione semplice in grado di minimizzare l’attività di manutenzione. Ciò ha contribuito al soddisfacimento del requisiti RO1.2.0 e RO1.2.1. In dettaglio gli store usati sono: • NoteStore: store il cui proxy è associato al model Note. In esso è definito un sistema di raggruppamento per data (dataCreate) e un sistema di ordinamento sempre per data; • AuthorStore: associato ad un proxy avente lo stesso tipo di NoteStore ma avente come model Author. Non presenta nessun tipo di ordinamento o raggruppamento.

controller : dai requisiti emersi durante l’attività di analisi si è osservata la necessità di un controller avente il compito di ge- stire le richieste inoltrate dall’utente per mezzo dell’iterazione con le viste. Si ricorda infatti che in un buon modello MVC (e più in generale in un buon approccio di programmazione orien- tata agli oggetti) le viste non devono contenere nessuna logica, ma solo la definizione delle componenti d’interfaccia. Il control- ler definito comporta il soddisfacimento del requisito RO2.0.0. Più nello specifico il controller è stato strutturato nel seguente modo: • NotesController: contiene dei riferimenti alle viste del view- port e agli store. Per componente grafica delle viste prende in delega il compito di gestire gli eventi ad esse associa- ti. Definisce inoltre la logica di transizione da una vista a l’altra.

app.js : è il file in cui vengono caricati gli oggetti Sencha necessari al corretto funzionamento dell’applicazione e si basa sulla de- finizione (Ext.define()) di un oggetto Ext.application(). In esso vengono riportati dei riferimenti anche alle classi da me definite nei passaggi precedenti. In particolare vi è un metodo launch() Nel metodo launch() eseguito all’avvio dell’applicazione in cui vengono inizializzate di app.js vengono le singole viste1 e successivamente caricate nel viewport. Si os- predisposte le view dell’applicativo. 1 Il lettore attento potrà osservare come ciò costituisca una violazione della best prac- tice riporta alla sezione “Viewport dinamico” . Ciò è stato fatto in quanto le pratiche di ottimizzazione del viewport, sono emerse solo in seguito ad uno studio effettuato dopo la realizzazione del prototipo. 82 prototipazione

servi che la prima vista ad essere caricata (che è anche la prima ad essere visualizzata all’utente) è NoteList.

index.html : è il file in cui vengono caricati: • tutti gli stili CSS necessari (Nel nostro caso quello di de- fault di Sencha, più un piccolo CSS in cui è definita la vista di visualizzazione di una nota all’interno della lista); • le librerie esterne utilizzate. Quindi la libreria di Sencha e (successivamente per il porting) quella di Cordova (Phone- Gap); • in ultima viene caricato il file app.js. Ciò garantisce l’esecu- zione dell’applicazione.

La suddivisione dei file nelle rispettive directory ha seguito la par- tizione (Figura 9):

Figura 9: Prototipo - struttura directory di lavoro [9, “How to create a Sencha Touch 2 app” ]

dove il contenuto delle cartelle corrisponde alle classi citate nell’e- lenco soprastante.

8.4 sviluppo del prototipo

Lo sviluppo del prototipo si può esprimere attraverso un modello incrementale basato su 3 cicli:

• primo ciclo: creazione dell’applicazione base seguendo la guida [9, “How to create a Sencha Touch 2 app” ];

• secondo ciclo: aggiunta delle funzionalità legate alla gestione degli autori. Tale aggiunta è emersa al fine di soddisfare alcuni requisiti non soddisfatti dall’applicazione della guida;

• terzo ciclo: modifica i proxy utilizzati. I tipi LocalStorage sono stati sostituiti con Sql.

Tra le parti più interessanti del codice sviluppato ritengo interes- sante porre delle piccole osservazioni su: 8.4 sviluppo del prototipo 83

• app.js;

• Note;

In questo modo il lettore potrà avere un idea più chiara di come configurare l’app.js da cui avviare l’applicazione e avrà un idea di base di come costruire uno store con qualche funzionalità extra (ordi- namento e raggruppamento). Il controller, anche se giudicato impor- tante, non viene riportato per la complessità di trattazione e poiché un’idea di base è già stata data alla sezione “FireEvent: una gestione intelligente degli eventi”.

8.4.1 App.js

Come già detto, definisce un’istanza di Ext.application. Nel codice sotto riportato si può osservare come all’inizio, alle omonime voci, vengano caricati mediante riferimento all’alias tutti gli oggetti usati all’interno dell’applicazione.

Listing 17: Prototipo - codice di app.js

Ext.application({ name: ’NotesApp’,

//---import--- 5 models: [ ’Note’, ’Author ’], stores: [ ’NoteStore’, ’AuthorStore ’], views: [ ’NotesList’, ’NoteEditor’, ’NoteAuthor’], controllers: [ ’NotesController ’],

10 launch: function() { //creo le viste

console.log( ’App avviata con successo’); 15 var notesList = { xtype: ’notesListView ’}; console.log( ’NoteListContainer creato con successo ’); var noteEditor = { xtype: ’noteEditorView ’}; console.log( ’NoteEditor creato con successo’); var noteAuthor = { xtype: ’noteAuthorView ’}; 20 console.log( ’NoteAuthor creato con successo ’);

//carico le viste nel viewport

Ext.Viewport.add([notesList,noteEditor,noteAuthor ]); 25 } }); 84 prototipazione

8.4.2 NoteStore

Quello che segue è il codice dello store aggiornato alla versione con il proxy di tipo Sql. In merito si è potuto constatare la semplicità di modifica di un proxy. Infatti rispetto alla versione precedente è stato sufficiente cambiare il contenuto della stringa type, da localstorage a sql. Inoltre per rendere la collocazione della tabella più ordinata si è impostato il nome del database. Si osservi che non è compito dello sviluppatore creare il database. Sarà compito di Sencha verificare l’e- sistenza del nome associato e nel caso un tale db non esista, sarà lei a crearlo. Osservando il codice dell’oggetto proxy definito nel package Ext, è stato possibile osservare la presenza delle tipiche funzioni Ja- vaScript usate per tali scopi. Per esempio il database veniva caricato con la funzione openDatabase(). Tornando allo store il lettore voglia osservare come sia possibile im- postare un ordinamento e un sistema di raggruppamento mediante le proprietà sorters e grouper.

Listing 18: Prototipo - codice di NoteStore.js

Ext.define( ’NotesApp. store .NoteStore ’, 3 { extend: ’Ext.data.Store’, config: { model: ’NotesApp.model.Note’, 8 proxy: { type: ’ sql ’, database: ’NotesDB’ 13 },

storeId: ’NoteStore’,

sorters: 18 [ { property: ’dateCreated ’, direction: ’DESC’ } 23 ],

grouper: { sortProperty: ’dateCreated ’, 28 direction: ’DESC’, groupFn: function(record) { 8.4 sviluppo del prototipo 85

if(record && record.data. dateCreated) { 33 return record.data. dateCreated. toDateString(); }

else { 38 return ’’; } } } } 43 });

CONSIDERAZIONISUIFRAMEWORKUSATI 9

Sencha Touch 2, PhoneGap e applicazioni ibride. Questi tre concet- ti mi hanno guidato per tutto il periodo di stage. In merito ho letto articoli sul web, libri ed ho sperimentato personalmente cosa essi vo- gliano dire. Al termine di tutto ciò mi sento di poter affermare quanto segue: Le applicazioni 1) le applicazioni ibride (e di conseguenza l’uso di Sencha e Pho- ibride non garantiscono il neGap) non sono la risposta alla domanda: “come creiamo la miglior risultato. migliore applicazione?”. Solo rapidi tempi di sviluppo. 2) le applicazioni ibride sono la risposta alla domanda: “come creiamo un app mobile minimizzando le tempistiche e di con- seguenza i costi?”.

Prima di analizzare questi due aspetti e capire cosa implichino, vor- rei procedere per gradi e spiegarvi cosa mi ha portato a tali conclu- sioni. Sencha è un framework potente in grado di dare una forma ben strutturata e ordinata alle applicazioni scritte in JavaScript. Usando questo strumento si ha quasi l’impressione di avere a che fare con un linguaggio totalmente nuovo avente dalla sua parte, molte del- le caratteristiche tipiche degli odierni OOP. L’ereditarietà e le clas- si sono concetti che non fanno parte di JavaScript, o che comunque vengono usati inconsciamente da coloro che non attuano una rigida definizione del concetto di OOP. Tuttavia con Sencha si ha davvero l’impressione di poter usare questi strumenti. Indubbiamente ho ap- prezzato la forma del suo codice e le potenzialità in esso contenute. La velocità con cui si riesce a sviluppare un’applicazione controllando diversi aspetti della stessa, è indubbiamente il pregio principale del framework. Malgrado la curva d’apprendimento sia piuttosto ripida, adoperando un investimento iniziale nella ricerca delle migliori fonti possibili, si riesce ad ammortizzare in parte il costo d’apprendimento. Purtroppo però è doveroso segnalare i seguenti problemi: Principali difetti di Sencha: • gli sviluppatori del framework si sono adoperati nel fornire una documentazione non sempre precisa e documentazione dall’aspetto accattivante e, in apparenza, dota- ripida curva ta di molte informazioni utili. Tuttavia basta cercare qualche no- d’apprendimento. tizia in più per ritrovarsi tra le mani una documentazione scarsa che non è in grado di dare tutte le informazioni necessarie all’u- so di un certo strumento. In più di un caso mi sono imbattuto nei commenti di utenti che richiedevano maggiori informazioni su metodi privi di descrizione o comunque, in cui non si capiva

87 88 considerazioni sui framework usati

come andassero utilizzati. Ciò diventa particolarmente sospetto nel momento in cui si osserva che la Sencha inc. fornisce un supporto valido solo a pagamento1;

• proprio perché non esiste una documentazione stabile in grado di dare le linee guida migliori, la maggior parte degli sviluppa- tori si affidano ai loro colleghi che scrivono sui forum di Sencha. Non sempre però quanto viene segnalato è del tutto vero e ciò porta sempre di più ad un clima di disinformazione;

• particolarmente dubbia è la procedura con cui i creatori di Sen- cha hanno definito metodi e classi private, già che mi è stato possibile in più di un caso usare pubblicamente un metodo defi- nito privato. Per esempio cito il metodo dropTable() della classe Ext.data.proxy.Sql;

• come accennato la curva di apprendimento per Sencha è ripida. Più nello specifico posso dire che non da grossi problemi finché si cerca di sviluppare un’applicazione semplice che non preveda oggetti ridefiniti e con una logica particolare. Nel caso le cose si fanno più complicate e spesso ci si imbatte in problemi di cui si ignorava l’esistenza (come l’esempio della gestione del multi-pat);

Questi proposti sono tuttavia problemi che potrebbero essere igno- rati da un utente esperto, avente ormai anni di conoscenze su tale strumento. Per lui resta comunque il problema legato all’uso di Pho- neGap. Lo strumento davvero semplice da usare, ci permette di effet- tuare un rapido porting delle nostre web app in applicazioni ibride. Purtroppo però non senza difetti. L’applicazione ibrida NotesApp, creata come prototipo per lo stu- Sui dispositivi di dio dei framework proposti si è rivelata leggermente lenta su di un fascia media, si nota dispositivo di fascia media (Huawei Honor), ma decisamente valida un rallentamento su smartphone di fascia alta (Huawei Ascend P6) e tablet (Samsung delle applicazioni ibride. tablet GT-P6510). Il rallentamento non è stato giudicato cosi eccessivo da rendere l’app inutilizzabile, ma la cosa diventa alquanto preoc- cupante se si pensa alla banalità dell’applicazione. Sorge spontanea la domanda: ma se avessimo un applicativo più complesso? Le co- se non potranno che peggiorare. Certo posiamo evitare il problema dichiarando che l’applicativo è predisposto per una certa fascia di de- vice (e.g. i tablet). La cosa può essere sensata ma comunque rimane evidente che il nostro lavoro non è ottimizzato quanto uno ideato con le tecnologie native. Tutto ciò ci riporta a quanto da me introdotto in questa sezione: le applicazioni ibride possono essere sviluppate velocemente (previo investimento nella formazione del personale) rispondendo quindi a

1 A seconda del pacchetto scelto, la spesa può essere compresa tra i $299 e i $4995, stando al tariffario consultato a giugno 2013 [27, “Sencha Touch Support” ]. considerazioni sui framework usati 89 quella che sembra essere la maggior preoccupazione delle aziende in questo periodo: risparmiare. Tuttavia risulta evidente che (a patto di non sviluppare unicamente per tablet) applicazioni complesse non possono essere sviluppate senza incorrere in rallentamenti notevoli. Plausibilmente si può supporre che la crescita tecnologica contribuirà a sanare questo problema: da una parte con l’aumento della potenza dei device, dall’altra (si spera) con il miglioramento del framework PhoneGap. Indicativamente (e in merito a quella che è la situazione odierna) ne raccomando l’uso solo per applicazioni semplici per le quali voglia- mo fornire il medesimo look & fell. Altrimenti consiglio di valutare l’opzione dello sviluppo nativo su target di piattaforme più limitato, ma sui cui almeno si potrà fornire un prodotto di qualità.

Parte III

SYNCENGINE

In questa parte sono riportate le informazioni legate al processo ingegneristico di creazione di una componente denominata SyncEngine. La libreria costituisce un tool per la sincronizzazione di un database locale con un server remoto, progettato al fine di sopperire alle mancanze del dominio tecnologico, emerse durante l’attività di studio.

ANALISIDELPROBLEMA 10

10.1 introduzione

Giunto al termine dell’attività di studio, ho potuto dare all’azienda un resoconto dettagliato di quelle che erano le alternative disponibili per l’archiviazione dei dati su applicazioni Sencha. In merito l’azienda ha fatto le seguenti osservazioni: Conclusioni aziendali sui sistemi • i web storage non possono essere usati in modo definitivo nelle di archiviazione. nostre applicazioni, poiché Session Storage non memorizza i da- ti in modo permanente, e Local Storage ha una struttura troppo lontana da quella di un vero database;

• Sencha.IO per quanto interessante non può essere utilizzato a causa di un eccessivo vincolo con quelle che sono le strutture fisiche (i server) su cui regge il sistema. Non vogliamo che i nostri dati risiedano in strutture non direttamente controllate da noi. Inoltre le operazioni di download e upload vengono eseguite con una logica troppo stringente;

• WebSQL risulta essere una buona base di partenza. Tuttavia è del tutto sprovvista del sistema di sincronizzazione cui è inte- ressata l’azienda.

• i plugin di terzi non possono essere presi in considerazioni, poiché non conosciamo realmente chi li ha implementati e con quale serietà siano stati sviluppati.

Generalmente in linea con le osservazioni fatte dall’azienda, ho successivamente ricevuto il compito di progettare e sviluppare la componente SyncEngine.

10.2 sistema di analisi

Come prima cosa è emersa l’esigenza di comprendere appieno il pro- blema e le esigenze aziendali. Riconoscendo il valore di una buona attività d’analisi, il mio lavoro in tal senso si è avvalso delle seguenti tecniche:

• discussione creativa con il tutor aziendale;

• utilizzo di diagrammi Use Case costruiti con la semantica UML 2.0.

93 94 analisi del problema

In particolare sottolineo che la seconda attività (costruzione degli Use Case) è stata preceduta dalla discussione creativa. Gli Use Case sono stati usati per riprendere i concetti di base e ampliarlo al fine di definire meglio la collocazione delle varie caratteristiche di sistema.

10.3 problematiche di sistema

Capitolato. Quella che segue è la richiesta aziendale:

Si vuole progettare e sviluppare un sistema di l’archiviazio- ne dati per dispositivi mobile (smarthone e tablet), in grado di sincronizzarsi con un server e operare operazioni di download e upload di record. La componente è pensata per applicazioni come gestionali, app per la raccolta ordini e tentata vendita. Il sistema, che da qui in avanti chiameremo SyncEngine, de- ve essere una componente riusabile in più progetti. Essa rap- presenta unicamente un apparato logico per la gestione dei dati. Se possibile non deve avere alcuna dipendenza con componen- ti di view (l’opzionalità è legata alla non totale conoscenza del dominio tecnologico usato). Il tool deve rendere possibile la creazione di un vero e pro- prio database SQLite all’interno del device in cui è utilizzato. Tutti i record di ogni tabella devono essere memorizzati perma- nentemente nel dispositivo. Non è ammessa la perdita di dati in seguito alla chiusura dell’applicativo. La base di archiviazione deve essere il proxy di tipo SQLite, WebSQL (decisione deri- vante dalle conoscenze emerse durante l’attività di studio dello stagista). In merito alla sincronizzazione, è da considerarsi obbligatorio rendere le operazioni di download e upload separate. L’utilizzato- re potrà richiedere un operazione di upload su una tabella senza necessariamente riscaricare il contenuto della tabella stessa dal server. Analoga considerazione va fatta per un operazione di do- wnload che non deve richiedere un upload dei record locali. Si sottolinea poi che le operazioni di upload e download si riferi- scono alle singole tabelle. In linea generale si potrebbe scaricare il contenuto di una tabella X senza scaricare quello delle altre tabelle del database. Le operazioni di sincronizzazione avvengono on demand. L’unico caso in cui si esegue un operazione di download gene- rale, ossia dell’intero database, senza la conferma del utente, è all’avvio dell’applicazione. Il sistema deve permettere a chi lo usa di eseguire operazioni CRUD su ogni tabella del database. Queste operazioni (anche in presenza di connettività) devono avvenire in locale e in parti- colare, i record cosi manipolati devono essere memorizzati come bozze fin tanto che non vengono inviati al server. Quando l’u- 10.4 usecase 95

tente visualizza i dati di una tabella egli deve poter vedere gli ultimi dati scaricati, modificati con le bozze salvate in locale.

Sulla base di una lettura approfondita del testo, ho proseguito me- diante un intervista al tutor aziendale con il quale sono emersi i seguenti punti: Considerazioni aggiuntive: • il sistema deve essere dotato di una sotto-componente incaricata di conoscere tutte le tabelle facenti parte del database, e da cui sia possibile eseguire le operazioni CRUD e di sincronizzazione, specificando la tabella d’interesse;

• d’altro canto l’utilizzatore deve poter lavorare direttamente con le singole tabelle senza dover passare per il sistema centrale;

• potenzialmente la componente in via di definizione andrà ad es- sere integrata in un progetto già esistente. Nel caso l’operazione di manutenzione evolutiva dovrebbe essere il meno costosa pos- sibile. Ciò implica l’esigenza di associare le tabelle del database a veri e propri Ext.data.Store.

10.4 usecase

Di seguito sono riportati gli Use Case usati per comunicare con il tutor aziendale le idee che stanno alla base della componente Syn- cEngine. Si osservi che qui non si parla realmente di un’applicazione, ma di una componente riusabile in più progetti. Di conseguenza la contestualizzazione fatta per capire come l’utente (o un qualsiasi altro attore) interagisce con la componente, è generica. Gli Use Case in se sono strutturati nel seguente modo: Struttura di un Use Case. • titolo;

• diagramma;

• lista degli attori;

• scopo e descrizione;

• precondizione;

• postcondizione;

• illustrazione scenario principale;

• (se necessario) illustrazione scenari alternativi; 96 analisi del problema

10.4.1 UC1.0.0.0

titolo : Avvio dell’applicativo.

diagramma :

Figura 10:UC 1.0.0.0 - creazione/caricamento del database all’avvio dell’applicazione

attori : Utente, Server.

scopo e descrizione : Il diagramma di Figura 10, mostra come al- l’avvio dell’applicazione l’utente potrà dare il via alla configura- zione del sistema di archiviazione. Ciò prevede o il caricamento di un database già esistente (UC1.3.0.0) o la creazione di un nuo- vo database (UC1.1.0.0). Idealmente l’Use Case UC1.1.0.0 viene eseguito solo al primo avvio, e da li in poi ad ogni avvio, viene eseguito il passo UC1.3.0.0. Entrambi gli use case evidenziati in- cludono nella loro esecuzione l’UC1.2.0.0 ossia il download dei record presenti nel server online.

precondizione : L’applicativo facente uso del SyncEngine è stato avviato con successo.

postcondizione : Un database è stato caricato con successo ed è stata eseguita un operazione generale di download.

illustrazione scenario principale : L’utente, dopo aver man- dato in esecuzione l’applicazione, può scegliere o di caricare un database già esistente (UC1.3.0.0) oppure di crearne uno nuovo 10.4 usecase 97

(UC1.1.0.0). L’esecuzione di uno qualsiasi dei due UC evidenzia- ti comporterà l’esecuzione di un operazione di download gene- rale(UC1.2.0.0). Tale operazione riguarda l’intera struttura del database e coinvolge, come ovvio, il server. illustrazione scenari alternativi : In caso di assenza di con- nettività, l’UC1.2.0.0 viene esteso con l’UC1.4.0.0 che prevede l’interruzione dell’attività di download.

10.4.2 UC2.0.0.0 titolo : Scelta sistema di lavoro. diagramma :

Figura 11:UC 2.0.0.0 - scelta del sistema di gestione del database: sulle singole tabelle o sul sistema centrale attori : Utente. scopo e descrizione : Dopo l’avvio del sistema, e come rappre- sentato nel diagramma in Figura 11, l’utente può decidere di la- vorare direttamente su una tabella da lui selezionata (UC2.1.0.0) oppure di selezionare il sistema di gestione centrale (UC2.2.0.0) da cui potrà operare diverse operazioni in modo più facilitato. precondizione : L’utente ha selezionato in precedenza o l’UC1.1.0.0 oppure l’UC1.3.0.0. Il database del sistema è quindi postcondizione : L’utente ha la possibilità di lavorare su di una tabella da lui selezionata, oppure può interagire con il sistema centrale. 98 analisi del problema

illustrazione scenario principale : Dopo l’avvio del databa- se, la prima interazione che l’utente ha con il sistema di gestione dei dati archiviati, riguarda la scelta del sistema su cui operare. L’utente può selezionare una tabella (UC2.1.0.0) esistente nel database, oppure sceglie di interagire con il sistema centrale (UC2.2.0.0). Lo scenario termina o con una tabella selezionata, oppure con il sistema centrale pronto all’uso.

10.4.3 UC2.1.0.0

titolo : Lavorare su una tabella selezionata.

diagramma :

Figura 12:UC 2.1.0.0 - mostra come l’utente può interagire con una tabella selezionata in precedenza 10.4 usecase 99 attori : Utente, Server. scopo e descrizione : Come rappresentato nel diagramma - Figu- ra 12, quando l’utente seleziona una tabella, ha l’opportunità di manipolare i dati contenuti in essa (operazioni CRUD) oppure può scaricare/inviare i dati da/verso il server. L’use case mostra chiaramente la separazione logica tra il download e l’upload dei dati. precondizione : L’utente ha selezionato una tabella registrata nel sistema di archiviazione. postcondizione : L’utente ha eseguito un operazione CRUD sulla tabella selezionata, oppure ha scaricato il contenuto del server online oppure ha inviato i dati locali (“bozze”) al server. illustrazione scenario principale : L’utente dopo aver scel- to una tabella appartenente al sistema di archiviazione (UC2.1.0.0), è pronto per compiere uno dei seguenti passi: • eseguire un operazione CRUD sulla tabella selezionata (UC2.1.1.0); • inviare i dati “bozze” al server (UC2.1.2.0); • scaricare i dati presenti nella tabella del database online (UC2.1.3.0). illustrazione scenari alternativi : Nel caso l’utente tenti di operare un operazione di download o di upload in assenza di connettività, tali operazioni saranno annullate (UC2.1.4.0). 100 analisi del problema

10.4.4 UC2.1.1.0

titolo : CRUD su una tabella selezionata.

diagramma :

Figura 13:UC 2.1.1.0 - mostra come un utente può operare operazioni CRUD su di una tabella selezionata

attori : Utente.

scopo e descrizione : Quando un utente seleziona una tabella può farlo con lo scopo di operare delle operazioni CRUD su di essa. Ciò è espresso dal diagramma in Figura 13.

precondizione : L’utente ha scelto una tabella su cui eseguire un operazione CRUD.

postcondizione : L’utente ha portato a temine l’operazione sele- zionata.

illustrazione scenario principale : L’utente sceglie una del- le 4 operazioni possibili: • visualizza i record della tabella (UC2.1.1.1); 10.4 usecase 101

• inserisce un nuovo record nella tabella1 (UC2.1.1.2); • modifica di un record esistente nella tabella (UC2.1.1.3); • eliminazione di un record esistente nella tabella (UC2.1.1.4).

10.4.5 UC2.2.0.0

titolo :

diagramma :

Figura 14:UC 2.2.0.0 - il diagramma mostra le funzionalità predisposte per il sistema centrale

1 Ovviamente ciò prevede l’inserimento di dati. Ciò non viene raffigurato in ulteriori use case poiché non è direttamente correlato al sistema di archiviazione/sincronizza- zione. Inoltre come accennato in principio questi use case rappresentano un utilizzo generale e di conseguenza non è previsto l’inserimento di un record prestabilito dotato di dati particolari. 102 analisi del problema

attori : Utente, Server.

scopo e descrizione : Quando un utente seleziona il sistema cen- trale di gestione dei dati, lo fa con lo scopo di utilizzare una delle funzionalità messe a disposizione (Figura 14). Nello spe- cifico si intendono fornire sia delle funzioni per lavorare su di una tabella ben definita (e registrata nel sistema), che per ope- rare un download generale e una funzione di upload usata per inviare tutti i dati “bozza” al server.

precondizione : L’utente ha scelto di lavorare con il sistema cen- trale di gestione

postcondizione : L’utente ha eseguito con successo una delle ope- razioni predisposte per il sistema centrale.

illustrazione scenario principale : L’utente sceglie di com- piere una delle seguenti azioni: • esegue un operazione CRUD (UC2.1.1.0) specificando una tabella su cui compiere tale azione (UC2.2.1.0); • esegue un operazione di sincronizzazione specificando la tabella su cui compiere l’operazione (UC2.2.2.0); • esegue un operazione di upload generale (UC2.2.3.0); • esegue un operazione di download generale (UC2.2.4.0).

illustrazione scenari alternativi : Nel caso l’utente scelga di compiere o un operazione di download o upload generale, in assenza di connettività, tale operazione verrà interrotta. 10.4 usecase 103

10.4.6 UC2.2.2.0 titolo : diagramma :

Figura 15:UC 2.2.2.0 - funzioni disponibili per la sincronizzazione di una tabella a partire dal sistema centrale attori : Utente, Server. scopo e descrizione : Se l’utente ha scelto di lavorare con il siste- ma centrale, allo scopo di operare una sincronizzazione di una tabella ben definita e registrata in esso, allora si troverà nella si- tuazione espressa dal diagramma in Figura 15, e potrà scegliere di: • eseguire un’operazione di upload; • eseguire un’operazione di download. precondizione : L’utente sta lavorando con il sistema centrale, nel- lo specifico sceglie di eseguire un operazione di sincronizzazio- ne su di una singola tabella. postcondizione : L’utente ha portato a termine una delle due operazioni predisposte. illustrazione scenario principale : L’utente sceglie tra le due possibilità: • eseguire un’operazione di upload (UC2.1.2.0); • eseguire un’operazione di download (UC2.1.3.0); 104 analisi del problema

illustrazione scenari alternativi : In assenza di connetti- vità, indifferentemente dall’operazione scelta dall’utente, tale operazione termina.

10.5 requisiti

Di seguito sono esposti i requisiti estrapolati dal capitolato, dalla di- scussione con il tutor e dai casi d’uso. La nomenclatura dei requisiti Nomenclatura dei ne espone la tipologia. I requisiti classificati come RO sono requisi- requisiti. ti di carattere obbligatorio. I requisiti classificati come RD sono di carattere desiderabile (da prendere in considerazione previo soddi- sfacimento dei requisiti obbligatori, e qualora non sopraggiungano nuove direttive aziendali aventi priorità maggiore).

Requisiti Descrizioni

RO1.0.0 deve essere possibile scaricare il con- tenuto di un tabella (di un database online) archiviandone i dati in locale; RO1.1.0 all’avvio il device dovrà verificare la presenza di connettività, nel caso si sincronizza con il server; RO1.2.0 se all’avvio non c’è connettività l’ap- plicativo deve garantire comunque la possibilità di lavorare con i dati presenti in locale; RO1.3.0 i dati salvati in locale e non ancora in- viati al server, sono trattati come boz- ze: deve essere possibile modificarli e nel caso annullare il loro inserimento (ciò comporta una loro eliminazione dalla lista delle ”bozze”); RO1.3.1 le bozze devono essere memorizza- te in una struttura dati che permetta una rapida associazione e visualizza- zione ad uno degli strumenti di view proposti da Sencha (e.g. una lista); RO1.3.2 il componente deve essere predispo- sto a scartare una delle modifiche ap- portate (annullamento delle modifi- che inerenti un certo record di una qualsiasi delle tabelle del DB). Tale modifica viene riconosciuta per mez- zo di un identificatore univoco che la rappresenti nell’archivio delle bozze; 10.5 requisiti 105

RO1.3.3 per le esigenze aziendali è necessario che, mediante la componente, sia pos- sibile modificare record già esistenti (operazione di update); RD1.3.4 l’applicativo per cui è destinata la componente è pensato per fornire la possibilità di visualizzare e modifica- re record già esistenti. Comunque è da considerarsi desiderabile, la predispo- sizione della componente per l’archi- viazione tra le bozze, di operazioni le- gate all’aggiunta e alla cancellazione di record; RO1.4.0 i dati salvati in locale devono esse- re memorizzati in una struttura per- sistente che implementi un’architettu- ra il più vicino possibile a quella di un database relazionale. Nello specifi- co (stando agli studi apportati fino ad ora) si dovrà usare il WebSQL; RO1.5.0 i dati cosi archiviati devono esse- re persistenti, ed essere mantenu- ti anche in seguito alla chiusura dell’applicazione; RO1.6.0 deve essere possibile utilizzare, per l’archiviazione remota, un server qual- siasi. il sistema di sincronizzazione deve quindi essere indipendente dal dominio del server; RO2.0.0 deve essere possibile effettuare modi- fiche ai dati locali, anche se il device non è in linea; RO2.1.0 deve essere possibile eseguire un upload dei dati modificati in locale, aggiornando cosi i dati presenti nel database online; RD2.2.0 l’utente deve avere la possibilità di sca- ricare il contenuto del database online in locale, rimandando però l’upload dei dati modificati; 106 analisi del problema

RD2.2.1 la sincronizzazione on demand deve essere una procedura che coinvolge contemporaneamente tutti gli store dell’applicativo. Con una sincronizza- zione si aggiornano tutte le tabelle costituenti il database; RO3.0.0 la sincronizzazione dei dati avviene di default su richiesta; RD4.0.0 il sistema deve essere predisposto per garantire (come futura espansio- ne) la possibilità di eseguire un’auto- sincronizzazione basando la propria scelta su di un algoritmo intelligen- te (e.g. controllo della data dell’ultima sincronizzazione avvenuta); PROGETTAZIONE 11

11.1 logica di sistema

11.1.1 Sistema centrale di gestione

Per dare una chiara lettura del sistema con cui funziona il SyncEngine, inizierò parlando del sistema centrale di gestione, ossia la componen- te in cui risiedono le informazioni relative al database locale: il Sync- SyncManager: Manager. Questa classe ha lo scopo di registrare al suo interno, in un sistema centrale di array, il nome di tutti i SyncStore1 presenti nell’applicazione. L’ordi- gestione del database. ne con cui vengono registrati i SyncStore è importante e rappresenta anche l’ordine con cui vengono effettuati i download e gli upload dei dati. Quindi se inseriamo nel registro del SyncManager gli sto- reID: “mioPrimoStore” e “mioSecondoStore”, avremo che in seguito ad una richiesta di download, prima sarà scaricato “mioPrimoStore” e poi “mioSecondoStore”. Come vedremo nei paragrafi successivi, il SyncManager predispone diversi metodi di utilità, sia per creare dina- micamente i SyncStore, sia per registrare al suo interno dei SyncStore già creati in precedenza.

11.1.2 Sistema di gestione degli ID

Durante l’attività di progettazione è emersa una problematica d’implementazione del sistema di gestione degli id. In merito si è osservata la presenza di due possibilità:

• Risolvere il problema lato server: il server riceve i dati dai vari client, sprovvisti di id, quindi si occupa lui di inserirli nel pro- prio sistema assicurandosi di assegnare come chiave primaria per il record, un valore univoco nel sistema.

• Risolvere il problema lato client: ogni device è dotato di un pro- prio codice identificativo, con il quale genera una chiave prima- ria semplicemente concatenando un numero incrementante. Co- si facendo i dati inviati sono già univoci nel sistema, e il server può procedere ad inserire i record senza ulteriori controlli.

Analizzando le due possibilità risulta evidente come il primo si- stema risulti inattuabile . Infatti stiamo parlando di una componente Il primo sistema per la progettazione di app mobile. Quindi per dispositivi per il quale risulta troppo costoso e complesso.

1 SyncStore è il nome della componente rappresentante una tabella del database. Nei paragrafi successivi ne sarà data una descrizione più approfondita.

107 108 progettazione

vogliamo il minor numero possibile di operazioni complesse. Con il primo sistema, ogni volta che si inviano i dati al server, sarebbe neces- sario eseguire un’operazione di download per aggiornare nel proprio database locale gli id dei vari record inviati. La cosa diventa eviden- temente più complessa nel caso di basi di dati complesse con record che puntano ad altri record mediante un sistema a chiavi esterne (poi- ché per l’appunto le chiavi esterne puntano alla chiave primaria del record a cui si riferiscono). In ragione di ciò la seconda scelta è decisamente migliore. Il client costruisce immediatamente la chiave primaria e la spedisce al server, consapevole che i dati da lei creati non sono stati modificati dal ser- ver e che quindi non necessitano di un aggiornamento immediato. Per adempiere a tale ruolo viene usata una classe denominata Inde- IndexIDStore xIDStore . Questa, creata dal costruttore del SyncManager, si occupa sfrutta la seconda di detenere un contatore numerico per ogni SyncStore che viene re- idea: una gestione gistrato nel sistema. Ogni volta che un nuovo record viene aggiunto locale degli ID con l’assunzione che essi nel SyncStore, si procede richiedendo all’IndexIDStore un nuovo id. siano univoci in Questa operazione si riassume in un incremento del contatore asso- tutto il sistema. ciato, e con la restituzione del medesimo valore. Sarà poi compito del SyncStore in uso, quello di concatenare tale valore numerico all’id del device. Quest’ultimo è una delle informazioni passate al costruttore di SyncManager, il quale lo restituirà ad ogni SyncStore che crea e che, di conseguenza, in esso viene registrato.

11.1.3 Store sincronizzabile

Ora introdurrò quello che si può definire come il cuore dei sistema SyncEngine: il SyncStore. Questi oggetti rappresentano il vero e pro- prio cuore del sistema. Possiamo pensare a loro come alle tabelle del nostro database. Ogni SyncStore è un estensione degli Ext.data.Store normali, definiti da Sencha, con un proxy di tipo Sql atto a generare una tabella da noi specificata in un db da noi specificato. Alla crea- zione questi store usano due factory method per generare due store CommitStore e di supporto: CommitStore e DownloadStore. Il primo, avente un pro- DownloadStore. xy di tipo sql, condivide con il SyncStore la base del modello, qui ridefinito al fine di contenere un campo in più: typeCommit. Questo viene usato per indicare la tipologia del record. CommitStore funge infatti da ”bozza” per i dati elaborati in locale. Ogni volta che trattia- mo un record mediante un operazione di add, update o delete, quel record viene notificato inserito nel CommitStore con il typeCommit Annotazioni per la appropriato: classificazione delle bozze. • a: indica che il nuovo record è stato appena inserito. Questo è quindi un record nuovo e non ancora inviato al server;

• u: indica che il record, di base presente sul database, è stato modificato in locale, ma le modifiche apportate non sono ancora 11.1 logica di sistema 109

presenti sul database online;

• d: indica che il record, di base presente sul database, è stato eliminato dal db locale, ma la sua eliminazione non è ancora avvenuta sul database online.

Ogni volta che al SyncStore viene richiesto di operare un upload dei dati, questo controlla prima la presenza di connettività, e l’effet- tiva presenza di dati da inviare. Nel caso, genera una richiesta AJAX ed invia al server una stringa JSON contenente tutti i dati presenti nel CommitStore. Al termine, se l’operazione ha avuto successo, il CommitStore viene svuotato dalle “bozze”. Invece per quanto riguarda il DownloadStore (store con proxy Jsonp), il suo scopo è quello di contenere i dati scaricati dal server. Il funzio- namento nel dettaglio è il seguente: Iter di un’operazione di download. • SyncStore riceve una richiesta di download dei dati;

• il DownloadStore viene ricaricato mediante il metodo load(), provocando un download dei dati presenti sul database onli- ne (ovviamente per la tabella del database rappresentata dal SyncStore in esame);

• se l’operazione di download è andata a buon fine, i dati me- morizzati nel SyncStore vengono eliminati e sostituiti con quelli presenti nel DownloadStore;

• quindi i dati attualmente presenti nel SyncStore vengono modi- ficati imponendo le modifiche rappresentate dai record ”bozza” contenuti nel CommitStore: – i record contrassegnati con typeCommit = “a” vengono aggiunti agli elementi presenti nel SyncStore; – i record contrassegnati con typeCommit = “u” vengono ag- giunti agli elementi presenti nel SyncStore in sostituzione agli elementi obsoleti, e di cui i record appena aggiunti rappresentano la modifica; – i record contrassegnati con typeCommit = “d” vengono ricercati nel SyncStore ed eliminati dal medesimo.

Al termine di tale operazioni, la memoria viene liberata proceden- do con l’eliminazione dei dati presenti in DownloadStore.

11.1.4 AddCommit, UpdateCommit e DeleteCommit

Il SyncStore definisce inoltre 3 tipologie di operazioni (in relazione alle 3 tipologie di typeCommit). Le operazioni sono:

• addCommit(): crea un’istanza di AddCommand, per aggiunge- re un nuovo record; 110 progettazione

• updateCommit(): crea un’istanza di UpdateCommand, per mo- dificare un record;

• deleteCommit(): crea un’istanza di DeleteCommand, per rimuo- vere un record.

Le tre classi menzionate sono figlie di StoreOperation, la quale definisce un costruttore comune e un insieme di dati usati nell’ese- cuzione delle operazioni. Entrambe adempiono al proprio compito mediante una chiamata al metodo execute(). Il sistema è simile ad un’implementazione del pattern strategy.

11.1.5 Il problema del multi-tap

Uno dei problemi riscontrati durante l’attività di studio, legati al do- minio tecnologico, è la gestione del multi-tap. Durante una prova effettuata sul prototipo di studio si è infatti osservato che: premen- do ripetutamente un pulsante della view si generano ripetuti eventi di tap. Questi vengono ovviamente presi e gestiti dal controller che ha predisposto una porzione di codice per la risoluzione del evento. Tuttavia mancando la mutua esclusione in JavaScript, questi blocchi di codice vengono eseguiti più volte e parallelamente, in linea con il numero di tap eseguiti sul pulsante. Una gestione mediante variabili booleane è purtroppo insufficiente, poiché queste non sono operazioni atomiche. L’unica alternativa indi- viduata è stata quella di predisporre un bottone in grado di accettare unicamente solo il primo tap in una sequenza continua in cui ogni tap può essere separato dall’altro da un certo intervallo temporale. Cosi facendo il bottone non reagirà ad una richiesta di multi-tap, ma unicamente ad un tap singolo. SingleTapButton, è L’oggetto predisposto a tale scopo prende il nome di SingleTapBut- la soluzione al ton. Per capire ulteriormente il problema e poter visionare il codice su problema del cui tale componente è basato, rimando il lettore alla sezione “Gestire multi-tap. il multi-tap”.

11.1.6 Composizione del server

Durante lo stage il mio unico scopo legato alla progettazione del Syn- cEngine è stata la creazione dell’applicativo lato client. Il server non è stato curato direttamente da me, ma una sua implementazione è stata realizzata dal tutor aziendale. Il server in questione ha un’implementazione basilare e nel com- plesso può ancora essere migliorato. Di base l’idea è stata quella di predisporre una pagina .aspx.vb per ogni tabella del database2. Que- ste pagine definiscono due comportamenti di risposta alla richiesta

2 l’URL memorizzato in un SyncEngine punta esattamente a tale pagina. 11.1 logica di sistema 111

JSON. La prima verifica se il contenuto della stringa JSON inoltrata al server è vuota. Nel caso esegue la query:

SELECT * FROM nome_tabella ORDER BY attributo

Quindi ritorna al client una stringa contenente i record ottenuti dalla query precedente. Di seguito propongo un codice per l’imple- mentazione di questa funzionalità. Nello specifico si tratta del codice di Note.aspx.vb.

Listing 19: SyncEngine - server: operazione di download

1 ...

Dim operation As String = Request.Params("operation") Dim cb As String = Request.Params("callback")

6 If String.IsNullOrEmpty(operation) Then

Dim dt As DataTable = SharedFunctions.getDataTable("SELECT ∗ FROM Note ORDER BY t i t l e ")

11 Dim responseString As String = "{success: true}" Dim jsonString As String = SharedFunctions.GetJson(dt)

If Not String.IsNullOrEmpty(cb) Then Response.ContentType = "text/javascript" 16 responseString = cb & "(" + jsonString & ")" Else responseString = jsonString End If Response.Write(responseString) 21 ...

Invece se si osserva che la stringa non è vuota, il server capisce che la richiesta inoltrata dal client non è di download ma di upload. Quindi inizia a prendere in considerazione ogni record inviato. Ana- lizzando il contenuto dell’attributo typeCommit può determinare l’o- perazione da eseguire sul database. Nello specifico:

• typeCommit = ’a’: il server deve eseguire un’operazione di in- sert di un nuovo record;

• typeCommit = ’u’: viene eseguita un’operazione di update di un record già esistente;

• typeCommit = ’d’: deve essere seguita un’operazione di delete di un record già esistente. 112 progettazione

Quindi dopo aver eseguito l’operazione giusta per ogni record, il server termina comunicando il successo dell’operazione al client. Per quanto riguarda le operazioni di update e delete queste si basano ovviamente sulla presenza di un record di riferimento nel server. Se tale record manca allora il server interrompe l’operazione e comunica il fallimento dell’operazione di update. Va da se che tale comporta- mento non può ritenersi completamente valida in un’applicazione ultimata e pronta per essere commercializzata. Infatti nelle future im- plementazioni tale componente dovrà essere rivista prevedendo un comportamento più scalabile.

11.2 descrizione delle classi

In queste sezioni vengono trattate in dettaglio tutte le classi che costi- tuiscono il sistema. Per accompagnare il lettore nell’apprendimento di tale struttura, le classi vengono introdotte in base alla loro funzio- ne principale anziché per package3 di appartenenza. La ripartizione concettuale per componenti prende la nomenclatura CSEn (Compo- nent SyncEngyne) e CSEIn (Component SingleEventItem), dove la n indica il numero della componente. Di ogni classe saranno date le seguenti informazioni:

• nome della classe;

• scopo della classe;

• package che la contiene.

• pattern usati.

• classe estesa;

• attributi contenuti nel config della classe;

• metodi della classe;

Si ricorda che la ripartizione delle classi in package cerca di rispet- Principi di tare il più possibile i seguenti concetti: ripartizione delle classi in package. • Scopo del package: le classi inserite in un dato package devono avere lo stesso scopo;

• Manutenibilità: la modifica di una classe può richiedere (al più) la modifica delle classi appartenenti allo stesso package.

3 Si suppone che il nome di un package possa essere in un primo momento privo di informazioni utili per il lettore. In una prima progettazione concettuale si intende mettere in evidenza il collegamento scopo-classe. Successivamente il lettore avrà modo di inquadrare le classi (di cui conosce già lo scopo) nei rispettivi package. 11.2 descrizione delle classi 113

11.2.1 CSE1 - Gestione ID

11.2.1.1 IndexIDModel scopo : Rappresenta il modello dei dati cui si appoggia lo store IndexIDStore.

package : org.s2.syncEngine.idHandler.

classe estesa : Ext.data.Model.

pattern usati : nessuno.

config : Contiene i campi dati fields del modello: storeID (di tipo string) e indexCount (di tipo int). Il primo deve contenere il no- me della tabella (store) registrata nel sistema di archiviazione dati. Il secondo campo rappresenta l’ultimo id numerico usato nella creazione di un record della tabella a cui si riferisce l’istan- za di IndexIDModel. Ciò significa che se viene registrato uno store “A”, deve essere creata un istanza IndexIDModel avente i valori: storeID = A e indexCount = 0. L’aggiunta di un record in “A” comporta deve comportare l’incremento di indexCount4.

metodi : Nessun metodo evidenziato.

11.2.1.2 IndexIDProxy scopo : Rappresenta il proxy usato da IndexIDStore. Non presenta nessuna modifica sostanziosa rispetto alla classe che estende. Semplicemente ridefinisce il costruttore.

package : org.s2.syncEngine.idHandler.

classe estesa : Ext.data.proxy.Sql.

pattern usati : nessuno.

config : Nessun attributo da evidenziare

metodi : Contiene il costruttore della classe, abilitato alla creazio- ne di un istanza di IndexIDProxy configurando il valore data- base (di Ext.data.proxy.Sql) mediante il valore ricevuto come parametro d’ingresso.

11.2.1.3 IndexIDStore scopo : Rappresenta lo store usato dal sistema per la gestione degli id.

package :org.s2.syncEngine.idHandler.

4 L’operazione di incremento appartiene a IndexIDStore. 114 progettazione

classe estesa : Ext.data.Store.

pattern usati : Observer (in Ext.data.Store).

config : • model: riferimento al modello utilizzato dallo store (org.s2.syncEngine.idHandler.IndexIDModel); • storeId: alias identificativo dello store; • proxy: riferimento al proxy usato dallo store (org.s2.syncEngine.idHandler.IndexIDProxy); • autoLoad: booleano usato per impostare il load automa- tico dello store al momento della creazione dello stesso. l’attributo è impostato a true.

metodi : • loadStoreIndex: metodo usato per registrare un SyncStore nel sistema, mediante l’inserimento di un record nello sto- re IndexIDStore. Il record inserito avrà il valore di storeID uguale al valore storeId dello store registrato; • increment: dato l’id di uno store, verifica se tale è registrato in IndexIDStore. Nel caso incrementa il valore indexCount del record associato; • getNewID: dato l’id di uno store, verifica se tale è registra- to in IndexIDStore. Nel caso restituisce il valore numerico del nuovo id utilizzabile dallo store per l’inserimento di un nuovo record;

11.2.1.4 IndexIDStoreFactory scopo : Rappresenta la classe factory per la creazione dell’IndexID- Store.

package : org.s2.syncEngine.idHandler.

classe estesa : Ext.Class.

pattern usati : factory method.

config : • storeName: nome con cui sarà creato lo store. Di default è IndexIDStore; • custumProxy: riferimento al proxy da utilizzare. Inizial- mente a null, il valore sarà reimpostato dal costruttore;

metodi : • costructor: costruttore della classe usato per reimpostare il valore di customProxy con un istanza di IndexIDProxy, modificata con il valore dbName richiesto dall’utilizzatore; 11.2 descrizione delle classi 115

• createIndexIDStore: usando Ext.create crea un’istanza di IndexIDStore impostando il valore storeId con il contenuto di storeName, e proxy con il valore di customProxy.

11.2.2 CSE2 - Store sincronizzato

11.2.2.1 DownloadStoreFactory scopo : Rappresenta la classe factory usata per definire e creare lo store DownloadStore. Questo viene creato mediante un costrut- tore che definisce l’URL a cui deve puntare DownloadStore. Il proxy usato sarà quindi di tipologia JsonP. package : org.s2.syncEngine.basicSyncStore.download. classe estesa : Ext.Class. pattern usati : factory method. config : • url: contiene l’URL usato dal proxy JsonP; • appName: contiene il nome dell’applicazione. Viene usato nella creazione del nome del DownloadStore; • modelName: parametro contenente il nome del modello associato al DownloadStore; • pathModel: nome completo del modello usato dal Down- loadStore. Per nome completo intendo una stringa del tipo: nomeApp.model.nomeModello; • nameDownloadStore: contiene il nome da usare per la crea- zione del DownloadStore. metodi : • costructor: costruttore della classe usato per impostare il valore dei parametri di config. Questi vengono presi dal- l’unico parametro accettato dal costruttore (property conf), specificando con una sintassi del tipo “.nomeParametro” il valore da estrarre dalla property; • createDownloadStore: usando Ext.create crea un’istanza di un oggetto DownloadStore, specificandone direttamente la struttura. Per impostare i vari attributi di configurazione dello store (e.g. il modello associato) richiama i valori dei parametri di config del oggetto DownloadStoreFactory.

11.2.2.2 CommitStoreFactory scopo : Rappresenta la classe factory usata per definire e creare lo store CommitStore. Questo viene creato mediante un costrutto- re che definisce i parametri di configurazione dello store. Data 116 progettazione

la necessità di archiviare i dati “bozza” in locale, e con una strut- tura analoga al modello del SyncStore assocaito, il proxy sarà di tipo Sql.

package : org.s2.syncEngine.basicSyncStore.upload.

classe estesa : Ext.Class.

pattern usati : factory method.

config : • pathModel: nome completo del modello usato dal Com- mitStore. Per nome completo intendo una stringa del tipo: nomeApp.model.nomeModello; • nameCommitStore: contiene il nome da usare per la crea- zione del CommitStore. • dbName: nome del database SQLite (o meglio del data- base WebSQL) in cui sarà inserita la tabella generata dal CommitStore.

metodi : • costructor: costruttore della classe usato per impostare il valore dei parametri di config. Questi vengono presi dal- l’unico parametro accettato dal costruttore (property conf), specificando con una sintassi del tipo “.nomeParametro” il valore da estrarre dalla property; • createDownloadStore: usando Ext.create crea un’istanza di un oggetto CommitStore, specificandone direttamente la struttura. Per impostare i vari attributi di configurazione dello store (e.g. il modello associato) richiama i valori dei parametri di config del oggetto CommitStoreFactory.

11.2.2.3 SyncStore scopo : Store di tipo Sql che rappresenta una tabella del database dell’applicazione. In associazione al proprio CommitStore e al proprio DownloadStore, garantisce la possibilità di sincronizza- re i dati della tabella associata con i dati presenti nel server.

package : org.s2.syncEngine.basicSyncStore.

classe estesa : Ext.data.Store.

pattern usati : Factory method, observer (in Ext.data.Store).

config : • model: modello associato al SyncStore, intesto come strin- ga completa del nome; 11.2 descrizione delle classi 117

• modelName: nome del modello associato al SyncStore (con- tiene la parte finale del nome riportato in model); • tableID: nome della tabella rappresentata dallo store. Il no- me qui impostato sarà quello che comparirà nel database WebSQL; • remoteURL: url di riferimento alla tabella associata al Sync- Store, e presente nel database del server; • storeId: identificativo del SyncStore; • deviceId: identificativo del dispositivo su cui è installata l’applicazione. Usato per la generazione degli id da usare nei record; • appName: nome dell’applicazione in cui è inserito il Syn- cEngine; • myDbName: nome del database in cui collocare la tabella associata al SyncStore; • commitStore: contiene il nome del CommitStore usato per la memorizzazione delle bozze; • downloadStore: contiene il nome del DownloadStore usa- to per scaricare e archiviare (temporaneamente) i dati in arrivo dal server; • autoLoad: flag booleano per stabilire se lo store deve essere caricato al momento della creazione. Di default è imposta- to a false; • disableDownload: flag booleano usato per disabilitare il do- wnload durante una procedura di upload, o in seguito ad una precedente richiesta di download. Il flag viene riporta- to a false (download abilitato) solo al termine di una delle due attività precedentemente elencate; • listener: listener usato per la gestione degli eventi. In esso sono definite le funzioni per l’iter di load e download dei dati. metodi : • costructor: costruttore per l’inizializzazione dei parametri di confing. Al termine di tale attività richiama i metodi initCommitStore e initDownloadStore; • getParent(): metodo usato per ottenere il nome dell’istanza di SyncStore; • initCommitStore: metodo usato per l’impostazione dei pa- rametri di creazione del CommitStore. Usando Ext.create crea un’istanza di CommitStoreFactory, dalla quale genera il CommitStore associato. Termina impostando la variabile di config commitStore con il nome del CommitStore creato; 118 progettazione

• initDownloadStore: metodo usato per l’impostazione dei parametri di creazione del DownloadStore. Usando Ext.create crea un’istanza di DownloadStoreFactory, dalla quale ge- nera il DownloadStore associato. Termina impostando la variabile di config downloadStore con il nome del Down- loadStore creato; • clearTable: metodo usato per cancellare il contenuto del- la tabella rappresentata dal SyncStore. Più in linea con la struttura di Sencha, si può affermare che cancella i dati presente nel proxy dello store5. • download: metodo usato per avviare l’iter di download dei record dal server. Come prima azione imposta il flag disa- bleDownload a true e carica il downloadStore se si rileva la presenza di connettività6. • downloadTemplate: metodo eseguito a partire dal listener per processare una richiesta di download. Il listener pro- cede in tal senso quando rileva l’esecuzione del metodo clearTable() propedeutico all’aggiornamento del contenuto di SyncStore. Il metodo non fa altro che copiare i dati ar- chiviati nel DownloadStore nel SyncStore. Quindi esegue il metodo per l’aggiornamento del SyncStore alle modifiche locali, eseguendo applyLocalChange(). • apllyLocalChange: metodo richiamato da downloadTem- plate() per modificare il contenuto dei dati appena scaricati, con le “bozze” locali. In tal modo l’utente può aggiornare i propri dati vedendo comunque le modifiche locali da lui eseguita ma non ancora inviate al server. • upload: metodo usato per inviare i dati al server. In ca- so vi sia connettività e ci sia almeno una bozza da invia- re al server, il metodo imposta disableDownload() a true, quindi procede al upload dei dati. Per farlo crea una ri- chiesta JSON mediante Ext.create (uso del pattern factory method), in cui inserisce tutti i record bozza. Quindi in- via la richiesta all’url specificato durante la creazione del CommitStore. In caso di successo il metodo procede eli- minando il contenuto delle bozze. In ogni caso il metodo termina riabilitando disableDownload(). • addCommit: metodo usato per l’esecuzione di un operazio- ne di add. Per farlo viene creata un’operazione AddCom- mit() mediante Ext.create. Quindi esegue il metodo exe-

5 Essendo di tipo Sql qui si fa uso del metodo dropTable() di Ext.data.ptoxy.Sql. Si osservi che, in linea con quanto riportato nelle conclusioni della parte di studio su Sencha, dropTable() è erroneamente segnalato nella documentazione Sencha come un metodo privato. 6 Per rilevare la presenza di connettività ho usato Ext.device.Connection.isOnline(). 11.2 descrizione delle classi 119

cute() dell’istanza creata. Termina distruggendo la classe AddCommit. • updateCommit: metodo analogo ad addCommit, usato pe- rò per un’operazione di update di un record. Per farlo si appoggia alla classe UpdateCommit. • deleteCommit: metodo analogo ad addCommit, usato pe- rò per un’operazione di delete di un record. Per farlo si appoggia alla classe DeleteCommit.

11.2.3 CSE3 - CRUD

11.2.3.1 StoreOperation scopo : Classe estesa da tutte le operazioni eseguibili sul SyncSto- re, atte ad attuare una manipolazione dei dati. Implementa il pattern strategy tramite le sue classi figlie. package : org.s2.syncEngine.basicSyncStore.storeCommand. classe estesa : Ext.Class. pattern usati : Strategy. config : • recordToUse: record usato dall’operazione. Istanza del mo- dello usato dal SyncStore; • tableID: nome del campo di SyncStore, usato come chiave primaria della tabella associata; • deviceId: identificativo del dispositivo in cui è in uso il SyncEngine; • commitModel: modello associato al CommitStore. Utile per tutte quelle operazioni che hanno bisogno di conoscere la struttura di un record presente in CommitStore; • commitStore: storeId del CommitStore. Usato come para- metro in Ext.getStore(), permette di ottenere un riferimento al CommitStore; • syncStore: riferimento al SyncStore interessato dal opera- zione. metodi : La classe contiene solo un costruttore, usato per inizializ- zare il contenuto degli attributi di config.

11.2.3.2 AddCommit scopo : Classe figlia di StoreOperation, implementa mediante il me- todo execute() il pattern strategy. Lo scopo della classe è quel- lo di fornire un mezzo per l’esecuzione di un operazione di inserimento di un record nel SyncStore. 120 progettazione

package : org.s2.syncEngine.basicSyncStore.storeCommand.

classe estesa : StoreOperation.

pattern usati : Strategy.

config : Nessun attributo evidenziato.

metodi : La classe contiene solo un metodo execute() usato per ese- guire l’operazione di inserimento. Il metodo inizia eseguendo una copia del record da inserire. Quindi esegue una ricerca nel SyncStore per verificare che il record di cui si richiede l’inseri- mento non sia già presente nel sistema (la ricerca avviene per chiave primaria tableID). Se il record esiste già, il metodo dele- ga l’operazione di update al metodo execute() di un’istanza di UpdateCommit. In caso contrario procede richiedendo un nuo- vo id numerico all’IndexIDStore del sistema. Successivamente concatena al valore di deviceId, il nuovo identificativo numeri- co. Cosi facendo ottiene un id univoco non solo per il database locale, ma anche per tutto il sistema presente nel server (poi- ché un deviceId è posseduto esclusivamente da un dispositivo). A questo punto viene creato un record avente come id quello creato in precedenza e come typeCommit il valore “a”. Il record di partenza (recordToUse) viene quindi inserito nel SyncStore mentre il nuovo record creato viene inserito nel CommitStore.

11.2.3.3 UpdateCommit scopo : Classe figlia di StoreOperation, implementa mediante il me- todo execute() il pattern strategy. Lo scopo della classe è quel- lo di fornire un mezzo per l’esecuzione di un operazione di modifica di un record esistente nel SyncStore.

package : org.s2.syncEngine.basicSyncStore.storeCommand.

classe estesa : StoreOperation.

pattern usati : Strategy.

config : Nessun attributo evidenziato.

metodi : La classe contiene solo un metodo execute() usato per ese- guire l’operazione di modifica. All’inizio del metodo viene ese- guita una copia di backup del record da usare. Quindi si proce- de definendo un record valido per il modello del CommitStore. Tale istanza sarà popolata con i dati presente in recordToUse (poiché il modello di base è lo stesso). In aggiunta però viene inserito nel campo typeCommit il valore “u”. Il metodo termi- na eliminando il record obsoleto dal SyncStore, inserendo la copia di backup di recordToUse e inserendo nel CommitStore il record creato al passo precedente. 11.2 descrizione delle classi 121

11.2.3.4 DeleteCommit scopo : Classe figlia di StoreOperation, implementa mediante il me- todo execute() il pattern strategy. Lo scopo della classe è quel- lo di fornire un mezzo per l’esecuzione di un operazione di eliminazione di un record esistente nel SyncStore. package : org.s2.syncEngine.basicSyncStore.storeCommand. classe estesa : StoreOperation. pattern usati : Strategy. config : Nessun attributo evidenziato. metodi : La classe contiene solo un metodo execute() usato per ese- guire l’operazione di eliminazione. Alla base del suo funziona- mento vi è una considerazione legata allo stato del record da usare. Si considerino i seguenti casi: • il record da eliminare è un record che non è presente in typeCommit, ne come record da aggiunto in sessione ne come record modificato; • il record da eliminare è un record presente in typeCommit o come record aggiunto o come record modificato. La presenza di questi due casi necessita di essere gestita come segue. All’inizio si effettua una copia di backup del record da usare (recordToUse). Quindi si procede eliminando il record dal SyncStore. A questo punto si controlla se esiste in CommitStore, un record avente come id quello del record da eliminare. Se si elimina quel record. Il metodo termina creando un record appartenente al model di CommitStore, popolato con i valori di recordToUse e con typeCommit uguale a “d”, e inserendo tale record in CommitStore.

11.2.4 CSE4 - Sistema centrale

11.2.4.1 MyDeviceInfo scopo : Classe usata per definire una raccolta di informazioni legate al dispositivo. In questa implementazione di base sono presenti solo l’identificativo del dispositivo e un metodo stub per ottene- re la connettività a partire da Ext.device.Connection.isOnline(). package : org.s2.syncEngine. classe estesa : Ext.Class. pattern usati : Nessuno. 122 progettazione

config : L’unico attributo presente è deviceID, il cui scopo è conte- nere l’identificativo univoco del dispositivo.

metodi : • consctructor: costruttore usato per inizializzare il valore di deviceID; • isOnline: stub al metodo isOnline della classe Ext.device.Connection. Usato per rilevare la presenza di connettività.

11.2.4.2 SyncManager 11.2.5 CSIE1 - Multi-tap

scopo : Oggetto che rappresenta il sistema centrale per la gestione del database. Con esso è possibile non solo creare le varie ta- belle (intese come SyncStore) del database, ma anche eseguire delle operazioni CRUD specificando il SyncStore (registrato nel sistema) su cui si desidera operare.

package : org.s2.syncEngine

classe estesa : Ext.Class.

pattern usati : Factory method.

config : • dbName: contiene il nome del database; • appName: contiene il nome dell’applicazione in cui è ese- guito il SyncEngine; • registry: è il registro contenente i nomi (storeId) di tutti i SyncStore registrati nel sistema; • deviceInfo: contiene un riferimento ad un oggetto MyDe- viceInfo; • indexStore: contiene lo storeId dell’IndexIDStore usato per gestire gli ID.

metodi : • constructor: costruttore usato per inizializzare gli attributi di config. Durante tale processo il metodo opera un creazio- ne (Ext.create) di un istanza di MyDeviceInfo, il cui riferi- mento è salvato in deviceInfo. Termina eseguendo il meto- do createIndexStore() a cui passa come parametro il nome del database in cui inserire l’IndexIDStore; • getStore: metodo di stub a Ext.getStore, che permette di ottenere un oggetto Ext.data.Store esistente nel sistema, a partire dallo storeId con cui è stato creato; 11.2 descrizione delle classi 123

• getDeviceID: metodo di stub a MyDeviceInfo.getDeviceID(). Permette di ottenere l’identificativo univoco del dispositi- vo, contenuto in deviceInfo; • createIndexStore: metodo implementante il pattern factory method, usato per creare IndexIDStore a partire dal no- me del database in cui va inserito. Per farlo, il metodo, crea un’istanza di IndexIDStoreFactory passando i parame- tri necessari. Quindi esegue il metodo createIndexIDStore() dell’istanza creata. Il metodo termina operando il load di IndexIDStore; • createSyncStore: metodo implementante il pattern factory method, usato per creare una nuova istanza di un SyncSto- re usando il metodo Ext.create(). Al termine dell’operazio- ne richiama il metodo registerStore, a cui passa lo storeId del SyncStore appena creato; • registerStore: metodo usato per registrare un SyncStore nel sistema. Per farlo controlla la validità dello storeId da usa- re. Se valido (diverso da undefined) allora procede inseren- dolo in registry; • find: metodo usato per operare la ricerca di uno storeId dentro a registry. Se la ricerca ha esito positivo, il metodo termina ritornando la posizione dello storeId all’interno di registry. In caso contrario ritorna il valore -1; • loadSyncStore: metodo usato per operare il caricamento di un SyncStore registrato nel sistema. Il metodo prima di procedere in tal senso, opera una ricerca in registry me- diante il metodo find. Solo se la ricerca ha esito positivo, il SyncStore designato viene caricato; • addToStore: metodo che dato uno storeId ed un record (un’istanza di un Ext.data.Model) opera un operazione di inserimento del record dato nel SyncStore specificato (uso di SyncStore.addCommit()). Ciò avviene se e solo se il Sync- Store designato è registrato nel sistema (presente nel regi- stro registry); • updateInStore: metodo che dato uno storeId ed un record (un’istanza di un Ext.data.Model) opera un operazione di modifica del record dato nel SyncStore specificato (uso di SyncStore.updateCommit()). Ciò avviene se e solo se il Sync- Store designato è registrato nel sistema (presente nel regi- stro registry); • deleteFromStore: metodo che dato uno storeId ed un re- cord (un’istanza di un Ext.data.Model) opera un operazio- ne di eliminazione del record dato nel SyncStore specifica- to (uso di SyncStore.deleteCommit()). Ciò avviene se e solo 124 progettazione

se il SyncStore designato è registrato nel sistema (presente nel registro registry); • loadDatabase: metodo utilizzato per caricare (utilizzo del metodo load di Ext.data.Store) tutti i SyncStore registrati nel sistema (presenti quindi in registry.

11.2.5.1 SingleTapButton scopo : Definisce un bottone in grado di ripartire gli eventi di tap in due categorie gestite separatamente: singletap e doubletap. Molto utile per gestire il problema del multi-tap lato view.

package : org.s2.singleEventItem.button.

classe estesa : Ext.Button.

pattern usati : Nessuno.

config : Nessun attributo evidenziato

metodi : • initialize: inizializza il bottone associando agli eventi sin- gletap e doubletap i rispettivi metodi onSingleTap e On- DoubleTap; • onSingleTap: usando fireEvent genera un evento singletap. L’idea è di catturare esternamente questo evento per poter- lo gestire con un metodo appropriato; • onDoubleTap: usando fireEvent genera un evento double- tap. L’idea è di catturare esternamente questo evento per poterlo gestire con un metodo appropriato; 11.3 diagramma delle classi 125

11.3 diagramma delle classi

In Figura 16 è riportato il diagramma delle classi del sistema predi- sposto per l’archiviazione dei dati. In particolare è data anche una rappresentazione del package singleItemEvent. Questo non è diret- tamente collegato al pakage syncEngine, ma se ne raccomanda l’uso per una corretta interazione tra le viste dell’applicativo il SyncEngine.

Figura 16: Diagramma delle classi del sistema di archiviazione 126 progettazione

RD4.0.0 Il lettore voglia osservare anche la presenza di un package non predisposizione di descritto nella descrizione delle classi: syncStrategy. Questo è stato SyncStore per pensato in risposta al requisito RD4.0.0, il quale richiedeva la predi- evoluzioni future. sposizione dell’applicativo (a livello di progettazione) per la creazio- ne di algoritmi intelligenti di sincronizzazione (e.g) un algoritmo che operi un download ogni 5 minuti). Lo sviluppo di tale funzionalità è stato però giudicato aggiuntivo e non direttamente in linea con gli scopi principali del progetto. Tuttavia al fine di garantire una manu- tenzione evolutiva futura più facile da implementare, è stato chiesto che tale dettaglio fosse aggiunto nella progettazione. La classe BasicSyncStore funge da classe base (idealmente vorrebbe essere un’interfaccia), e dovrà essere estesa da ogni classe che intende sviluppare la funzionalità sopra descritta. Alla creazione di SyncMa- nager, l’utente passerà al costruttore un istanza di una classe figlia di BasicSyncStore, la quale sarà archiviata all’interno di SyncMana- ger. Da li potremmo abilitarla o disabilitarla a seconda del caso. La classe di sincronizzazione sarà eseguita da un thread (in JavaScript parliamo di web worker) che potrà stabilire in autonomia (secondo un pattern specificato) quando operare la sincronizzazione.

11.4 pattern utilizzati

Il sistema di cui in precedenza ho dato una rappresentazione grafica, fa uso di 3 pattern. Prima di procedere individuando la loro collo- cazione, voglio ricordare al lettore che a causa della particolarità del dominio tecnologico, l’uso di tali pattern non fa uso di interfacce e classi astratte. Pattern utilizzati. I pattern utilizzati sono:

singleton : usato nella progettazione della classe SyncManager. L’idea è che per ogni applicazione può esistere un unico sistema centrale di gestione del database.

factory method : usato nelle classi: • DownloadStoreFactory: per la creazione dello store di sup- porto per le operazioni di download; • CommitStoreFactory: per la creazione dello store per l’ar- chiviazione delle “bozze”; • IndexIDStoreFactory: per la creazione dello store IndexID- STore; • SyncStore: per la creazione delle istanze di StoreOperation, in risposta alla necessità di eseguire un operazione di add, update o delete; • SyncManager: per la creazione dei SyncStore che andranno a costituire il database dell’applicazione. 11.5 diagrammi di sequenza 127 strategy : pattern usato in StoreOperation. L’idea è che l’algoritmo per l’operazione vera e propria viene ridefinito nelle classi figlie di StoreOperation (AddCommit, UpdateCommit e DeleteCom- mit) mediante l’override del metodo execute().

In aggiunta alcune delle classi definite fanno già uso del pattern observer per via delle classi che estendono. Nello specifico tali ogget- Store e Proxy ti sono gli store ed i proxy. Si osservi infatti che una modifica ad un implementano il proxy provoca l’aggiornamento automatico di tutti gli store che rac- pattern Observer. colgono i record del proxy modificato. Analogamente la modifica di uno store provoca l’aggiornamento di tutte le liste (o altri componenti grafici appartenente al pacchetto Ext) a cui è associato.

11.5 diagrammi di sequenza

In questa sezione presento 2 diagrammi di sequenza utili per com- prendere meglio come le varie classi interagiscono tra loro per il compimento delle attività principali. I punti trattati riguardano:

• creazione di un SyncStore a partire da SyncManager (Figura 17);

• procedura di download di un SyncStore in presenza di connet- tività (Figura 18);

I diagrammi saranno proposti nell’ordine sopra riportato. Sottoli- neo che nell’ultimo diagramma, il caso trattato è solo quello di pre- senza di connettività. Ciò in quanto da una parte il caso di assenza di connettività è scarsamente interessante (il primo metodo chiamato termina immediatamente), e dall’altra i diagrammi di sequenza non sono lo strumento migliore per mostrare cicli e condizioni. 128 progettazione

Figura 17: Diagramma di sequenza 1 - creazione si un SyncStore a partire da SyncManager 11.5 diagrammi di sequenza 129

Figura 18: Diagramma di sequenza 2 - procedura di download

ANALISIDELPRODOTTOULTIMO 12

12.1 introduzione

In questo capitolo tratterò alcuni punti legati allo sviluppo del pro- dotto e al suo completamento. Nello specifico intendo:

• fornire al lettore un’analisi dettagliata del codice del SyncStore, che in un certo senso rappresenta il cuore del sistema SyncEn- gine;

• mostrare al lettore l’interfaccia grafica del prototipo modifica- to al fine di essere utilizzato con il sistema di archiviazione, aggiungendo considerazioni sulle metodiche di modifica;

• fornire al lettore le indicazioni su come usare il sistema a partire dal sistema centrale SyncEngine.

12.2 syncstore, analisi del codice

SyncStore è sicuramente l’oggetto più importante dell’intero sistema. In esso è presente quello che si può definire come il cuore del sistema di sincronizzazione. Di conseguenza è assai importante fornire al let- tore un’idea chiara del suo contenuto e di come sia stato strutturato anche nel codice. Di seguito propongo quindi il listato del SyncSto- re. Al suo interno sono stati inseriti diversi commenti utili per com- prendere meglio il funzionamento dell’oggetto e i vari step in cui si suddividono i metodi.

Listing 20: SyncStore

Ext.define( ’org . s2 .syncEngine. basicSyncStore . SyncStore ’, { 3 extend: ’Ext.data.Store’, alias: ’SyncStore’,

requires: [ 8 ’Ext.device.Connection’, ’org . s2 .syncEngine. basicSyncStore .upload. CommitStoreFactory ’, ’org . s2 .syncEngine. basicSyncStore .download. DownloadStoreFactory ’, ’org . s2 .syncEngine. basicSyncStore .storeCommand. DeleteCommit’,

131 132 analisi del prodotto ultimo

’org . s2 .syncEngine. basicSyncStore .storeCommand. UpdateCommit’, 13 ’org . s2 .syncEngine. basicSyncStore .storeCommand. AddCommit’ ],

config: { 18 //ATTENZIONE:i seguenti dati vanno inseriti dall ’utente con la logica qui specificata: //Si osservi anche il costruttore nel ramo conf. costructorRid model: ’ null ’, //model di riferimento modelName: ’ null ’, //inserire il nome del model tableID : ’ null ’, //id della tabella rappresentata dal model. usato per le PK 23 remoteURL: ’ null ’, //URL per la connessione remota al database storeId: ’ null ’, //ID dello store, idealmente uguale al nome dato alla classe deviceId: ’ null ’, //identificativo del device in cuie’ creato lo store. Usato per la generazione delle PK appName: ’ null ’, //nome dell’applicazione myDbName: ’ null ’, //nome del database in cui viene inserito lo store 28 //Store di tipo WebSQL usato per salvare le ’’ bozze’’ dei dati non ancora sincronizzati. commitStore viene svuotato dal suo contenuto al termine di ogni operazione RIUSCITA di invio dei dati. Vedere upload() per ulteriori informazioni in merito commitStore: ’ null ’, //contiene il nome dello store di commit commitModel: ’ null ’, downloadStore: ’ null ’, //contiene il nome dello store di download 33 autoLoad: false, disableDownload: false,

//per via dell’assincronia presente nelle operazioni di load degli store, si usa un listeners la cui struttura rappresenta anche gli step che intercorrono durante un operazione di download. listeners: 38 { //listener che resta in ascolto di un operazione di load. Richiamato solo al termine del load dello store ’load ’: function(scope, records, 12.2 syncstore, analisi del codice 133

successful, operation, eOpts ) { this.download(); 43 },

//listener che resta in ascolto di un operazione di download. Richiamato solo al termine del download dei record ’downloadCompleate’: function(scope, records, successful, operation, eOpts ) { 48 //caso base: nessun dato scaricato if(Ext.getStore(this. getDownloadStore()).getCount () == 0) { //nota: se sono qui disableDownload == true... devo riabilitarlo this.setDisableDownload( false); 53 return false; } //secondo step: eliminoi dati locali this.clearTable(); }, 58 //listener che resta in ascolto di un operazione di clear. Richiamato solo al termine dell’eliminazione dei dati presenti in SyncStore ’clearCompleate ’: function(scope, records , successful, operation, eOpts ) { this.downloadTemplate(); 63 } } },

constructor: function(conf) 68 { if(conf.costructorRid) { this.setModel(conf.model); this.setModelName(conf.modelName); 73 this.setTableID(conf.tableID); this.setRemoteURL(conf.remoteURL); 134 analisi del prodotto ultimo

this.setStoreId(conf.storeId); this.setDeviceId(conf.deviceId); this.setAppName(conf.appName); 78 this.setMyDbName(conf.myDbName); }

this.callParent(arguments);

83 this.setProxy({ type: ’ sql ’, database: this.getMyDbName() });

88 //creo il commit store this.initCommitStore(); this.initDownloadStore(); },

93 getParent: function() { //metodo usato nei test. Un istanza di un oggetto che eredita da SyncStore, sara’ in grado tramite questo metodo, di provare di essere un SyncStore return ’org . s2 .syncEngine. basicSyncStore . SyncStore ’; }, 98 //metodo usato per la creazione dello store di commit initCommitStore: function() { //variabili utili per la memorizzazione dei nomi 103 var pathModel = this.getAppName() + ’ .model. ’ + this.getModelName(); var nameCommitStore = this.getModelName() + ’ sCommitStore ’; //imposto le variabili di config coni nuovi nomi del modelloe dello store di commit this.setCommitModel(pathModel + ’CommitModel’); this.setCommitStore(nameCommitStore); 108 //creo un istanza della classe factory di CommitStore var myFactory = Ext.create( ’CommitStoreFactory ’, { pathModel: pathModel, nameCommitStore: nameCommitStore, 113 myDbName: this.getMyDbName() }); //eseguo la creazionee il caricamento del CommitStore. Al termine distruggo la factory myFactory.createCommitStore().load(); myFactory.destroy(); 12.2 syncstore, analisi del codice 135

118 },

initDownloadStore: function() { //variabili utili per la memorizzazione dei nomi 123 var pathModel = this.getAppName() + ’ .model. ’ + this.getModelName(); var nameDownloadStore = this.getModelName() + ’ sDownloadStore ’; //imposto le variabili di config coni nuovi nomi del modelloe dello store di download this.setDownloadStore(nameDownloadStore); //creo un istanza della classe factory di DownloadStore 128 var myFactory = Ext.create( ’DownloadStoreFactory ’ , { url: this.getRemoteURL(), appName: this.getAppName(), modelName: this.getModelName(), 133 pathModel: pathModel, nameDownloadStore: nameDownloadStore }); //eseguo la creazionee il caricamento del DownloadStore. Al termine distruggo la factory myFactory.createDownloadStore(this.getStoreId()); 138 myFactory.destroy(); },

//metodo usato per rimuovere ogni elemento dal SyncStore (inteso come store locale) clearTable: function() 143 { this.getProxy().dropTable(); this.removeAll(); this.sync(); //segnalo il termine della procedura di clear dello store 148 this.fireEvent( ’clearCompleate ’, this); },

download: function() { 153 if(this.getDisableDownload() || !Ext.device. Connection.isOnline()) { return false; } //ho connettivita’ 158 this.setDisableDownload(true); Ext.getStore(this.getDownloadStore()).load(); 136 analisi del prodotto ultimo

return true; },

163 downloadTemplate: function() { //avverto chei dati che sto per inserire nello store non sono nuovi, ma sono quelli scaricati dal db var myName = this.getStoreId(); var modelLongName = this.getAppName() + ’ .model. ’ + this.getModelName(); 168 //Per ogni record scaricato, procedo aggiungendo quel record allo store locale(SyncStore) Ext.getStore(this.getDownloadStore()).each( function(record) { var currentRecord = Ext.create( modelLongName,record.data); 173 Ext.getStore(myName).add(currentRecord); });

this.applyLocalChange(myName, this.getTableID(), this.getCommitStore());

178 //termino la procedura di downloade update dello store locale Ext.getStore(this.getStoreId()).sync(); this.setDisableDownload(false); },

183 //metodo usato per applicare le modifiche avvenute localmente, ai dati scaricaricati in seguito all’ esecuzione di this.download() applyLocalChange: function(storeName, idName, commitName) { Ext.getStore(commitName).each(function(record) { 188 if(record.get( ’typeCommit’) == ’a ’) { Ext.getStore(storeName).add( record.copy()); } if(record.get( ’typeCommit’) == ’u’) 193 { Ext.getStore(storeName).removeAt( Ext.getStore(storeName).find( idName,record.get(idName))); Ext.getStore(storeName).add( record.copy()); } if(record.get( ’typeCommit’) == ’d’) 12.2 syncstore, analisi del codice 137

198 { Ext.getStore(storeName).removeAt( Ext.getStore(storeName).find( idName,record.get(idName))); } }); }, 203 //metodo usato per inviarei dati al server. upload: function() { var commitName = this.getCommitStore(); 208 var toCommit = ’[’; var remote = this.getRemoteURL();

//non ci sono record nel CommitStore. Il metodo termina restituendo0 --> fallimento if(Ext.getStore(this.getCommitStore()).getCount() == 0) 213 { return 0; }

//assenza di connettivita’. Il metodo termina restituendo0 --> fallimento 218 if(!Ext.device.Connection.isOnline()) { return 0; }

223 //variabile usata per conteggiare il numero di record inseriti nella stringa JSON. Utile in fase di testingo per restituire un feed all’ utente var numElem = 0;

Ext.getStore(this.getCommitStore()).each(function (record) { 228 toCommit += Ext.encode(record.data) + ’,’ ; numElem++; });

toCommit = toCommit.substring(0,toCommit.length - 1); 233 toCommit += ’]’;

this.setDisableDownload(true);

var myId = this.getStoreId(); 238 var downloadName = this.getDownloadStore(); 138 analisi del prodotto ultimo

//creazione della richiesta JsonP perl’invio dei dati al server. //la richiesta genera in automatico una funzione di callback, iniettata nel codice, avente il compito di valutare la risposta del server. In caso di successo viene richiamata la funzione success, failure altrimenti. var requestUpload = Ext.data.JsonP.request({ 243 url: remote, params: { data: toCommit, operation: ’post ’ 248 }, success: function(response) { //se sono qui, ho inviato tuttii dati al server. //procedo eliminando il contenutp del CommitSTore 253 Ext.getStore(commitName). removeAll(); Ext.getStore(commitName).sync(); //riabilito il download. Ext.getStore(myId). setDisableDownload(false); return true;//successo 258 }, failure: function(response) { //riabilito il download Ext.getStore(myId). setDisableDownload(false); 263 return false;//fallimento } //chel’invio abbia successoo meno, il download viene sempre riabilitato, ma solo in risposta alla risposta del server,o inseguito allo scadere del timeout(condizione che provocal’ esecuzione di failure) });

268 return numElem; },

addCommit: function(toAdd) { 273 var myOperation = Ext.create( ’AddCommit’, { recordToUse: toAdd, 12.3 modifica del prototipo 139

tableID: this.getTableID(), deviceId: this.getDeviceId(), 278 commitModel: this.getCommitModel(), commitStore: this.getCommitStore(), scope: this }); this.executeOperation(myOperation); 283 },

updateCommit: function(toUpdate) { var myOperation = Ext.create( ’UpdateCommit’, 288 { recordToUse: toAdd, tableID: this.getTableID(), deviceId: this.getDeviceId(), commitModel: this.getCommitModel(), 293 commitStore: this.getCommitStore(), scope: this }); this.executeOperation(myOperation); }, 298 deleteCommit: function(toDelete) { var myOperation = Ext.create( ’DeleteCommit’, { 303 recordToUse: toDelete, tableID: this.getTableID(), commitModel: this.getCommitModel(), commitStore: this.getCommitStore(), scope: this 308 }); this.executeOperation(myOperation); },

//comando generale perl’esecuzione di una classe derivata da StoreOperation 313 executeOperation: function(myOperation) { myOperation.execute(); myOperation.destroy(); } 318 });

12.3 modifica del prototipo

Durante lo sviluppo del componente SyncEngine, ho operato una mo- difica al prototipo di studio al fine di adattarlo al sistema in via di definizione. Ciò mi ha permesso di: 140 analisi del prodotto ultimo

• avere una conferma sul buon esito dello sviluppo del SyncEngi- ne (in aggiunta ai già citati test di unità);

• valutare le difficoltà di modifica correttiva, derivante dalla tran- sizione dal vecchio sistema di archiviazione (proxy type Sql) al nuovo sistema (SyncEngine).

In merito posso osservare che le difficoltà di aggiornamento del prototipo sono state assai lievi. Fondamentalmente dipende dall’ap- proccio che si intende usare. Una modifica atta a sostituire tutte le chiamata allo store con il sistema centrale, ha un costo leggermen- te superiore al voler cambiare tali punti semplicemente sostituendoli con la nuova tipologia di store creata (il SyncStore). Tra queste l’ope- razione che ha richiesto più tempo è stata la sostituzione delle opera- zioni di add e remove con addCommit e deleteCommit. Per facilitare l’interazione di queste componenti con l’oggetto IndexIDStore, si rac- comanda di seguire i passi riportati nella prossima sezione. In parti- colare raccomando la creazione di un SyncManager direttamente nel lancher di app.js. Al termine della modifica le 3 view del prototipo si presentavano nel seguente modo (vedi Figura 19, 20 e 21):

Figura 19: Home del prototipo 12.3 modifica del prototipo 141

Figura 20: View per l’inserimento e la modifica di una nota 142 analisi del prodotto ultimo

Figura 21: View per l’inserimento di un nuovo autore 12.4 usare il syncmanager 143

12.4 usare il syncmanager

Il modo migliore per utilizzare il SyncManager è quello di crearne un’istanza nel lancher dell’applicazione (esattamente dove viene defi- nito il viewport della medesima). Al costruttore è necessario passare 3 parametri:

• dbName: nome che si desidera assegnare al database SQLite in cui saranno inserite le tabelle dei vari SyncStore;

• appName: nome dell’applicazione, importante per per l’asse- gnazione dei modelli ai SyncStore;

• deviceID: identificativo del dispositivo, usato per la generazione delle chiavi primarie (ovviamente sintetiche) da assegnare ai record da aggiungere in uno dei SyncStore.

La creazione del SyncManager avviene quindi nel seguente modo:

Listing 21: Esempio di creazione di un SyncManager

var myStoreManager = Ext.create( ’SyncManager’, 2 { dbName: ’NomeDatabase’, appName: ’NomeApplicazione’, deviceID: ’MioID’ });

Il passo successivo è la creazione e la registrazione dei SyncStore. Qui sono possibili due strade:

• Creazione dinamica di un SyncStore: si attua usando il metodo createSyncStore(conf) di SyncManager. Questo metodo crea un istanza di SyncStore a partire dalle informazioni contenute nella variabile di configurazione. Le informazioni richieste sono: – model: path completa del modello da associare allo store (e.g ’NotesApp.model.Author’); – tableID: nome del campo del modello, da usare come chia- ve primaria. Il nome usato non può essere la keyword ”id”. Si consiglia come best practice di definire il modello con un campo avente nome: nomeModel + id (e.g. per il model author, si consiglia di definire il campo da usare per le PK come ”authorID”; – remoteURL: URL da usare per contattare la funzione del server che è in grado di rispondere alle richieste CRUD del SyncStore; – storeId: identificativo dello store all’interno dell’applicazio- ne. Permette di ottenere il SyncStore, in una qualsiasi parte del programma utilizzando la funzione Ext.getStore(storeID). 144 analisi del prodotto ultimo

Segue un esempio del codice da usare per la creazione di un SyncStore:

Listing 22: SyncManager - uso di createSyncStore()

myStoreManager.createSyncStore( { model: ’NotesApp.model.Author ’, 4 tableID: ’authorID ’, remoteURL: ’http://srv1 . soluzioni−sw . i t/NotesWeb/Author. aspx ’, storeId: ’Authors ’ });

il metodo createSyncStore si occuperà automaticamente della registrazione del SyncStore nel sistema.

• Registrazione di un SyncStore già esistente: qualora si dispon- ga già del SyncStore da registrare nel sistema, o si desideri de- finirne uno ad hok con delle potenzialità extra, è possibile usa- re il metodo registerStore(storeId). Questa soluzione risulta es- sere pratica nel caso di aggiornamento di un’applicazione che non usa il SyncEngine e dispone già di alcuni store. Nel caso, basterà modificare gli store esistenti affinché siano estensioni di SyncStore, e in seguito garantirne la registrazione mediante l’istruzione registerStore().

Segue un esempio pratico che riassume quanto spiegato fin qui.

Listing 23: SyncManager - esempio di utilizzo

Ext.application({ name: ’NotesApp’, 3 models: [ ’Note’, ’Author ’], //Solo il SyncStore Notes viene caricato direttamente stores: [ ’Notes ’], views: [ ’NotesList’, ’NoteEditor’, ’NoteAuthor’, ’ AuthorPicker ’], controllers: [ ’Notes ’], 8 requires: [ ’org . s2 .syncEngine.SyncManager’],

launch: function() { //creazione delle view 13 var notesList = { xtype: ’notesListView ’}; var noteEditor = { xtype: ’noteEditorView ’}; var noteAuthor = { xtype: ’noteAuthorView ’};

//creazione ed avvio del SyncManager 18 var myStoreManager = Ext.create( ’SyncManager’, { dbName: ’NotesDB’, 12.4 usare il syncmanager 145

appName: ’NotesApp’, deviceID: ’MyPC’ 23 });

//esempio di creazione dinamica dello store da aggiungere al sistema myStoreManager.createSyncStore( { 28 model: ’NotesApp.model.Author ’, tableID: ’authorID ’, remoteURL: ’http://srv1 . soluzioni−sw. i t/ NotesWeb/Author. aspx ’, storeId: ’Authors ’ }); 33 //aggiungo al syncManager gli store da mappare nel DB che non sono stati creati dal SyncManager myStoreManager.registerStore( ’Notes ’); //Si osservi chee’ stato aggiunto Notes, lo store caricato all’inizio

38 //creazione ed avvio del viewport Ext.Viewport.add([notesList,noteEditor,noteAuthor ]); } });

VERIFICAEVALIDAZIONE 13

13.1 modalità di testing

L’attività di verifica è stata strutturata in tre sotto attività:

• syntax check mediante l’uso di LintRoller;

• test di unità creati con Jasmine;

• test dell’applicativo mediante l’uso dello stesso su più piattafor- me.

La prima modalità di verifica è stata eseguita al termine di ogni modifica sostanziosa del codice. Successivamente man mano che ve- nivano create le classi della componente SyncEngine, venivano defini- ti i test di unità. In merito sono stati creati 84 test e sono stati eseguiti con successo al termine di ogni modifica sostanziosa del codice1. L’a- ver eseguito come prima cosa il syntax check a garantito che il codice testato fosse privo di errori semantici. Come ultima cosa (successivamente alla convalida degli 84 test) ho eseguito l’applicativo NotesApp (prontamente integrato con il Syn- cEngine) sui dispositivi segnalati in “Strumenti utilizzati”. Di seguito propongo la lista dei test di unità eseguiti. Tale lista è costituita dalle immagini dei risultati ottenuti con Jasmine nell’e- secuzione delle varie classi: TestSuit.01 - IndexIDStoreSpec - Figura 22;

Codice test Spec Figura

TestSuit.01 IndexIDStoreSpec Figura 22 TestSuit.02 IndexIDStoreFactorySpec Figura 23 TestSuit.03 DownloadStoreFactorySpec Figura 24 TestSuit.04 CommitStoreFactorySpec Figura 25 TestSuit.05 AddCommitSpec Figura 26 TestSuit.06 UpdateCommitSpec Figura 27 TestSuit.07 DeleteCommitSpec Figura 28 TestSuit.08 SyncStoreSpec Figura 29 TestSuit.09 StoreManagerSpec Figura 30

1 In tal modo i test di unità hanno funzionato anche da test di regressione.

147 148 verifica e validazione

13.2 test di unità svolti

Figura 22: TestSuit.01 - test di IndexIDStore

Figura 23: TestSuit.02 - test di IndexIDStoreFactory

Figura 24: TestSuit.03 - test di DownloadStoreFactory 13.2 test di unità svolti 149

Figura 25: TestSuit.04 - test di CommitStoreFactory

Figura 26: TestSuit.05 - test di AddCommit 150 verifica e validazione

Figura 27: TestSuit.06 - test di UpdateCommit

Figura 28: TestSuit.07 - test di DeleteCommit 13.2 test di unità svolti 151

Figura 29: TestSuit.08 - test di SyncStore 152 verifica e validazione

Figura 30: TestSuit.09 - test di SyncManager 13.4 requisiti soddisfatti 153

13.3 errori rilevati

L’esecuzione di LintRoller ha rilevato per lo più errori di distrazioni o piccole dimenticanze. Per esempio un errore tipico è stata la man- canza del “;” al termine di un istruzione. Altro errore tipico è stato l’uso del operatore “==” anziché “===”. Sicuramente più interessante è stato l’uso di Jasmine che mi ha per- messo di rilevare malfunzionamenti nel sistema di sincronizzazione, e in particolare nel modo in cui viene processato l’iter di download e di aggiornamento con i record presenti in CommitStore. Infine, il test dell’applicazione sui diversi dispositivi, mi ha permes- so di verificare la solidità del oggetto SingleTapButton e la stabilità dello stile CSS di Sencha usato per il layout grafico.

13.4 requisiti soddisfatti

Di seguito propongo la tabella riassuntiva dei requisiti soddisfatti. In generale posso concludere che tutti i requisiti evidenziati sono stati soddisfatti.

Requisiti Soddisfatto

RO1.0.0 Si RO1.1.0 Si RO1.2.0 Si RO1.3.0 Si RO1.3.1 Si RO1.3.2 Si RO1.3.3 Si RD1.3.4 Si RO1.4.0 Si RO1.5.0 Si RO1.6.0 Si RO2.0.0 Si RO2.1.0 Si RD2.2.0 Si RD2.2.1 Si RO3.0.0 Si RD4.0.0 Si

CONCLUSIONI 14

In questo capitolo intendo tirare le somme di quella che è stata la mia esperienza lavorativa all’interno dell’azienda Soluzioni Software e dell’attività di progettazione e realizzazione della componente Syn- cEngine. Per quanto riguarda il mio giudizio su Sencha e PhoneGap, rimando al capitolo “considerazioni sui framework usati”. Per quanto concerne l’attività di stage voglio precisare i seguenti Considerazioni punti: sull’attività di stage.

• ritengo che la scelta dell’università di far compiere ai propri stu- denti uno stage obbligatorio sia non solo valida, ma addirittura essenziale. Per me è stato un “rito di passaggio” dall’ambien- te universitario, decisamente più didattico e mirato a fornire le idee e le metodiche teoricamente più giuste, all’ambiente lavora- tivo, dove invece non si può usare sempre la teoria ma a causa di forti vincoli temporali ed economici si deve ponderare con maggior maturità le varie scelte, sapendo gestire con giudizio le proprie risorse;

• l’azienda ospite, e in particolare la figura del tutor aziendale Bruno Santo, mi hanno saputo aiutare notevolmente nel mio percorso formativo, non solo elargendomi validi consigli e mo- strandomi come sia “la vita aziendale”, ma anche trattando- mi con educazione e rispetto. Cosa di cui sono profondamente grato;

• l’azienda sembra soddisfatta del mio operato e del modo con cui ho lavorato nella loro sede. Sicuramente spero di aver lascia- to loro un prodotto di qualità in grado di porre le basi per futu- re implementazioni, in misura almeno pari a quanto loro hanno lasciato a me come formazione e maturità nel lavoro d’azienda.

Le problematiche affrontate e riassunte nella sezione “Problemati- che affrontate”, hanno contribuito a rendere il lavoro più interessan- te offrendomi spunti di riflessione non solo sugli strumenti e i fra- mework usati, ma anche sull’idea stessa di applicazione ibrida e su come si stia evolvendo il mondo dell’informatica. In sintesi l’attività di stage è stata più che positiva non solo per l’esito del lavoro condotto, ma anche per come ha saputo aumentare il mio bagaglio di esperienze1, lasciandomi soddisfatto del mio operato e del prodotto ultimo consegnato. Proprio in merito al SyncEngine, che in se rappresenta il fulcro dei Considerazioni su SyncEngine. 1 Vedasi “Competenze acquisite”

155 156 conclusioni

miei sforzi e dell’attività di studio del dominio tecnologico, voglio puntualizzare che:

• il prodotto ha raggiunto un livello di maturità che gli permette di essere impiegato in un progetto di medie dimensioni. Sotto- lineo medie dimensioni, poiché fornire un database eccessiva- mente grande potrebbe (al momento) comportare un degrado notevole delle prestazioni, soprattutto a causa del dominio tec- nologico (vedasi considerazioni su Sencha Touch 2) e al fatto che ancora oggi vengono usati dispositivi non di fascia alta, e aventi quindi prestazioni (soprattutto in termini di memoria) non eccelse;

• l’approccio ingegneristico condotto nella realizzazione di Syn- cEngine, ha contribuito alla creazione di una struttura valida dello stesso, garantendo operazioni di manutenzione evolutiva e al più correttiva più facili e meno costose. Soprattutto, consi- derando la non predisposizione del dominio tecnologico (Java- Script) ad una progettazione e programmazione orientata agli oggetti. In tal senso è stato comunque molto utile il framework Sencha Touch, che con qualche trucco ha saputo predisporre un’ottima simulazione del concetto di ereditarietà.

• SyncEngine è stato ultimato rispettando le tempistiche azienda- li. Il collaudo sul prototipo ha anche messo in luce che: importa- re la componente in un progetto già esistente, al fine di sostituir- ne l’apparato di archiviazione dati, non è un’operazione ecces- sivamente costosa. Ciò comunque dipenderà delle dimensioni del progetto e dalla progettazione con cui è stato pensato.

• il prodotto fa uso di tutte le conoscenze apprese durante lo stu- dio. Per quanto possa comunque essere migliorato ed esteso, ritengo che possa considerarsi in se completo e funzionante. In merito ai requisiti di progetto, sono stati soddisfatti interamen- te. L’unico punto trattato in maniera più marginale è il requisi- to RD4.0.0. Di per sé soddisfatto in quanto richiedeva solo una considerazione di progettazione (e non di sviluppo immediato). Chi dovrà lavorarci in seguito, dovrebbe trarre vantaggio dalla progettazione eseguita. Parte IV

APPENDICI

MODULEPATTERN A

Data l’importanza dell’argomento, sia per rendere edotto il lettore di questa best practice utile nella realizzazione di applicazioni web (e di conseguenza di applicazioni ibride), sia per fornire un esempio di definizione di un oggetto in JavaScript, di seguito è riportato il codice d’implementazione del module patter. Uno dei problemi che emergono utilizzando la programmazione Module pattern ad oggetti in JavaScript è la mancanza del concetto di visibilità delle simula il concetto proprietà e dei metodi all’interno di un oggetto. Linguaggi come Java dell’ information hiding all’interno di presentano alcuni costrutti base del linguaggio (public, private, pro- JavaScript. tected) che permettono al programmatore di modificare la visibilità di un membro di una classe. Il module pattern è nato quindi, per risolvere questa lacuna per- mettendo usufruire dei modificatori di visibilità anche in JavaScript.

Listing 24: Module pattern - esempio d’implementazione

4

59 SQLITE B

b.1 cos’è sqlite

Figura 31: SQLite - logo [28, “SQLite Foreign Key Support” ]

SQLite1 è una libreria software scritta in linguaggio C che imple- SQLite, definizione. menta un DBMS SQL di tipo ACID incorporabile all’interno di appli- cazioni. SQLite permette di creare una base di dati (comprese tabelle, query, form, report) incorporata in un unico file, come nel caso dei moduli Access di Microsoft Office e Base di OpenOffice.org e analogamente a prodotti specifici come Paradox o Filemaker. SQLite non è un processo stand alone utilizzabile di per sé, ma può essere incorporato all’interno di un altro programma. È utilizzabi- le con il linguaggio C/C++, ed esistono binding anche per altri lin- guaggi, in particolare Tcl. È inoltre stato integrato nella versione 5 di PHP, consentendo a tale popolare linguaggio di disporre di un altro RDBMS indipendentemente dalla presenza di MySQL. Viene utilizza- to in Mozilla Firefox e Seamonkey per memorizzare i bookmark, la cronologia di navigazione ed altre informazioni. SQLite non manca però di limiti . Tra essi sottolineiamo: Limiti di SQLite.

• non offre le stored procedure.

• non prevede la gestione dei permessi d’accesso, demandata al software con cui si interagisce con il database e/o al meccani- smo dei permessi del file system;

• non ha una vera gestione della concorrenza: le applicazioni che lo utilizzano, se necessario, devono implementarla;

• per garantire la coerenza del file del database sono usati i lock del file system, e quindi vi possono essere problemi qualora quest’ultimo non li implementi correttamente, ad esempio con file system di rete (come NFS);

1 In Figura 31 è presente il logo della libreria SQLite.

161 162 sqlite

• non offre alcuna cache per le query (e non ne ha la possibilità, non esistendo un processo server centrale);

• non ha protocolli di rete, non essendo utilizzabile come pro- gramma a sé; è possibile utilizzare un database remoto, ma solo tramite file system di rete del sistema operativo, con prestazioni difficilmente accettabili;

• non supporta alcuni importanti costrutti SQL quali RIGHT JOIN e FULL OUTER JOIN;

• non supporta le sotto-query variabili.

• non supporta la scrittura diretta nelle viste (occorre usare trig- ger “INSTEAD OF”);

• non consente di modificare, cancellare o rinominare le colonne di una tabella: il comando ALTER TABLE è infatti limitato alla modifica del nome della tabella e all’aggiunta di colonne in coda alla stessa. Molti frontend di terze parti aggirano comunque il limite rigenerando in modo trasparente la tabella (perdendo però trigger e indici ad essa correlati);

• non supporta trigger di tipo “FOR EACH STATEMENT” (solo “FOR EACH ROW”, eventualmente combinato con “INSTEAD OF”);

• il supporto ai trigger ricorsivi ed ai vincoli sulle chiavi esterne, introdotto rispettivamente nelle versioni 3.6.18 e 3.6.19, deve es- sere attivato dal programmatore; tale comportamento, dovuto alla compatibilità con le versioni precedenti, sarà modificato a partire dalla versione 3.7.

Come si può osservare dalla sopracitata lista, nelle precedenti ver- sioni di SQLite, la funzionalità delle chiavi esterne esisteva ma non era gestita. Tuttavia non mancava il modo di forzare tale vincolo, in- troducendo una serie di trigger. Ad oggi il sistema di chiavi esterne è perfettamente funzionante. Sono tuttavia da tenere in considerazione i seguenti punti:

• Il servizio SQLite delle chiavi esterne è da abilitare o per mezzo del comando sqlite > PRAGMA foreign_keys = ON (qualora si operi da terminale), oppure se si usa un interfaccia grafica, tale voce è da ricercare nel DB setting.

• la creazione delle tabelle va fatta in modo oculato! è vitale ac- certarsi che tutti i vincoli del tipo ON DELETE CASCADE / ON UPDATE CASCADE siano rispettati. NOTA: altrimenti sa- rà impossibile eliminare un elemento A, se esiste un istanza B (in un’altra tabella) ad esso collegata. B.2 sqlite manager 163

Ecco un banalissimo esempio di database caratterizzato da 2 entità: Creare un database Persona e Indirizzo. Molto semplicemente si vuole rappresentare un SQLite. sistema in cui una persona può avere uno o più indirizzi.

Listing 25: Esempio database SQLite con utilizzo di foreign key

CREATE TABLE "Persona" ( 3 id INTEGER PRIMARY KEY AUTOINCREMENT, Nome VARCHAR, Cognome VARCHAR )

8 CREATE TABLE "Indirizzo" ( id_ind INTEGER PRIMARY KEY, via VARCHAR, id_persona INTEGER NOT NULL, 13 FOREIGN KEY(id_persona) REFERENCES Persona(id) ON UPDATE CASCADE ON DELETE CASCADE )

Per un uso più “raffinato” di tale strumento, rimandiamo alla do- cumentazione: [28, “SQLite Foreign Key Support” ]

b.2 sqlite manager

SQLite Manager è un componente aggiuntivo di Firefox che forni- sce un interfaccia grafica per la creazione e la gestione di database SQLite. L’ambiente è particolarmente intuitivo e il suo funzionamen- to è analogo a phpMyAdmin. Dopo aver creato un database tramite l’analogo pulsante presente nella barra di menù, è possibile aggiun- gere una nuova tabella grazie ad un pulsante collocato in fianco al precedente. Sulla sinistra è presente un pannello da cui l’utente po- trà selezionare la base di dati su cui lavorare. Il pannello centrale ci Funzionalità di permette di operare in 4 ambiti di lavoro: SQLite Manager. • Structur: fornisce le informazioni di struttura sulla tabella at- tualmente selezionata. Offre anche la possibilità di manipolarla per mezzo di una serie di pulsanti quali Drop o Rename.

• Brows & Search: da una chiara visione del contenuto della ta- bella selezionata, permettendoci di manipolare i dati in essa contenuti.

• Excecute_SQL: da la possibilità di immettere query SQL per la ricerca e manipolazione dei dati. è possibile e consigliabile (se non addirittura d’obbligo) creare le tabelle da tale voce, poi- chè il sistema di creazione grafico non fornisce la possibilità di specificare vincoli di integrità referenziale. 164 sqlite

• DB_settings: sotto tale voce sono riportate le configurazioni del DB, tra cui la già citata Foreign Keys (attivo/disattivo).

Come si è potuto capire SQLite Manager è uno strumento facile e veloce da usare. Si raccomanda tuttavia di fare qualche prova, al fine di prendere una maggior dimestichezza con l’ambiente di lavoro. Per quanto riguarda l’attività di stage, il programma è stato usa- to per verificare il contenuto dei database WebSQL creati durante lo studio del dominio tecnologico. Per maggiori informazioni, non che per la possibilità di scaricarlo, rimando al seguente riferimento bibliografico: [29, “SQLite Manager 0.8.0” ] TESTSULWEBSQL C

Quella che segue è la lista dei test eseguiti per verificare se il limite dei 5MB dei WebSQL esiste realmente o meno. Associata alla descrizione Test eseguiti. di ogni test, vi è l’esito ottenuto.

• Creazione di un DB WebSQL su Chrome mediante l’uso di Ext.data.proxy.Sql: Il sistema non ha dato nessun genere di se- gnalazione negativa, ed è stato possibile creare un database dal peso effettivo di 18 MB.

• Creazione di un DB WebSQL su dispositivo portatile smart- phone Huawei (sistema Android 4.1.0), mediante l’uso di Ext.data.proxy.Sql: Il sistema non ha dato nessun genere di se- gnalazione negativa, ed è stato possibile creare un database dal peso effettivo di 6 MB.

• Creazione di un DB WebSQL su Chrome mediante l’uso di una classe che ridefinisce Ext.data.proxy.Sql, impostando il limite “size” del DB a 2 MB: Il sistema non ha dato nessun genere di segnalazione negativa, ed è stato possibile creare un database dal peso effettivo di 18 MB.

• Creazione di un DB WebSQL su dispositivo portatile smart- phone Huawei (sistema Android 4.1.0), mediante l’uso di una classe che ridefinisce Ext.data.proxy.Sql, impostando il limite size del DB a 2 MB: Il sistema non ha dato nessun genere di segnalazione negativa, ed è stato possibile creare un database dal peso effettivo di 6 MB.

• Creazione di un DB WebSQL su Chrome mediante l’uso diret- to delle funzionalità javascript/html per la manipolazione di web database: Il sistema non ha dato nessun genere di segnala- zione negativa, ed è stato possibile creare un database dal peso effettivo di 18 MB.

Qui viene riportato il codice della pagina html usato nell’ultimo test della precedente lista. Dopo aver aperto la pagina cosi definita è possibile osservare la dimensione del database creato, cercandolo nella directory contente i database di Google Chrome.

165 166 test sul websql

Listing 26: Test javascript per la creazione di un WebSQL database

1 26 test sul websql 167

L’unico riscontro trovato nel web, che sembra suggerire che effetti- vamente questo campo size non abbia alcun utilizzo pratico (se non in Safari) è [13, “Introducing Web SQL Databases” ].

Invece tra le fonti online che rimandano al limite dei 5MB, cito: [25, “Sencha Touch: Clarifying WebSQL, SQLite and how they relate to Sen- cha Touch”]. Considerazioni In merito, un idea personale sul perché esista questa voce consiste sull’errata nell’errato modo di riferirsi al WebSQL. Molti sviluppatori tendono a limitazione dei 5MB. classificare tale tecnologia come uno dei sistemi di archiviazione dei WebStorage di HTML5 (che ricordiamo sono LocalStorage e Session- Storage). Questi ultimi hanno effettivamente un limite fisico di 5MB. Associando WebSQL a tali tecnologie è probabile che molti svilup- patori siano giunti alla conclusione che WebSQL soffra della stessa limitazione dei WebStorage.

LEBASIDIJASMINE D

Figura 32: Jasmine - logo [14, “Jasmine” ]

Jasmine1 è un framework open source per il testing di componenti Jasmine è un JavaScript. Sviluppato dal team Pivotal Labs, Jasmine è cresciuto nel framework per il tempo fino a diventare uno dei framework BDD più usati per gli testing di componenti unit test di applicazioni JavaScript. Questo sopratutto in virtù del suo JavaScript. approcciò intuitivo e di una sintassi facile da leggere. Il framework ha inoltre il vantaggio di essere eseguibile su ogni piattaforma in grado si supportare JavaScript. Per compiere al meglio il suo dovere, egli si appoggia anche ad altri framework come: ScrewUnit, JSSpec, JSpec, e RSpec.

d.1 come creare una suit di test

Rifacendomi alla guida [14, “Jasmine” ], riportiamo di seguito la sin- tassi per eseguire i test con il framework proposto. Come primo è necessario definire una suit di test. Per compiere ta- le operazione è sufficiente richiamare la funzione globale “describe”, passando come parametri il nome della suit di test (per chiarezza si consiglia di adottare una nomenclatura che richiami la classe che si sta testando), e la funzione (nel caso, anonima) definita ad hoc per l’e- secuzione del test di uno dei metodi della classe da testare. Si osservi (nell’esempio sotto riportato) che per definire una funzione di test si usa la dicitura “it”. Tale funzione globale descrive le cosi dette “specs” della test suit. In esse compaiono una o più “expectation”. Queste al- L’esito del test è tro non sono che le definizioni dei valori attesi da delle chiamate a determinato da funzioni. Tali valori possono essere di diverso tipo (nell’esempio sot- expect() e dal tipo di matcher usato. to riportato si userà per semplicità due valori booleani). La sintassi di tali comandi è (nella loro forma base):

expect(VALORE_OTTENUTO).toBE(VALORE_ATTESO);

A seconda dell’esito del confronto tra questi due valori, Jasmine può segnalare il test come passato o non passato. Cosi come è possi-

1 In Figura 32 è riportato il logo di Jasmine.

169 170 le basi di jasmine

bile richiedere che il valore ottenuto sia (toBe(...)) uguale ad un certo valore atteso, è anche possibile specificare che il valore ottenuto NON sia uguale ad un certo valore. Una procedura del genere si esprime con la sintassi:

expect(VALORE_OTTENUTO).not.toBE(VALORE_NON_ATTESO);

Tra le possibili tipologie di valori su cui richiamare expect, si segna- la jasmine.any(’ClassName’). Questa funzione ci permette di “pren- dere” il costruttore della classe specificata, e di confrontarlo con il costruttore dell’oggetto atteso. Un esempio di utilizzo è il seguente, dove vogliamo verificare se il valore ottenuto è un numero:

expect(12).toEqual(jasmine.any(Number));

concludiamo il paragrafo con un esempio di test-suit:

Listing 27: Jasmine - creare una test suit

1 describe("Nome classe da testare", function() { it("nome funzione da testare", function() { expect(true).toBe(true); /*in questo semplice esempio, il test passera’ sempre, poiche ’ per i parametri passati, abbiamo che expect confrontera ’ sempre true con true, restituendo ovviamente true.*/ 6 }); });

d.2 considerazioni aggiuntive sui matchers

Con Jasmine esiste la possibilità di usare altri matchers oltre che a toBe e not.toBe. Una trattazione approfondita dell’argomento esula dallo scopo di questa appendice. Pertanto si rimanda il lettore al riferimento bibliografico [38, “GitHub - Jasmine wiki - Matchers” ]. Si sottolinea comunque la possibilità di creare anche dei matchers ad hoc per i nostri scopi. Il tutorial sull’argomento è reperibile allo stesso indirizzo web proposto in precedenza.

d.3 beforeach e aftereach

Spesso i test necessitano di essere eseguito in un contesto ben defi- nito. Per esempio se volessimo testare una funzione che rimuove un certo record x da un database, e nello specifico vorremo verificare l’effettiva rimozione di un record esistente, prima di eseguire il test dovremmo essere certi che il record x sia inserito nel database. Pertan- to all’avio del test è necessario portare il database in una situazione D.4 innestare più blocchi 171

valida (e.g si può eseguire un query in grado di aggiungere il record x nel database). A tale scopo sono state ideate le keyworld beaforEach e afterEach. beaforEach e Queste definiscono funzioni anonime che vengono richiamate da ogni afterEach, possono spec rispettivamente, all’avio e al termine della spec stessa. Ecco un essere utili per riconfigurare le esempio della loro definizione: premesse iniziali prima e dopo ogni Listing 28: Jasmine - uso di beaforEach e afterEach test.

2 describe("A spec (with setup and tear−down) ", function() { var foo;

beforeEach(function() { foo = 0; 7 foo += 1; });

afterEach(function() { foo = 0; 12 });

it("is just a function, so it can contain any code", function() { expect(foo).toEqual(1); }); 17 it("can have more than one expectation", function() { expect(foo).toEqual(1); expect(true).toEqual(true); }); 22 });

d.4 innestare più blocchi

Le chiamate alle funzioni describe possono essere innestate definen- do al loro interno più specs ad ogni livello. Ciò ci permette di com- porre una suit come una struttura ad albero in grado di richiamare, ad ogni livello d’innesto, le funzioni beafor e after necessarie. Segue l’esempio:

Listing 29: Jasmine - describe innestati

2 describe("A spec", function() { var foo;

beforeEach(function() { foo = 0; 7 foo += 1; }); 172 le basi di jasmine

afterEach(function() { foo = 0; 12 });

it("is just a function, so it can contain any code", function() { expect(foo).toEqual(1); }); 17 it("can have more than one expectation", function() { expect(foo).toEqual(1); expect(true).toEqual(true); }); 22 describe("nested inside a second describe", function() { var bar;

beforeEach(function() { 27 bar = 1; });

it("can reference both scopes as needed ", function() { expect(foo).toEqual(bar); 32 }); }); });

d.5 spies

Jasmine fornisce delle funzionalità per osservare se, l’esecuzione di una certa funzione, comporta una chiamata ad altre funzioni “spia- te”. Tale procedura si ottene definendo delle spy, semplici stub alle funzioni da osservare, in grado di tracciare le funzioni chiamanti e i parametri da loro passati. Segue un esempio di definizione di Spies:

Listing 30: Jasmine - usare le ”spie”

describe("A spy", function() { var foo, bar = null;

5 beforeEach(function() { foo = { setBar: function(value) { bar = value; } 10 };

spyOn(foo, ’setBar’); D.5 spies 173

foo.setBar(123); 15 foo.setBar(456, ’another param’); });

it("tracks that the spy was called", function() { expect(foo.setBar).toHaveBeenCalled(); 20 });

it("tracks its number of calls", function() { expect(foo.setBar.calls.length).toEqual(2); }); 25 it("tracks all the arguments of its calls", function() { expect(foo.setBar).toHaveBeenCalledWith(123); expect(foo.setBar).toHaveBeenCalledWith(456, ’another param’) ; }); 30 it("allows access to the most recent call", function() { expect(foo.setBar.mostRecentCall.args[0]).toEqual(456); });

35 it("allows access to other calls", function() { expect(foo.setBar.calls[0].args[0]).toEqual(123); });

it("stops all execution on a function", function() { 40 expect(bar).toBeNull(); }); });

Esiste inoltre la possibilità, oltre che di tracciare la chiamate alla funzione spiata, anche di delegare a questa l’esecuzione la risoluzio- ne della chiamata effettiva ”tracciata”. Per fare ciò è sufficiente sosti- tuire al listato precedente l’istruzione:

spyOn(foo, ’setBar’);

con:

spyOn(foo, ’setBar’).andCallThrough();

Analogamente alla possibilità di richiamare la funzione osservata, c’è la possibilità di richiamare un’altra funzione specificata. Per farlo si usa il comando andCallFake(function()):

spyOn(miaClasse, ’f()_spiata’).andCallFake(function(){ ... });

Altra proprietà interessante, da associare ad una spy, consiste nel restituire in seguito ad una chiamata alla funzione spiata, una valore 174 le basi di jasmine

ben definito. Per farlo si userà l’istruzione:

spyOn(miaClasse, ’f()_spiata’).andReturn(VALORE);

In ultima segnaliamo la seguente possibilità: Jasmine permette di definire delle spie che non puntano ad un oggetto realmente esistente. Un tale uso delle spie può risultare utile nei seguenti casi: • vogliamo verificare se l’esecuzione di un pezzo di codice provo- ca una chiamata ad una funzione che, a livello di progettazio- ne sappiamo che esisterà, ma al momento il suo codice non è ancora stato scritto; • vogliamo verificare se l’esecuzione di un pezzo di codice provo- ca una chiamata ad una funzione obsoleta che è stata eliminata dal sistema. Segue un esempio:

Listing 31: Jasmine - usare jasmine.createSpyObj

describe("Multiple spies , when created manually", function() { 3 var tape;

beforeEach(function() { tape = jasmine.createSpyObj(’tape’, [’play’, ’pause’, ’stop’, ’rewind’]);

8 tape.play(); tape.pause(); tape.rewind(0); });

13 it("creates spies for each requested function", function() { expect(tape.play).toBeDefined(); expect(tape.pause).toBeDefined(); expect(tape.stop).toBeDefined(); expect(tape.rewind).toBeDefined(); 18 });

it("tracks that the spies were called", function() { expect(tape.play).toHaveBeenCalled(); expect(tape.pause).toHaveBeenCalled(); 23 expect(tape.rewind).toHaveBeenCalled(); expect(tape.stop).not.toHaveBeenCalled(); });

it("tracks all the arguments of its calls", function() { 28 expect(tape.rewind).toHaveBeenCalledWith(0); }); }); D.6 casi particolari: settimeout e setinterval 175 d.6 casi particolari: settimeout e setinterval

Jasmine predispone la possibilità di rendere sincrone le chiamate set- Timeout e setInterval, cosi da facilitare il test di quelle funzioni che ne fanno uso. Per fare ciò è sufficiente usare l’istruzione:

jasmine.Clock.useMock

nelle spec (o nelle suit) che fanno uso delle funzioni temporali.

GLOSSARIO

API Acronimo di Application Programming Interface, de- signa l’interfaccia esposta agli utenti programma- tori da parte di una libreria software al fine di rendere più agevole lo sviluppo di applicazioni astraendo una serie di dettagli di basso livello e centralizzando l’accesso a determinate procedure, 14

Best practice Prassi (dal greco πραξισˆ , ‘azione’) consolidata sul- la base dell’esperienza comune in un determinato dominio e la cui validità è universalmente o in lar- ga misura riconosciuta dagli esperti di tale domi- nio. In genere le best practices sono formalizzate in una serie di regole la cui applicazione offre buone garanzie di riuscita del prodotto finale, 6 BI Abbreviazione per Business Intelligence, espressio- ne coniata nel 1958 ad opera di Hans Peter Luhn. Oggi può avere tre diversi significati:

• un insieme di processi aziendali per rac- cogliere dati ed analizzare informazioni strategiche;

• la tecnologia utilizzata per realizzare questi processi;

• le informazioni ottenute come risultato di questi processi;

, 4 Browser Programma utilizzato per attingere, elaborare, vi- sualizzare e trasmettere informazioni su internet affidandosi a protocolli di livello applicazione (HTTP, FTP). I browser oltre a integrare un motore di rendering necessario a interpretare e tradurre il codice (X)HTML in forma di ipertesto offrono la possibilità di realizzare computazione lato client grazie, ad esempio, ad un interprete JavaScript, 4

177 178 Glossario

Clinet in un’architettura client-server, corrisponde alla componente che richiede e ottiene accesso a risorse e/o servizi attraverso un canale di comunicazione (quale una rete informatica), 17 CRUD Acronimo per “create, read, update and delete”. Con questo termine si identificano le 4 operazioni basilari di un sistema di archiviazione persistente, 94

Database Raccolta di informazioni (dati e metadati) perma- nenti gestiti da un elaboratore elettronico. In parti- colare, i metadati descrivono lo schema secondo cui sono organizzati i dati mentre questi ultimi corrispondono alla rappresentazione di una por- zione di realtà, sono persistenti, hanno una cardi- nalità molto maggiore rispetto ai metadati e sono accessibili mediante transazioni, 26 Design pattern Traducibile in lingua italiana come schema proget- tuale, nell’ambito dell’ingegneria del software, è un concetto che può essere definito come “una so- luzione progettuale generale a un problema ricor- rente”. Esso non è una libreria o un componente di software riusabile, quanto piuttosto una descrizio- ne o un modello da applicare per risolvere un pro- blema che può presentarsi in diverse situazioni du- rante la progettazione e lo sviluppo del software, 20 DOM Acronimo di Document Object Model, è lo standard ufficiale del W3C per la rappresentazione logica di documenti, neutrali sia per linguaggio che per piat- taforma. Letteralmente si traduce con “modello a oggetti del documento” e nell’ambito del progetto si riferisce al documento HTML, 20

ERP Enterprise resource planning (letteralmente piani- ficazione delle risorse d’impresa, spesso abbrevia- to in ERP) è un sistema di gestione, chiamato in informatica sistema informativo, che integra tutti i processi di business rilevanti di un’azienda (ven- dite, acquisti, gestione magazzino, contabilità etc.) [34, “Wikipedia - definizione ERP” ], 4 Glossario 179

Factory method Nella programmazione ad oggetti, il Factory Me- thod è un design pattern di tipo creazionale. Es- so indirizza il problema della creazione di oggetti senza specificarne l’esatta classe. Per raggiungere il suo scopo fornisce un’interfaccia per creare un oggetto, ma lascia che le sottoclassi decidano quale oggetto istanziare, 108 Framework Insieme integrato di componenti software prefab- bricate. Forniscono la base riusabile di diverse applicazioni entro uno stesso dominio, 4

IDE Acronimo di Integrated Development Environment (ambiente di sviluppo integrato) rappresenta un applicativo che ha il compito di facilitare la codi- fica del software integrando tipicamente al pro- prio interno sotto un’unica interfaccia un editor per i sorgenti, un compilatore/interprete per il linguaggio prescelto e un , 24 IM Abbreviazione per Information Management, ter- mine usato per indicare la raccolta e la gestione di informazioni da una o più fonti e la distribuzione di tali informazioni ad uno o più destinatari, 4

Kernel Costituisce il nucleo di un sistema operativo. Si tratta di un software avente il compito di forni- re ai processi in esecuzione sull’elaboratore un ac- cesso sicuro e controllato all’hardware. Dato che possono esserne eseguiti simultaneamente più di uno, il kernel ha anche la responsabilità di assegna- re una porzione di tempo-macchina (scheduling) e di accesso all’hardware a ciascun programma, 11

Look & feel In informatica, l’espressione inglese look and feel (talvolta abbreviata in L&F) viene usata per descri- vere le caratteristiche percepite dall’utente di una interfaccia grafica, sia in termini di apparenza visi- va (il look) che di modalità di interazione (il feel), 15 180 Glossario

MVC Acronimo per Model-View-Controller. In informa- tica è un pattern architetturale ampliamene utiliz- zato soprattutto nell’ambito OOP. Il pattern è basa- to sulla separazione dei compiti fra i componenti software che interpretano tre ruoli principali:

• il model fornisce i metodi per accedere ai dati utili all’applicazione;

• il view visualizza i dati contenuti nel model e si occupa dell’interazione con utenti e agenti;

• il controller riceve i comandi dell’uten- te (in genere attraverso il view) e li at- tua modificando lo stato degli altri due componenti.

Questo schema, fra l’altro, implica anche la tradi- zionale separazione fra la logica applicativa, a cari- co del controller e del model, e l’interfaccia utente a carico del view, 31

Observer È un pattern intuitivamente utilizzato come base architetturale di molti sistemi di gestione di even- ti. Sostanzialmente il pattern si basa su più oggetti suddivisi in due categorie: Observer e Observable (utilizzando la nomenclatura Java). I primi hanno lo scopo di osservare lo stato degli Observable in attesa di una notifica da questi. I secondi possono essere osservati dagli Observer e hanno il compi- to di notificare a questi quando (per un qualche motivo) il loro stato interno è cambiato, 32 Glossario 181

OOP La programmazione orientata agli oggetti (Object Oriented Programming, da cui l’acronimo OOP) è uno stile fondamentale di programmazione (o pa- radigma) che si basa principalmente sul raggrup- pamento all’interno di un’unica entità (la classe) delle strutture dati e delle procedure che operano su di esse. Un linguaggio di programmazione è definito ad oggetti quando permette di implemen- tare tre meccanismi usando la sintassi nativa del linguaggio:

• incapsulamento;

• ereditarietà;

• polimorfismo.

, 31 Open source Termine che indica un software i cui autori (più precisamente i detentori dei diritti) ne permettono e favoriscono il libero studio e l’apporto di modi- fiche da parte di altri programmatori indipenden- ti. Questo è realizzato mediante l’applicazione di apposite licenze d’uso, 11

Plugin Programma non dotato di una propria autonomia (non stand-alone) ma che al contrario può esse- re eseguito esclusivamente dall’interno di un al- tro programma di cui rappresenta un’estensione modulare, 7

REST Representational state transfer (REST) è un tipo di architettura software per i sistemi di ipertesto distribuiti come il World Wide Web. Il termine è spesso usato nel senso di descrivere ogni sempli- ce interfaccia che trasmette dati su HTTP senza un livello opzionale come SOAP o la gestione della sessione tramite i cookie. I sistemi che seguono i principi REST sono spesso definiti RESTful, 48

S.r.l. Società a responsabilità limitata. Si tratta di un tipo di società di capitali, dotata di personalità giuridi- ca e risponde delle obbligazioni sociali solamente con il suo patrimonio [35, “Wikipedia - definizione s.r.l.” ], 3 182 Glossario

Server In un’architettura client-server, componente che for- nisce un servizio in risposta alle richieste ricevute dalla controparte (client), 5 Silver bullet Termine inglese che in italiano significa ”pallotto- la d’argento”. Si tratta di un riferimento all’arti- colo [16, “No Silver Bullet” ] di Fred Brooks. Cosi come nel folklore, le pallottole d’argento sono l’u- nico mezzo per uccidere i lupi mannari, nel con- testo ingegneristico informatico, trovare un silver bullet significa l’aver trovato la soluzione finale ad un problema, 18 Singleton Nella programmazione orientata agli oggetti è un design pattern creazionale che ha lo scopo di ga- rantire che di una determinata classe venga creata una e una sola istanza, e di fornire un punto di accesso globale a tale istanza, 125 SO Abbreviazione per Sistema Operativo. In informa- tica è un insieme di componenti software, che garantisce l’operatività di base di un calcolatore, coordinando e gestendo le risorse hardware di pro- cessamento e memorizzazione, le periferiche, le ri- sorse/attività software (processi) e facendo da in- terfaccia con l’utente, senza il quale quindi non sa- rebbe possibile l’utilizzo del computer stesso e dei programmi/software specifici, come applicazioni o librerie software, 4 Stand-alone Oggetto o software il cui funzionamento è indipen- dente da altri oggetti o applicativi, in particolare, un programma stand-alone è autonomo (versus un plugin) e non richiede altri componenti una volta installato, 64 Stub In fase di analisi dinamica, la componente passi- va richiamata nel corso dell’attività di verifica da una parte attiva che costituisce l’oggetto del test. Si tratta di componenti di semplice implementazione in quanto hanno solo il ruolo di fornire in output risultati plausibili senza alcuna necessità di appli- care gli algoritmi della “reale” logica di business, 170 Glossario 183

TCO Acronimo di Total Cost of Ownership (in italiano, co- sto totale di proprietà o costo totale di possesso), è un approccio sviluppato da Gartner nel 1987, uti- lizzato per calcolare tutti i costi del ciclo di vita di un’apparecchiatura informatica (Software e Hard- ware). Per farlo tiene quindi conto delle fasi di: acquisto, installazione, gestione, manutenzione e smantellamento, 15

UML In ingegneria del software, UML (Unified Mode- ling Language, “linguaggio di modellazione unifi- cato”) è un linguaggio di modellazione e specifica basato sul paradigma object-oriented. L’UML svol- ge un’importantissima funzione di “lingua franca” nella comunità della progettazione e programma- zione a oggetti. Gran parte della letteratura di set- tore usa UML per descrivere soluzioni analitiche e progettuali in modo sintetico e comprensibile a un vasto pubblico, 7

BIBLIOGRAFIA

libri

[1] “Sencha Touch 2 - Up and Runnig” Autore: Adrian Kosmaczewski, Anno di pubblicazione: 2013, Periodo di consultazione: giugno 2013, Editore: O’Reilly.

articoli web

[2] “Adobe PhoneGap Build” Autore: Adobe, Anno di pubblicazione: 2013, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: https://build.phonegap.com/ [3] “Apple share rebounds in Britain as iPhone 4 pulls in smartphone first- timers” Autore: Peter Rogers/Rhianna Brien, Anno di pubblicazione: 29 luglio 2013, Periodo di consultazione: luglio - agosto 2013, Lingua: inglese, URL: http://uk.kantar.com/media/463141/kantar_worldpanel_ comtech_smartphone_os_barometer_29_07_13.pdf [4] “Applicazioni ibride per iphone, android e blackberry” Autore: Daniele Pizzoni, Anno di pubblicazione: 15 maggio 2012, Periodo di consultazione: giugno 2013, Lingua: italiano, URL: http://danielepizzoni.it/blog/2012/05/applicazioni-ibride- per-iphone-android-blackberry-etc/ [5] “Automating Unit Tests” Autore: Arthur Kay, Anno di pubblicazione: 2 agosto 2012, Periodo di consultazione: luglio 2013, Lingua: inglese, URL: http://www.sencha.com/blog/automating-unit-tests [6] “Can I use... - IndexedDB” Autore: Alexis Deveria,

185 186 Bibliografia

Anno di pubblicazione: 31 maggio 2013, Periodo di consultazione: giugno - 2013, Lingua: inglese, URL: http://caniuse.com/#feat=indexeddb

[7] “Get IIS6 to serve JSON files” Autore: StackOverflow, Anno di pubblicazione: febbraio 2013, Periodo di consultazione: maggio - giugno 2013, Lingua: inglese, URL: http://stackoverflow.com/questions/332988/get-iis6-to- serve-json-files-inc-post-get/1121114#1121114

[8] “Getting the create Command to Work on PhoneGap 2.2.0 Android” Autore: Simon MacDonald, Anno di pubblicazione: 16 novembre 2012, Periodo di consultazione: maggio - giugno 2013, Lingua: inglese, URL: http://simonmacdonald.blogspot.ca/2012/11/getting- create-command-to-work-on.html

[9] “How to create a Sencha Touch 2 app” Autore: Jorge Ramon, Anno di pubblicazione: febbraio 2012, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://miamicoder.com/2012/how-to-create-a-sencha- touch-2-app-part-1/

[10] “How to implement and use a custom proxy” Autore: StackOverflow, Anno di pubblicazione: 27 gennaio 2012, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://stackoverflow.com/questions/9032634/sencha- touch-2-mvc-how-to-implement-and-use-a-custom-proxy

[11] “HTML5 - Local Storage” Autore: Praveen Kundurth, Anno di pubblicazione: 18 novembre 2011, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: http://software.intel.com/it-it/articles/html5-local-storage

[12] “IndexedDB Polyfill over WebSql” Autore: sviluppatori registrati a GitHub. Nell’articolo non hanno dato alcun riferimento alla loro persona, Anno di pubblicazione: 2013, Periodo di consultazione: giugno - luglio 2013, Bibliografia 187

Lingua: inglese, URL: http://nparashuram.com/IndexedDBShim/

[13] “Introducing Web SQL Databases” Autore: Remy Sharp, Anno di pubblicazione: 24 febbraio 2010, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: http://html5doctor.com/introducing-web-sql-databases/

[14] “Jasmine” Autore: Pivotal Labs, Anno di pubblicazione: 2012, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://pivotal.github.io/jasmine/

[15] “Multiple taps issue - BUG?” Autore: Sencha Forum, Anno di pubblicazione: 24 marzo 2012, Periodo di consultazione: luglio 2013, Lingua: inglese, URL: http://www.sencha.com/forum/showthread.php?208657- Multiple-taps-issue-BUG

[16] “No Silver Bullet — Essence and Accidents of ” Autore: Frederick P. Brooks Jr., Anno di pubblicazione: 1986, Periodo di consultazione: luglio 2013, Lingua: inglese, URL: http://faculty.salisbury.edu/ xswang/Research/Papers/ SERelated/no-silver-bullet.pdf

[17] “PhoneGap” Autore: Adobe, Anno di pubblicazione: 2013, Periodo di consultazione: maggio - giugno 2013, Lingua: inglese, URL: http://phonegap.com/

[18] “PhoneGap Development Guide” Autore: Adobe, Anno di pubblicazione: 2013, Periodo di consultazione: maggio 2013, Lingua: inglese, URL: http://docs.phonegap.com/en/2.2.0/guide_plugin- development_index.md.html

[19] “PhoneGap Documentation - Storage” Autore: Adobe, 188 Bibliografia

Anno di pubblicazione: 2013, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://docs.phonegap.com/en/2.7.0/cordova_storage _storage.md.html#Storage

[20] “PhoneGap v2.7.0 - feature” Autore: Adobe, Anno di pubblicazione: 2013, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://phonegap.com/about/feature/

[21] “Revisiting the Sencha Touch 2.2 Sql Proxy” Autore: Druck-it, Anno di pubblicazione: 2 aprile 2013, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: http://druckit.wordpress.com/2013/04/02/revisiting-the- sencha-touch-2-2-sql-proxy/

[22] “Sencha Docs IO” Autore: Sencha inc., Anno di pubblicazione: 2013, Periodo di consultazione: giugno 2013, Lingua: inglese, URL : http://docs.sencha.io/current/index.html#!/guide/ overview_introduction

[23] “Sencha Touch 2 SQL proxy for SQLite” Autore: Vadim Popa, Anno di pubblicazione: 3 marzo 2013, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: http://vadimpopa.com/sencha-touch-2-sql-proxy-for- sqlite/

[24] “Sencha Touch” Autore: Sencha inc., Anno di pubblicazione: 2013, Periodo di consultazione: maggio - luglio 2013, Lingua: inglese, URL: http://www.sencha.com/products/touch

[25] “Sencha Touch: Clarifying WebSQL, SQLite and how they relate to Sencha Touch” Autore: Simon Shepherd, Anno di pubblicazione: 19 aprile 2013, Periodo di consultazione: giugno 2013, Bibliografia 189

Lingua: inglese, URL: http://senchatouchdev.com/wordpress/2013/04/19/sencha- touch-clarifying-websql-sqlite-and-how-they-relate-to-sencha- touch/

[26] “Sencha Touch Performance Tips and Tricks” Autore: Dion Beetson, Anno di pubblicazione: 31 ottobre 2012, Periodo di consultazione: luglio 2013, Lingua: inglese, URL: http://dionbeetson.blogspot.it/2012/10/sencha-touch- performance-tips-and-tricks.html

[27] “Sencha Touch Support” Autore: Sencha inc., Anno di pubblicazione: 2013, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: https://www.sencha.com/store/touch/

[28] “SQLite Foreign Key Support” Autore: SQLite sito ufficiale, Anno di pubblicazione: 2012, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: http://www.sqlite.org/foreignkeys.html

[29] “SQLite Manager 0.8.0” Autore: Mozila, Anno di pubblicazione: aprile 2013, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://addons.mozilla.org/it/firefox/addon/sqlite- manager/

[30] “The Sencha Class System” Autore: Jacky Nguyen, Anno di pubblicazione: 29 novembre 2011, Periodo di consultazione: giugno - luglio 2013, Lingua: inglese, URL: http://www.sencha.com/learn/sencha-class-system

[31] “UI Testing a Sencha App” Autore: Arthura Kay, Anno di pubblicazione: 10 gennaio 2013, Periodo di consultazione: luglio 2013, Lingua: italiano, URL: http://www.sencha.com/blog/ui-testing-a-sencha-app 190 Bibliografia

[32] “Using Model Associations in Sencha Touch 2 and Ext JS 4” Autore: Rob Boerman e Aaron Smith, Anno di pubblicazione: 8 luglio 2012, Periodo di consultazione: giugno 2013, Lingua: inglese, URL: http://appointsolutions.com/2012/07/using-model- associations-in-sencha-touch-2-and-ext-js-4/

[33] “Wikipedia - definizione BDD” Autore: Wikipedia, Anno di pubblicazione: 9 aprile 2013, Periodo di consultazione: luglio 2013, Lingua: italiano, URL: http://it.wikipedia.org/wiki/Behavioural- driven_development

[34] “Wikipedia - definizione ERP” Autore: Wikipedia, Anno di pubblicazione: 28 giugno 2013, Periodo di consultazione: luglio 2013, Lingua: italiano, URL: http://it.wikipedia.org/wiki/Enterprise_resource_planning

[35] “Wikipedia - definizione s.r.l.” Autore: Wikipedia, Anno di pubblicazione: 23 maggio 2013, Periodo di consultazione: luglio 2013, Lingua: italiano, URL: http://it.wikipedia.org/wiki/Società_a_responsabilità _limitata

[36] “Wikipedia - definizione TDD” Autore: Wikipedia, Anno di pubblicazione: 14 marzo 2013, Periodo di consultazione: luglio 2013, Lingua: italiano, URL: http://it.wikipedia.org/wiki/Test_Driven_Development

github - tool e strumenti

[37] “GitHub - Ext.data.proxy.WebSQL” Autore: Vansante, Anno di pubblicazione: ottobre 2012, Periodo di utilizzo: giugno 2013, Tipologia strumento: plugin Sencha per l’uso del WebSQL, URL: https://github.com/grgur/Ext.data.proxy.WebSQL#readme Bibliografia 191

[38] “GitHub - Jasmine wiki - Matchers” Autore: Pivotal Labs, Anno di pubblicazione: 2012, Periodo di utilizzo: giugno - luglio 2013, Tipologia strumento: wiki contenenti i matchers usabili con il me- todo expect() delle spec Jasmine, URL: https://github.com/pivotal/jasmine/wiki/Matchers [39] “GitHub - LintRoller” Autore: Arthura Kay, Anno di pubblicazione: maggio 2013, Periodo di utilizzo: luglio 2013, Tipologia strumento: tool per l’esecuzione di syntax check su listati JavaScript, URL: https://github.com/arthurakay/LintRoller [40] “GitHub - PG-SQLitePlugin-Android” Autore: Chris Brody, Anno di pubblicazione: 2013, Periodo di utilizzo: luglio 2013, Tipologia strumento: plugin Sencha per l’uso del WebSQL, URL: https://github.com/pgsqlite/PG-SQLitePlugin-Android [41] “GitHub - Plugin PhoneGap” Autore: Jesse MacFadyen, Anno di pubblicazione: 2010, Periodo di utilizzo: maggio - giugno 2013, Tipologia strumento: plugin di PhoneGap, URL: https://github.com/phonegap/phonegap-plugins

strumenti per lo sviluppo android

[42] “Eclipse” Azienda/ente produttore: Eclipse Foundation, Tipologia strumento: IDE per lo sviluppo software, URL: http://www.eclipse.org/downloads/ [43] “Java SE Development Kit 7” Azienda/ente produttore: Oracle, Tipologia strumento: kit di sviluppo per applicazioni Java, URL: http://www.oracle.com/technetwork/java/javase/downloads/ jdk7-downloads-1880260.html

sito dell’azienda ospitante

[44] “Soluzioni Software s.r.l.” URL: http://www.soluzioni-sw.it/

INDICEANALITICO

—cAc— —cOc— AJAX, 20 Observer, 125 Android, 11 Apcelerator Titanium, 38 —cPc— PhoneGap —cBc— Definizione, 33 BDD, 61 Funzionalità, 34 BlackBerry, 12 —cRc— —cCc— Rhomobile, 37 CSS3, 20 —cSc— —cFc— Sencha Factory method, 125 Associazioni, 43 Firefox OS, 14 Build, 36 callParent(), 43 —cHc— Componenti base, 32 HTML5, 19 Definizione, 31 Store, panoramica, 69 Directory di progetto, 39 Eventi, 49 —cIc— Ext.Class, 40 IndexedDB Storage, 70, 71 Ext.data.proxy, 46 iOS, 11 Ext.data.Store, 45 —cJc— Ext.define(), 41 Jasmine, 167 Jasmine, 64 JavaScript, 20 Multi-tap, 53 fireEvent(), 49 MyCustumProxy, 48 jQuery Mobile, 37 Namespacing, 42 Plugin WebSQL, 72 —cLc— Post-processor, 43 LintRoller, 62 Pre-processor, 42 Local Storage, 69 Scrolling, 57 Server-side Proxy, 47 —cMc— Viewport dinamico, 56 Module pattern, 157 Web Storage, 70 —cNc— WebSQL, 70 NotesApp, 77 Sencha.IO, 73 App.js, 83 Session Storage, 69 Architettura, 79 Singleton, 125 NoteStore, 84 Soluzioni Software, 3 Requisiti, 77 Dati aziendali, 3 SyncEngine, applicazione, 137 Prodotti, 4

193 194 indice analitico

SQLite, 159 —cWc— Stage Web Storage, 69, 71 Dati, 5 WebSQL, 69, 163 Device utilizzati, 23 Gestione ID, 71 Piano di lavoro, 6 Windows Phone, 12 Scopo, 4 Software utilizzato, 24 Valutazione strumenti, 27 Strategy, 125 Sviluppo mobile, 14 Ibrido, 16 Nativo, 15 Web app, 15 Symbian, 12 SyncEngine Architettura, 124 Capitolato, 94 createSyncStore(), 126 Download, 126 IndexIDStore, 107, 112 Pattern, 125 Requisiti, 104, 151 SingleTapButton, 110, 122 StoreOperation, 109, 117 SyncManager, 107, 120, 141 SyncStore, 108, 115, 129 Syntax check, 151 Test di unità, 146 UseCase, 95 Syntax check, 62, 151

—cTc— TDD, 60 Tizen, 14

—cUc— Ubuntu Phone OS, 14 UI test, 68 Unit test, 63

—cVc— Verifica, 59 Analisi dinamica, 59 Analisi statica, 59 Strumenti, 61 Test, 59