Sei sulla pagina 1di 211

— Università 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:
andreapd90@hotmail.it

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)
P R E FA Z I O N E

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
Software 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 introduzione 1
1 informazioni sullo stage 3
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 AJAX . . . . . . . . . . . . . . . . . . . . . . . . . 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
ELENCO DELLE FIGURE

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.html . . . . . . . . . . . . . 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 javascript 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à.
I N F O R M A Z I O N I S U L L O S TA G E
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 : info@soluzioni-sw.it;

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 Management e 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 web
application - 60 ore;
• studio del dominio tecnologico e verifica delle competenze
acquisite, mediante realizzazione di un’applicazione deno-
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.
U N A PA N O R A M I C A S U L L O S V I L U P P O M O B I L E
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 approcci di sviluppo 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
prestazioni.
Quindici anni fa Java promise di essere il linguaggio che
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’html5.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 <video> e <audio>);
• vengono deprecati o eliminati alcuni elementi che hanno dimo-
strato scarso o nessun utilizzo effettivo;
• vengono estesi a tutti i tag una serie di attributi, specialmente
quelli finalizzati all’accessibilità, finora previsti solo per alcuni
tag;
• viene supportato Canvas che permette di utilizzare JavaScript
per creare animazioni e grafica bitmap;
• introduzione della geolocalizzazione, dovuta ad una forte espan-
sione di sistemi operativi mobili (quali Android e iOS, tra i più
diffusi);
• sistema alternativo ai normali cookie, chiamato Web Storage,
più efficiente, il quale consente un notevole risparmio di banda;
• standardizzazione di programmi JavaScript, chiamati Web Wor-
kers e possibilità di utilizzare alcuni siti offline;
• sostituzione del lungo e complesso doctype, con un semplice
<!DOCTYPE html>.
20 una panoramica sullo sviluppo mobile

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 Object
Model (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 Safari).

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 (Document Object Model) 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 <script> aggiunti dinamicamente
(JSON);

• in genere viene usato XML come formato di scambio dei dati,


anche se di fatto qualunque formato può essere utilizzato, in-
cluso testo semplice, HTML preformattato o JSON. Questi file
sono solitamente generati dinamicamente da script lato server.

Le applicazioni web che usano AJAX richiedono browser che sup-


portano le tecnologie sopracitate.
A M B I E N T E D I L AV O R O
3
3.1 strumenti utilizzati

Prima di iniziare con la parte relativa a Sencha, vi propongo di segui-


to un elenco degli strumenti utilizzati durante lo studio. Gli strumenti
si dividono in due tipologie:

• i dispositivi e gli strumenti hardware usati;

• i programmi usati (strumenti software).

Per ognuno vengono fornite alcune informazioni di base sul mo-


tivo dell’utilizzo e sui vantaggi derivanti da ciò. Per gli strumenti
hardware è fornita una scheda tecnica, utile per comprendere meglio
i risultati ottenuti durante lo studio e la realizzazione del SyncEngi-
ne. Prima di procede si sottolinea che gli strumenti proposti rappre-
sentano una soluzione gratuita alle nostre esigenze di lavoro. Solo
nelle rispettive sezioni di Sencha e PhoneGap saranno proposte delle
alternative a pagamento.

strumenti hardware :
• Notebook ASUS
tipo device : notebook;
produttore : ASUSTeK Computer Inc.;
sistema operativo : Windows 7 Home Premium;
tipo sistema : 64 bit;
cpu : i7-2670QM da 2.20GHz;
scheda video : NVIDIA GeForce GT 540M;
ram : 6 GB;
scopo di utilizzo : sviluppo software, debugin, uso di
internet per l’attività di studio e la consultazione di
articoli.
• Huawei Honor U8860 Dispositivi mobile
impiegati per il
tipo device : smartphone; testing.
produttore : Huawei;
sistema operativo : Android 4.0.3;
chipset : Qualcomm MSM8255T Snapdragon;
cpu : Scorpion single-core 1.4 GHz;

23
24 ambiente di lavoro

gpu : Adreno 205;


ram : 512 MB;
scopo di utilizzo : testing sui limiti degli store HTML5,
testing dell’app NotesApp, testing componente Syn-
cEngine.
• Huawei Ascend P6
tipo device : smartphone;
produttore : Huawei;
sistema operativo : Android 4.2.2;
cpu : modllo K3V2, quad-core 1.5 GHz;
ram : 2 GB;
scopo di utilizzo : testing dell’app NotesApp, testing
componente SyncEngine.
• Samsung tablet GT-P6510
tipo device : tablet;
produttore : Samsung;
sistema operativo : Android 4.2.2;
cpu : dual core da 1 GHz;
scopo di utilizzo : testing sui limiti degli store HTML5,
testing dell’app NotesApp, testing componente Syn-
cEngine.

strumenti software :
• JDK: per sviluppare una mobile application fruibile su piat-
taforme Android, si necessita del Java Delelopment Kit. Fin
dall’introduzione di Java questo strumento, sviluppato dal-
la Oracle, è sempre stato l’ambiente di sviluppo più utiliz-
zato dai programmatori Java. Si osservi che la JDK contiene
già la JRE che di conseguenza non dovrà essere scaricata
ed installata separatamente. Alla data corrente l’ultima ver-
sione disponibile (che corrisponde anche a quella usata) è
la 7. Nello specifico la distribuzione utilizzata durante lo
stage è la Java SE Development Kit 7u21 per Windows
x64. Tale nomenclatura è la stessa presente nel sito della
Oracle [43, “Java SE Development Kit 7” ] dove è reperibile
il kit di sviluppo;
• Eclipse: è un ambiente di sviluppo (IDE) integrato multi-
linguaggio e multipiattaforma. Ideato da un consorzio di
grandi società quali Ericsson, HP, IBM, Intel, MontaVista
Software, QNX, SAP e Serena Software, chiamato Eclipse
Foundation sullo stile dell’open source. Per quanto la scel-
ta tra le diverse versioni non dovrebbe comportare alcun
3.1 strumenti utilizzati 25

problema, si raccomanda il download di Eclipse IDE for


Java EE Developers. Alla data corrente, l’ultima versione
(che corrisponde anche a quella utilizzata in questa guida)
è Juno1 (4.2);
• PhoneGap: framework necessario per il porting delle web
application. Una trattazione approfondita di questo fra-
mewrok sarà data nella seconda parte della tesi. Questo
strumento è reperibile dal sito ufficiale di PhoneGap2 . Alla
data corrente è disponibile la versione 2.7.0, ed è questa la
versione da me usata nei miei studi;
• Sencha Touch 2 SDK: framework JavaScript per lo svulup-
po di applicazioni ibride. Il framework è reperibile al sito
ufficiale della Sencha inc. Alla data in cui è stato iniziato lo
stage è disponibile la versione 2.2.0. Nei mesi successivi è
uscita la versione 2.2.1 ma, per conformità con quanto usa-
to all’inizio dello stage, tutte le informazioni qui reperibili
si rifanno alla versione 2.2.0. La versione usata appartiene
ad un pacchetto gratuito di sviluppo. Tuttavia si mette in
evidenza la presenza di una versione a pagamento, otti-
ma se si desidera un ambiente di sviluppo completo. Tale
versione fornisce:
– Sencha Architect;
– Sencha Ext JS;
– Sencha Touch SDK
– Sencha Eclipse Plugin;
– Sencha Touch Charts;
– Sencha Mobile Packaging;
– Enterprise Data Connectors;
– Sencha Support Package;
• ANT: Apache Ant è un software per l’automazione del pro-
cesso di build. È simile a make ma è scritto in Java ed è
principalmente orientato allo sviluppo con tale linguaggio.
Ant è un progetto Apache open source ed è rilasciato sotto
licenza Apache;
• Android SDK: è l’ambiente di sviluppo di Android che,
usato insieme all’IDE Eclipse, permette di realizzare delle
applicazioni per sistemi Android. Come vederemo, l’uso
di PhoneGap insieme a questi due strumenti sono alla base
delle applicazioni ibride per Android;
• plugin Android ADT: questo plugin è essenziale per riu-
scire a sviluppare applicazioni Android con Eclipse;
1 Il software è reperibile al sito [42, “Eclipse” ].
2 Sito di PhoneGap: [17, “PhoneGap” ]
26 ambiente di lavoro

• IIS: è un complesso di servizi server Internet per sistemi


operativi Microsoft Windows. Durante lo stage è stato usa-
to per rendere possibile il testing dell’applicazione Note-
sApp e della componente SyncEngine. Lo strumento è già
presente (ma non installato) nella distribuzione Windows
seven home premium da me usata;
• Google Chrome: è un browser basato su WebKit svilup-
pato da Google, usato nello stage per accedere alle pagine
.js che compongono l’applicazione. Particolarmente utile
durante il debugin, è stato il tool per sviluppatori forni-
to da Chrome. Accedibile selezionando la voce “ispezio-
na elemento” (che compare nel menù a tendina derivante
da un click destro sulla pagina in esame), fornisce diverse
informazioni utili tra cui:
– una console dei messaggi di log e di errore di Java-
Script;
– un visualizzatore del sorgente HTML;
– un tool per controllare il contenuto dei vari store HTML
usati dall’applicazione;
• SQLite Manager: è un componente aggiuntivo di Firefox,
molto utile per esaminare e gestire il contenuto di data-
base SQLite. Per una trattazione approfondita di questo
strumento, e per un’introduzione alle specifiche di SQLite,
si rimanda all’appendice “sqlite”

3.2 best practice di configurazione

In questa sezioni tratterò alcune best practice individuate durante


la configurazione e l’utilizzo degli strumenti proposti al paragrafo
precedente. Questi suggerimenti oltre a garantire un miglioramento
dei tempi di sviluppo permettono di diminuire gli errori in cui si
rischia di incappare durante le prime prove con Sencha e PhoneGap.
Elenco delle best
practice di • durante l’attività d’installazione dell’ambiente di lavoro è im-
configurazione.
portante prendere nota dei percorsi d’installazione dei vari stru-
menti. Questo perché, in un secondo momento, sarà necessario
configurare le variabili d’ambiente di Windows. Nello specifico
bisognerà aggiungere alla variabile “path” i percorsi ai seguenti
file:
– javac;
– ant;
– adb3 ;
3 Il percorso è relativo ad adb.exe, e lo troverete nella cartella platform-tools presente
nella directory d’installazione della Andrid SDK.
3.3 riferimenti utili 27

– android4 ;

• al termine dell’installazione conviene salvare in un file di bac-


kup la stringa associata alla variabile path. Durante lo stage è
emersa la necessità di installare Node.js. Al termine dell’instal-
lazione si è osservato che la variabile path era stata sovrascritta
dal percorso d’installazione di Node.js. Un backup dei percorsi
usati risolve facilmente il problema;

• dopo l’installazione di IIS è importante aggiornare il catalo-


go MIME aggiungendo l’estensione “JSON’ per le applicazioni
“application/json”.

3.3 riferimenti utili

Tutte le note qui riportate sono in parte dovute all’esperienza appresa


durante lo stage e in parte riscontrate dalla lettura di diversi articoli.
Di seguito propongo una serie di riferimenti bibliografici utili sia
per l’installazione che per la configurazione dell’ambiente di lavoro.
Per leggere i dettagli dei vari riferimenti si rimanda alla bibliografia
proposta in appendice.

• Risoluzione dei problemi legati a IIS: [7, “Get IIS6 to serve


JSON files” ];

• Problemi tipici nella configurazione dell’ambiente di lavoro:


[8, “Getting the create Command to Work on PhoneGap 2.2.0 An-
droid” ].

3.4 valutazione finale degli strumenti

Gli strumenti utilizzati si sono dimostrati validi per lo scopo e di


facile installazione. Salvo qualche piccolo rallentamento dovuto alla
mancanza di esperienza nel loro utilizzo, se ne raccomanda l’utilizzo,
soprattutto in virtù del fatto che gli strumenti sono gratuiti.
Particolarmente utili durante il debugin, sono stati:

• SQLite Manager;

• il tool per sviluppatori fornito da Google Chrome.

Con il primo ho testato il sistema di salvataggio dei database SQ-


Lite offerto da HTML5. Con il secondo è stato testato parte del com-
portamento legato alla modifica degli store di HTML5, e mediante
messaggi console di diagnostica, si è facilitato il compito di studio
della struttura degli oggetti JavaScript usati e del loro contenuto.
Interessante è stato l’utilizzo dell’IDE Sencha Architect (che ricordo Sencha Architect,
per un ambiente di
4 Troverete il file nella cartella d’installazione della SDK di Andorid. sviluppo completo.
28 ambiente di lavoro

essere presente nella SDK completa di Sencha Touch). Di base questo


ambiente di sviluppo è a pagamento. Di conseguenza è stato unica-
mente possibile provarlo per un paio di giorni nella sua versione trial.
In particolare si Segnala la possibilità di costruire l’interfaccia grafica
in maniera facile ed intuitiva, mediante un sistema di drag and drop
degli oggetti, direttamente sul piano di lavoro. Il codice auto-generato
si è rivelato pulito e sufficientemente ottimizzato.
In merito all’uso di Eclipse, come unica nota negativa, si segnala la
mancanza di un plugin gratuito (simile all’ADT di Android) per lo
sviluppo di applicazioni con Sencha Touch 2. L’unica alternativa in
merito è a pagamento e facente parte del SDK completa di Sencha.
Parte II

SENCHA TOUCH 2

In questa parte sono riportati i fondamenti dei framework


e alcune best practice emerse durante l’attività di studio
di Sencha Touch e PhoneGap. In particolare sono stati
inserite diverse considerazioni riguardanti il sistema di
archiviazione dei dati di Sencha.
INTRODUZIONE
4
4.1 sencha touch

4.1.1 Le basi del framework

Figura 4: Sencha Touch - logo [24, “Sencha Touch” ]

Sencha Touch1 è un framework JavaScript avente architettura MVC, Sencha è un


e il suo utilizzo è particolarmente adatto alla realizzazione di applica- framework MVC.
zioni mobile ibride. Tra le sue caratteristiche c’è la capacità di sviluppa-
re applicazioni con il look and fell nativo delle principali piattaforme
mobile. Tutto ciò avviene semplicemente caricando un apposito css
nella pagina index.html dell’applicativo.
Sencha basa il proprio funzionamento su Ext JS e dispone di alcune
componenti grafiche appositamente ottimizzate per un input di tipo
touch.
Molto interessante è il modo con cui gli sviluppatori di Sencha han- Sencha simula OOP.
no cercato di definire un esperienza d’utilizzo il più vicino possibile
a quella di un moderno linguaggio OOP pur non essendolo (ricordo
che Sencha si basa su JavaScript che, per quanto detto nell’introdu-
zione, non è un linguaggio ad oggetti). In particolare segnalo la pos-
sibilità di usare un sistema di ereditarietà, e la possibilità di definire
“stampi” (Ext.define) per oggetti, molto simili al concetto di “classi”.
Quando si desidera creare un’applicazione con Sencha, è impor-
tante seguire alcune prassi obbligatorie. Nello specifico si necessità
sempre di due file:

• index.html: è la pagina html principale da cui richiamare l’ap-


plicazione. Essa predispone:
– i fogli di stile CSS per gestire la grafica dell’applicazione;

1 In Figura 4 è presente il logo del framework. L’immagine e alcune informazioni


riportate in questo capitolo, sono state estrapolate dal sito ufficiale della Sencha inc.
[24, “Sencha Touch” ].

31
32 introduzione

– i file .js corrispondente al kernel delle librerie esterne neces-


sarie (quindi di sicuro il file js della libreria di Sencha);
– il file app.js (che osserviamo deve risiedere nella stessa
directory di index.html);

• app.js: definisce l’oggetto Ext.Application usato per inizializza-


re e avviare l’applicazione.

Un oggetto Ext.Application permette di specificare i file esterni


da caricare (si pensi all’import dei file usato su Java), e all’interno
di una funzione denominata launch() è possibile caricare le viste
facenti parte del “viewport”, ossia tutte le viste navigabili usando
l’applicazione.

4.1.2 Le componenti principali

Volendo fornire una visione generale dell’architettura di Sencha, evi-


denzio le seguenti componenti:

• Ext.Container - [View]: sono le viste della nostra applicazione


e sono definibili come dei contenitori di componenti grafici;

• Ext.data.Model - [Model]: rappresentano il modello dei dati.


Quando definiamo un model definiamo i campi che lo caratte-
rizzano e la loro natura (tipologia, parametri di default, opziona-
lità di inserimento, ecc...). Idealmente possiamo pensare ad un
model come allo schema di una tabella di un database. Quando
definiamo un Model è possibile (ma non obbligatorio) definire
anche la tipologia della sorgente fisica da cui estraiamo e su
cui memorizziamo i dati.

• Ext.data.proxy.Proxy - [Proxy]: rappresenta la tipologia di sor-


gente fisica espressa al punto precedente. Un proxy in associa-
zione ad un Model, definisce come i dati vengono gestiti fisica-
mente dal browser e (nel caso siano usati su una applicazione
ibrida) dal dispositivo portatile. Per esempio un proxy può es-
sere di tipo JsonP, stabilendo quindi che la sorgente dei dati
è fisicamente presente in un server esterno al dominio in cui
risiede l’applicativo.

• Ext.data.Store - [Store]: rappresenta un interfaccia alla sorgente


in cui sono contenuti dei dati corrispondenti ad un certo mo-
dello. Usando le nomenclature fin qui acquisite, rappresenta un
interfaccia ad un Ext.data.proxy.Proxy. Ribadisco che i dati me-
morizzati devono essere conformi allo schema espresso da un
model, dichiarato in fase di definizione dello Store (o in alter-
nativa dichiarato durante la definizione del proxy associato allo
4.2 phonegap 33

store). Uno Store è un oggetto che può essere facilmente associa-


to ad un componente della vista (come per esempio una lista).
Sencha predispone una relazione store-view simile a quella de-
finita dal pattern observer , e garantisce quindi una sincroniz- Un uso naturale del
zazione automatica della vista al variare dei dati presenti nello pattern observer.
store. In conformità al suo ruolo di interfaccia ad un proxy, lo
store predispone dei metodi di manipolazione dei record, di fil-
traggio dei dati, e altri per facilitare la ricerca di un record sotto
specifiche condizioni. Tutto ciò avviene indifferentemente dalla
tipologia di proxy adottata, permettendo allo sviluppatore di
cambiare proxy in un qualsiasi momento senza dover cambiare
lo store usato per interfacciarsi ai record.

• Ext.app.Controller - [Controller]: è l’oggetto contenente la logi-


ca di gestione dei dati. In una buona programmazione, il con-
troller dovrebbe essere colui che fa interagire la vista con i da-
ti sottostanti (pensando ad un’architettura MVC) e che sa far
corrispondere ad ogni evento il giusto gestore.

4.2 phonegap

4.2.1 Cos’è PhoneGap

Figura 5: PhoneGap - logo [17, “PhoneGap” ]

PhoneGap2 è un framework JavaScript per lo sviluppo mobile cross-


platform . Con esso è possibile creare delle applicazioni native attraver- PhoneGap
so l’utilizzo di tecnologie web quali HTML, CSS e JavaScript. In altre garantisce il
cross-platform.
parole, PhoneGap consente di “tradurre” le web-application in mobile
application.
L’architettura di Phonegap prevede uno strato di astrazione del de-
vice, che espone le funzionalità mediante un API JavaScript utilizza-
bile dall’applicazione senza conoscere i dettagli del device sottostante.
Per ottenere questo risultato esiste una controparte nativa, specifica
2 In Figura 5 è presente l’immagine del logo del framework.
34 introduzione

per piattaforma/sistema operativo, che mappa le funzionalità sulle


API specifiche del device.
Il codice dell’applicazione è basato su HTML, CSS e Javascript, esat-
tamente come una mobile web app servita da un web server. In que-
sto caso le risorse fanno parte degli asset locali distribuiti insieme
all’ applicazione nativa, che (semplificando) utilizza un istanza del-
l’oggetto UIWebView come “container” per eseguire l’applicazione e
comunicare con il layer nativo. Questo tipo di approccio è noto come
hybrid mobile app.
PhoneGap è Qualora le API disponibili con PhoneGap non fossero sufficienti,
estendibile tramite il framework è estendibile grazie ad un’architettura a plugin3 , che
plugin.
consente di creare nuove funzionalità, sviluppandone la controparte
nativa ed esponendole via Javascript. Ciò da una parte si esprime
come un vantaggio ma, in un contesto cross-platform, potrebbe rive-
larsi anche una limitazione dal momento che occorre sviluppare una
controparte nativa del plugin per ogni piattaforma/sistema operativo
mobile che si desidera supportare.

4.2.2 Funzionalità e dispositivi supportati

Alla data in cui ho iniziato lo stage PhoneGap è alla versione 2.7.0,


e questa sarà la versione cui mi riferirò per tutto il resto della tesi.
Si segnala comunque che nel corso dei 2 mesi successivi dall’inizio
dello stage, PhoneGap ha raggiunto la versione 2.9.0 (26 giugno 2013).
PhoneGap ha la possibilità di essere utilizzato sulle piattaforme:

• Android;

• iOS;

• Blackberry OS;

• WebOS;

• Windows Phone 7 ed 8;

• Symbian;

• Bada;

Nello specifico sono supportate le feature riportate in Figura 6.

3 Il repository ufficiale, basato su GitHub, contenente i plugin di PhoneGap è disponi-


bile all’indirizzo: [41, “GitHub - Plugin PhoneGap” ].
La guida completa per lo sviluppo di plugin nativi (l’argomento non è trattato in
questa tesi) è disponibile su [18, “PhoneGap Development Guide” ].
Figura 6: PhoneGap v2.7.0 - funzionalità supportate [20, “PhoneGap v2.7.0 - feature” ]
4.2 phonegap
35
36 introduzione

4.2.3 Sistema di build delle applicazioni

Come già detto PhoneGap può essere visto come un framework atto
a trasformare delle web application in applicazioni mobile fruibili su
più piattaforme. Il build dell’app può avvenire in due modi:

• utilizzo di piattaforme specifiche: la creazione di un applicazio-


ne con PhoneGap richiederà strumenti di sviluppo particolari a
seconda della piattaforma su cui vogliamo rendere disponibile
l’app. Per esempio se si volesse distribuire l’app su piattafor-
me iOS, sarebbe necessario disporre di un computer Apple con
installato Xcode. Il sistema che andremmo a descrivere, si basa
sull’uso di una piattaforma Windows con lo scopo di distribuire
l’app su sistemi android;

• utilizzo di un build online: Adobe ha creato un sistema di build


online che permette di caricare il proprio codice sorgente o me-
diante un upload diretto, oppure specificando l’indirizzo di un
repository Git contenente l’applicazione mobile. Questa scelta
sicuramente comoda e da preferirsi alla prima, presenta però
lo svantaggio di essere a pagamento, e di fornire gratuitamen-
te il build di un’unica applicazione. Per ulteriori informazio-
ni rimandiamo al riferimento bibliografico [2, “Adobe PhoneGap
Build”].

4.2.4 Considerazioni su PhoneGap

I vantaggi di In conclusione PhoneGap presenta i seguenti vantaggi:


PhoneGap.
• garantisce tutti i vantaggi legati allo sviluppo cross-platform;

• la curva di apprendimento (per le funzionalità base) è molto


lieve. Praticamente inesistente per chi già conosce JavaScript e
in particolare i metodi per accedere alle risorse del device;

• il continuo rilascio di plugin rende PhoneGap sempre più poten-


te, aprendo le porte agli sviluppatori per la creazione di nuove
app;

• se si sviluppano le applicazioni mediante un framework Java-


Script, orientato allo sviluppo mobile, l’impressione è quella di
non usare nemmeno PhoneGap. L’approccio ai suoi strumenti è
totalmente invisibile agli occhi dello sviluppatore.

Gli svantaggi di Gli svantaggi invece sono:


PhoneGap.
• se si ha in animo di produrre un nuovo plugin, si è costretti a
svilupparlo per tutte le piattaforme supportate da PhoneGap;
4.3 alternative ai framework proposti 37

• le applicazioni che basano il proprio funzionamento su Phone-


Gap hanno un notevole calo delle prestazioni. In particolare, il
suo utilizzo sembra valido solo per smartphone di fascia alta e
tablet di fascia medio-alta.

4.3 alternative ai framework proposti

4.3.1 Framework per lo sviluppo

Quando pensiamo a delle alternative all’uso di Sencha, quindi alter-


native al framework con cui sviluppare l’applicazione web di base,
fondamentalmente tutti i framework basati su JavaScrit e sulle tecno-
logie web possono essere utilizzati allo scopo. Ovviamente la scelta è
influenzata da:

• complessità del framework utilizzato;

• predisposizione del framework allo sviluppo mobile (e.g pre-


senza di componenti grafiche adatte ai display di smartphone e
tablet);

• tipologia di framework per il porting utilizzato (ovviamente nel


caso si intenda trasformare l’app da applicazione web ad appli-
cazione ibrida);

Limitando l’esposizione a quelli che sono i framework maggior-


mente utilizzati e adatti alla realizzazione di applicazioni con look &
fell adatti a dispositivi touch, cito:

rhomobile : framework open-source sviluppato da Motorola e ba-


sato sul linguaggio Ruby, indicato per applicazioni business.
Esattamente come Sencha, permette di sviluppare applicazio-
ni con pattern architetturale MVC. Tra i vantaggi d’utilizzo si
riconosce:
• un’avanzata gestione dei dati;
• dotato di strumenti avanzati per la connessione a servizi
back-end per la gestione dei dati remoti;
• fornisce API per sfruttare molti moduli hardware dei device
(principalmente iOS e Android);

jquery mobile : framework basato sul linguaggio JavaScript è la


naturale evoluzione del framework jQuery rivolto però al mon-
do dello sviluppo mobile. Tra le sue caratteristiche principali si
osserva:
• compatibilità con la maggior parte delle piattaforme mobi-
le e dei browser desktop;
38 introduzione

• curva d’apprendimento bassa per tutti coloro che hanno


già dimestichezza con jQuery;
• dipendenze limitate e buona ottimizzazione per lo svilup-
po mobile;
• predispone diversi widget ottimizzati per l’interazione con
il touch;

Osservando che tali framework non fanno parte del mio personale
bagaglio di esperienze lavorative, le considerazioni sopra riportate si
basano su quanto letto su di articoli web. L’impressione generale è
che i tali framework, compreso Sencha, offrano più o meno le stesse
potenzialità. Tutti permettono lo sviluppo sulla quasi totalità delle
piattaforme mobile, e tutti hanno le stesse funzionalità.
La scelta del framework si basa principalmente sull’esperienza la-
vorativa del soggetto che lo usa. Conoscere già jQuery è sicuramente
un incentivo a prendere in considerazione jQuery Mobile, cosi come
conoscere Ruby lo è per Rhomobile ed Ext JS per Sencha Touch.

4.3.2 Framework per il porting

Per quanto riguarda invece i framework da usare per il porting della


web application, si segnala la presenza di un’alternativa a PhoneGap:
Appcelerator Titanium. Il framework permette il porting di applica-
zioni basate sulle tecnologie web, sia su ambienti mobile che desktop.
Sostanzialmente l’idea di base è la stessa di PhoneGap e in merito
alle differenze tra i due si segnala:

• Titanium ha un maggior numero di API e di componenti UI


native rispetto a PhoneGap;

• Titanium è sotto licenza Apache che è più rigida della MIT di


PhoneGap;

• Titanium ha un proprio IDE Eclipse based, Titanium Studio,


derivato da Aptana.

Per quanto riguarda le piattaforme supportate non si segnala nes-


suna differenza tra Titanium e PhoneGap.
BEST PRACTICE
5
5.1 come creare un progetto

Per creare una buona applicazione e lavorarvi nell’ordine, è importan-


te impostare correttamente l’ambiente di lavoro. Innanzitutto configu-
rando la directory root dell’applicazione. Nel mio caso, usando IIS, ho
inserito la cartella di lavoro nella directory wwwroot di inetpup. La
posizione definita è quella usata di default da IIS per caricare le appli-
cazioni web. Al percorso specificato si procede creando una cartella
con il nome del progetto. Quindi bisogna definire al suo interno: Struttura di un
progetto Sencha.
• una cartella app che conterrà la struttura vera e propria dell’ap-
plicativo. La cartella conterrà a sua volta:
– una cartella view;
– una cartella controller;
– una cartella store;
– una cartella model;
– (opzionale... diventa obbligatorio se si vuole ridefinire un
Ext.data.proxy.*) una cartella proxy.

Le cartelle cosi create andranno a contenere i file che de-


finiscono gli omonimi oggetti Sencha precedentemente de-
scritti;
• una cartella lib che conterrà la libreria Sencha Touch 2;
• una cartella rsc (o resorces se preferite), dove andranno caricati i
CSS personali;
• un file index.html;
• un file app.js;
• (per ora facoltativo... diventa obbligatorio se si desidera tra-
sformare la web app in un app ibrida fruibile su device porta-
tili) copiare il file cordova cordova-2.7.0.js, scaricabile insieme
all’ultima versione di PhoneGap.

5.2 considerazioni generali

La logica di sviluppo di un applicazione Sencha, non che il siste-


ma con cui si “incastrano” le varie componenti fin qui presentate,
dovrebbe essere quella di:

39
40 best practice

• progettare e predisporre la grafica dell’applicazione tramite la


definizione di un layout adatto. Per farlo è consigliabile usare
l’omonima proprietà (layout) del oggetto Ext.form.Panel, che ci
permette di stabilire come le componenti saranno inserite nella
vista;

• definire i modelli dei dati su cui lavorare, stando attenti a sce-


gliere la tipologia giusta di proxy (lo sviluppatore non si spa-
venti, passare da un tipo di proxy ad un altro in corso d’opera,
è un azione semplice quanto sostituire una stringa);

• definire gli store necessari scegliendo con cura se gestirli con


un auto load o nel caso assicurandosi di caricarli nel momento
giusto;

• associare gli store alle componenti delle view predisposte per la


visualizzazione dei dati;

• definire degli eventi da associare ai componenti della vista;

• predisporre un uno o più controller. Idealmente, sia per chia-


rezza che per manutenibilità, si definisce un controller per ogni
view dell’applicazione;

5.3 l’architettura delle classi

Prima di iniziare con la trattazione del argomento, informo il lettore


che quanto mi accingo a trattare costituisce un breve riassunto del ela-
borato [30, “The Sencha Class System” ], aggiornato con quanto da me
sperimentato durante lo stage. Detto ciò voglio ricordare che Sencha
Touch non è un linguaggio di programmazione object oriented. Pertan-
to egli non ha un concetto di programmazione a classi ben definito
come in altri linguaggi (vedi per esempio Java). Sencha cerca tuttavia
di predisporre degli oggetti il cui funzionamento e scopo emulano
quasi alla perfezione quello delle classi, dando un esperienza d’uso
che facilita lo sviluppatore nel compito di imporre una buona organiz-
zazione strutturale al codice dell’applicativo. Nello specifico Sencha
Creare oggetti con predispone un oggetto base denominato Ext.Class a cui possiamo ri-
Ext.class. ferirci quando, l’oggetto che stiamo definendo non deve ereditare nes-
sun oggetto particolare già esistente. Per creare tali entità è possibile
usare una sintassi simile alla seguente:
Listing 1: Esempio creazione di una Ext.Class in Sencha

1 var Person = new Ext.Class({


name: ’Mr. Unknown’ ,
walk: function(steps) {
alert(this.name + ’ i s walking ’ + steps + ’ steps ’ );
}
6 });
5.3 l’architettura delle classi 41

Come si può osservare l’oggetto Ext.Class accetta come unico para-


metro un oggetto costituito da coppie chiave-valore. In tale contesto
le chiavi devono essere univoche e i valori associati possono essere
oggetti, tipi primitivi o funzioni. In un certo senso cosi facendo è
possibile definire “inline” la struttura di un oggetto specificandone le
variabili e i metodi pubblici.
Come ogni classe degna di questo nome anche in Sencha è possibile
definire un costruttore per l’inizializzazione delle istanze della classe.
Per farlo si usa la keyword new come nel seguente caso:

Listing 2: Definire un costruttore per le classi Sencha

var Person = new Ext.Class({


name: ’Mr. Unknown’ ,

4 //costruttore pubblico della classe


constructor: function(name) {
this.name = name;

return this;
9 },

walk: function(steps) {
alert(this.name + ’ i s walking ’ + steps + ’ steps ’ );
}
14 });

//creo un’istanza di persona usando il costruttore


var jacky = new Person( ’ Jacky ’ );
jacky.walk(10); // alerts "Jacky is walking 10 steps"

5.3.1 Ext.define()

Ovviamente un sistema di definizione delle classi come quello pro-


posto in precedenza è sconsigliabile, e da usare solo quando Sencha
non ci permette di usare l’oggetto Ext.define(). Questo infatti ci per-
mette di definire lo schema di un oggetto (ci permette di emulare una
classe) in un file separato dal resto del codice in cui l’oggetto viene
istanziato. Ext.define() accetta 3 parametri: Usare Ext.define().

• una stringa rappresentante il nome della classe;

• un oggetto analogo a quello usato in Ext.Class, contente le cop-


pie chiave-valore usate per definire la struttura dell’oggetto;

• una funzione di callback da invocare quando tutte le dipenden-


ze della classe sono state risolte;

Un esempio di utilizzo di tale sistema è il seguente:


42 best practice

Listing 3: Usare Ext.define()

Ext.define( ’My. sample . Person ’ , {


2 name: ’Mr. Unknown’ ,

constructor: function(name) { /* ... */ },

walk: function(steps) { /* ... */ }


7 });

Per istanziare un oggetto a partire da una classe cosi definita, è


sufficiente utilizzare la già citata funzione Ext.Class(), passando:

• come primo parametro il nome completo della classe o l’alias


con cui è stata definita;

• come secondo parametro (se la classe lo richiede) l’oggetto di


configurazione usato dal costruttore ridefinito.

5.3.2 Namespacing

Come nella progettazione di ogni applicativo, usare un approccio


orientato agli oggetti ci permette di definire le classi cui si compone
l’applicativo stesso. Mediante il sistema di emulazione delle classi for-
nito da Ext.define() ciò è possibile anche con Sencha. Di conseguenza
è possibile strutturare le componenti dell’applicazione mediante una
suddivisione in package e l’ovvio ordinamento dei nomi mediante
namespacing. Ciò si ripercuote sulla nomenclatura usata per definire
le classi. Tale infatti deve rispettare la posizione che la classe in esame
ha nel package in cui è collocata. Per esempio se abbiamo il packa-
Esempio di ge MyCompany/MyTool/MyClass, la classe MyClass dovrà essere
namespacing. nominata nel Ext.define() come: MyCompany.MyTool.MyClass.

5.3.3 Pre & post-processors

Prima di creare ed eseguire una classe da noi definita, vi è un’attività


della pre-processors in cui il codice della classe viene esaminato alla
ricerca di determinate parole chiave. Tra queste keyword cito:

Usare le estensioni • extend: property usata per emulare il meccanismo di ereditarie-


in Sencha. tà tra classi;

• mixins: property usata per far si che la classe definita contenga


anche i dati delle classi specificate in tale proprietà;

• config: property in cui vengono definite coppie chiave-valore


per le quali il meccanismo di pre-processors definisce metodi di
set e di get in automatico;
5.4 come usare le associazioni tra modelli 43

• requires: property usata per definire una serie di elementi ester-


ni richiesti dalla classe per i suoi scopi (simile al meccanismo di
import delle classi in Java);

• statics: property che permette di definire delle variabili e delle


funzioni statiche;

Analogamente ai pre-processors esistono dei post-processors, ossia


delle parole chiave (con funzioni ben precise) che vengono processate
a run-time solo quando la classe è pronta. Tra queste menziono:

• singleton: emulazione del pattern singleton, usata quindi per Usare il pattern
limitare il numero di istanze creabili ad una; singleton.

• alternateClassName: permette di definire un nome alternativo


con cui riferirsi alla classe. Generalmente usata per garantire
una retro-compatibilità per le classi rinominate;

• alias: genera un xtypes che viene mappato nel contesto dell’ap-


plicazione. Tale alias può essere usato in un qualsiasi punto
come shorthands (abbreviazione) per riferirsi alla classe stessa.

5.3.4 Ridefinire un metodo

In ultima segnalo una best practice legata al override dei metodi. Se vi


trovate ad estendere una classe di Sencha, può essere necessario ride-
finire un comportamento specifico per un metodo della superclasse,
che al suo interno preveda un caso di default la cui gestione debba
essere delegata allo stesso metodo della superclasse (quindi al me-
todo non sovrascritto). Un esempio potrebbe essere la ridefinizione
del metodo load() di uno store. Supponendo di voler gestire in modo
diverso il primo load, potremmo sovrascrivere il metodo andando a
specificare un comportamento per il nostro caso, richiamando negli
altri il load di super. Una procedura del genere si esegue inserendo, this.callParent()
all’interno del metodo sovrascritto, l’istruzione this.callParent(). Si permette di
richiamare il metodo
osservi infine che se il metodo richiamato necessità di parametri la
corrente della
dicitura diventa this.callParent(arguments). superclasse.

5.4 come usare le associazioni tra modelli

Sencha permette di definire 3 diverse tipologie di associazione1 tra Tipologie di


modelli: associazioni.

• hasOne: serve per indicare che un istanza del modello è associa-


ta ad una ed una solo istanza del modello a cui è associata (e.g.
una macchina ha uno ed un solo motore -> car hasOne engine);

1 In Figura 7 è riportato un esempio d’utilizzo di tutte e 3 le tipologie.


44 best practice

• hasMany: serve per indicare un associazione multipla. L’istan-


za di partenza è associata a zero o più istanze del modello
associato (e.g. una macchina ha più ruote -> car HasMany tyre);

• belongsTo: indica un rapporto di appartenenza unitario, del ti-


po padre-figlio (e.g una macchina appartiene ad uno ed un solo
proprietario -> car belongsOne owner).

Figura 7: Sencha Touch - associazioni tra modelli [32, “Using Model


Associations in Sencha Touch 2 and Ext JS 4” ]

Quanto detto si traduce in codice nel seguente modo:

Listing 4: Esempio di associazioni tra modelli

Ext.define( "MyApp.model. Car" , {


extend: ’Ext . data .Model ’ ,
3 config: {
idProperty: ’ Id ’ ,
fields: [
{ name: ’ Id ’ },
{ name: ’brandName’ },
8 { name: ’type ’ },
{ name: ’ownerId ’ }
],
belongsTo: [{ model: ’MyApp.model.Owner’ , associationKey:
’ownerId ’ }],
hasOne: [{ model: ’MyApp.model. Engine ’ , associationKey: ’
engineId ’ }],
13 hasMany: [{ model: ’MyApp.model. Tyre ’ }]
}
});

Tutto ciò risulta di grande interesse perché permette di avvicinare


sempre di più il codice degli Ext.data.Model a quella che è la forma
del modello logico del database. Tuttavia dagli studi eseguiti emer-
ge una mancanza significativa negli automatismi offerti da Sencha.
Supponendo di creare uno store che si basa sulla memorizzazione di
istanze di tyre, vogliamo definire una vista a cui associarlo, e in cui
visualizzare direttamente non solo i dati dei pneumatici, ma anche i
5.5 un approfondimento sui proxy 45

dati contenuti nei modelli associati, che per l’appunto, si basano su


di un proxy di tipo JsonP. Per esempio vogliamo che ogni item della
lista visualizzi il nome del pneumatico, l’id della macchina associa-
ta e il nome del proprietario della macchina. Tutto ciò risulta essere
problematico.

il problema : analizzando in dettaglio il problema osserviamo quan- Problemi di


to segue. Quando viene eseguito il comando load dello store, assincronia durante
i load.
questi carica i dati dal server remoto usando le informazioni di
configurazione del proxy. In molti casi però il caricamento dei
dati è asincrono. Questo significa che i record dei pneumatici e
delle auto saranno istanziati senza conoscere le loro controparti
correlate. Così, quando abbiamo recuperare un record tyre dal-
lo store, questi non ha alcun riferimento al record (padre) auto,
che vorremo utilizzare nel componente List. L’unico modo per
farlo è quello di caricare l’intera struttura dati dei proprietari
(owner), compresi i figli di car e di tyre, in un singolo passag-
gio e utilizzando una struttura dati “ibrida”. In pratica questo
metodo di caricamento dei dati è ingombrante e per lo più non
supportato dalle tipiche backend’s API.

la soluzione :una soluzione al problema è stata trovata da due Modelli


sviluppatori: Rob Boerman e Aaron Smith [32, “Using Model As- “intelligenti”.
sociations in Sencha Touch 2 and Ext JS 4” ]. Essa consiste nel ride-
finire un modello “base” che provvede all’inizializzazione delle
associazioni (agli altri modelli), quando una componente (per
esempio una lista) necessita dei dati. Ciò si traduce nell’istruire
il modello su come rintracciare i dati associati.
Osservando che uno dei metodi principali per ottenere dati a
partire da uno store è il metodo getData(), gli sviluppatori so-
pramenzionati hanno optato per un override del metodo stesso,
impostando una logica che contenesse le informazioni su come
ottenere i dati associati. Quindi ogni modello del sistema sarà
creato come estensione di questo modello base.

Prendendo in considerazione altre soluzioni, si osserva la presenza


di un’alternativa più facile da pensare ma decisamente più onerosa
in termini di tempo di elaborazione. Tale è possibilità di definire ad
hoc delle richieste AJAX al server per ottenere tutti i dati necessari.

5.5 un approfondimento sui proxy

5.5.1 Gli store e le loro funzionalità

Come già detto nelle prime pagine, gli store di Sencha si appoggiano
a degli oggetti denominati proxy. Un proxy definisce la sorgente fisica
in cui sono (e saranno) memorizzati i dati a cui attingerà lo store, e
46 best practice

in cui saranno salvati i dati aggiunti (o modificati) sullo store. In un


certo senso possiamo pensare agli store come a delle interfacce per
I metodi principali la gestione dei dati memorizzati nella sorgente definita dal proxy. Lo
di Ext.data.Store. store fornisce metodi utili allo scopo, tra cui i più usati:
• add(record): usato per inserire un record nello store;

• remove(record) e removeAt(recordIndex): usato per rimuove-


re un determinato record. Con il primo metodo si rimuove il
metodo avente come campi dati, valori identici a quelli del re-
cord passato come parametro. Con il secondo metodo invece, si
rimuove il record di posizione recordIndex;

• get(fieldName, fieldValue) e getAt(recordIndex): usati per otte-


nere dei record ben definiti. Con il primo metodo si ottengono i
record aventi come valore, associato al campo fieldName, quel-
lo specificato da fieldValue. Con il secondo metodo invece si
ottiene il record presente di posizione recordIndex.
Si voglia osservare però che le operazioni che attuano una modifica
dei dati “a cui punta” lo store, non avranno effetto fintanto che non si
esegue un operazione di sincronizzazione dello store stesso. Il meto-
Gli store devono do sync() creato per lo scopo, si occupa di modificare la sorgente dei
essere sincronizzati. record eseguendo le operazioni effettuate sullo store a partire dal suo
ultimo sync(), o nel caso non ve ne siano stati durante l’esecuzione
dell’app, a partire dal load dello store.
Le operazioni eseguibili sullo store sono le medesime indifferente-
mente dalla tipologia del proxy sottostante. Il vantaggio è evidente, e
si bassa sul sistema di estensioni con le quasi sono progettate le com-
ponenti Sencha. Infatti uno store è in grado di operare con ogni ogget-
to la cui classe di appartenenza erediti direttamente o indirettamente
dalla classe Ext.data.proxy.Proxy. Questo comporta anche la possibili-
tà per lo sviluppatore di definire a proprio vantaggio un proxy, senza
preoccuparsi di definire uno store apposito per interagire con que-
sti. L’unica precondizione al corretto funzionamento della struttura,
è che il proxy sia definito correttamente.

5.5.2 Tipologie di proxy a confronto

I proxy sono definiti a partire dalla classe Ext.data.proxy.Proxy. Que-


sta presenta due sottoclassi, che definiscono a loro volta le due tipo-
I proxy possono logie di proxy di più alto livello:
essere suddivisi in
due categorie. • Ext.data.proxy.Client: è un proxy con sorgente dei dati locale.
Per utilizzare al meglio il framework (e stando ai consigli ripor-
tati nella reference guide) si consiglia di far estendere tale clas-
se da tutti i proxy definiti dallo sviluppatore, e che si basano
su di un archiviazione client-side. Infatti Ext.data.proxy.Client è
superclasse dei già menzionati WebStorage proxy.
5.5 un approfondimento sui proxy 47

• Ext.data.proxy.Server: analogamente alla classe precedente, la


presente definisce un proxy con sorgente dei dati remota (server-
side), ed è superclasse di Ajax proxy e JsonP proxy. Le osser-
vazioni sull’uso diretto fatte per Ext.data.proxy.Client valgono
anche per questa classe.

I proxy client-side saranno trattati più in dettaglio nel capitolo “si-


stemi di archiviazione dati”. Ora invece darò una trattazione
più approfondita dei proxy server-side.

5.5.3 Server-side Proxy

I proxy server-side presentano delle caratteristiche comuni: Caratteristiche dei


proxy server-side.
• url: ogni proxy necessità di conoscere l’url a cui dovrà inoltrare
le richieste per il prelievo e l’aggiornamento dei dati;

• reader: è un oggetto che definisce come devono essere interpre-


tate le risposte del server. Per esempio il JSON reader stabilisce
che la risposta del server sarà caratterizzata da un stringa JSON.
Quando istanziamo un proxy server-side, il costruttore passa il
nome del model (usato dal proxy) al reader. Questi userà il mo-
dello associato per verificare se la stringa JSON ritornata dal
server rispetta il formato dei dati attesi. Qualora si voglia abili-
tare il reader all’accettazione di dati non conformi alla struttura
di un model prestabilito, ma comunque aventi una formattazio-
ne nota, è possibile dichiarare tale formattazione nell’attributo
tootProperty.

Date queste informazioni preliminari, andiamo a vedere più da


vicino le tipologie di proxy offerte da Sencha: Tipologie di proxy
server-side.
ext.data.proxy.ajax : è uno dei proxy più usati e permette di ot-
tenere dati da una fonte remota (da un server) attraverso delle
richieste di tipo AJAX. L’inizializzazione di un proxy AJAX ri-
chiede da parte dello sviluppatore, di conoscere l’url a cui si
dovranno inoltrare le richieste. Di default viene creato con un
reader di tipo JSON abilitato ad accettare stringhe aventi il for-
mato specificato dal model designato durante l’inizializzazione.
Di default l’AJAX proxy, in risposta ad un’operazione di lettu-
ra, inoltra una richiesta di tipo GET. Invece per quanto riguarda
le operazioni di update dei dati, usa una richiesta di tipo PO-
ST. L’unica limitazione dell’AJAX proxy, è l’incapacità di otte-
nere dati archiviati al di fuori del dominio corrente, per via
di una politica di sicurezza del browser. Per superare questa
limitazione è stato introdotto il proxy JsonP.

ext.data.proxy.jsonp :Come accennato in precedenza, permette


di ottenere dati archiviati anche al di fuori del dominio in cui
48 best practice

è eseguita l’applicazione. Per fare ciò, il proxy inietta uno tag


<script> nel DOM quando di solito verrebbe usata una richie-
sta AJAX. Riportando l’esempio fatto nella reference guide, se
si desidera caricare dei dati presenti all’indirizzo
http://domainB.com/users, il tag script che verrebbe ad essere
iniettato, sarà simile a:

<script src="http://domainB.com/users?callback=
someCallback"></script>

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’ );
//Sollevo l’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 tracciare i 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 risolvere l’evento. Nel caso, si
tratta di istruzioni per creare una nuova
nota vuota, ed effettuare uno shift di
navigazione, alla view contenente l’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
mutua esclusione.
come handler associato una funzione di download che:

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
scrolling.
sto problema in diversi casi. Ecco alcuni consigli utili per risolvere il
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.
T E S TA R E U N ’ A P P L I C A Z I O N E S E N C H A
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 Douglas Crockford 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/l i n t r o l l e r/


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 unit test

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 modelli e store necessari per il testing
//Per esempio:
models: [ ’Note ’ , ’Author ’ ],
5 stores: [ ’Notes ’ ],

requires:
[
//elenco delle classi richieste per l’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

<html>
2 <head>
<meta charset= "UTF−8" >
<!-- i commenti indicano cosa inserire nelle
varie parti. I dati non commentati sono
lasciati per esempio-->
<title>NotesApp unit test - Jasmine</title>
<!-- Jasmine css file: carica il css di Jasmine
-->
7 <link rel= " stylesheet " type= " text/css " href= "app−
test/lib/jasmine−1.3.1/jasmine . css " >
<!-- <x-bootstrap> inseirisci qui la libreria
sencha-->
<script src= " lib/ST2/sencha−touch−all−debug. j s "
></script>
<!-- Jasmine js files -->
<script type= " text/javascript " src= "app−test/lib/
jasmine−1.3.1/jasmine . j s " ></script>
12 <script type= " text/javascript " src= "app−test/lib/
jasmine−1.3.1/jasmine−html . j s " ></script>
<!-- App css files -->
66 testare un’applicazione sencha

<link rel= " stylesheet " href= " ./ lib/ST2/resources/


css/sencha−touch . css " type= " text/css " >
<link rel= " stylesheet " href= " ./resources/css/app.
css " type= " text/css " >
<!-- application source files -->
17 <script src= "app−test . j s " ></script>
<!-- / application source files: inserisci qui
gli spec per il testing delle singole
componenti -->
<script type= " text/javascript " src= "app−test/spec
/IndexIDStoreSpec . j s " ></script>
<script type= " text/javascript " src= "app−test/spec
/IndexIDStoreFactorySpec . j s " ></script>
<script type= " text/javascript " src= "app−test/spec
/DownloadStoreFactorySpec . j s " ></script>
22 <script type= " text/javascript " src= "app−test/spec
/CommitStoreFactorySpec . j s " ></script>
<script type= " text/javascript " src= "app−test/spec
/AddCommitSpec. j s " ></script>
<script type= " text/javascript " src= "app−test/spec
/UpdateCommitSpec. j s " ></script>
<script type= " text/javascript " src= "app−test/spec
/DeleteCommitSpec . j s " ></script>
<script type= " text/javascript " src= "app−test/spec
/SyncStoreSpec . j s " ></script>
27 <script type= " text/javascript " src= "app−test/spec
/SyncManagerSpec . j s " ></script>
</head>
<body></body>
</html>

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 per i 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 ui test

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” ].
S I S T E M I D I A R C H I V I A Z I O N E D AT I
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
memorizzazione
sto non si basa solo sul sito remoto (l’URL di navigazione) ma anche
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
memorizzazione
quel record nel database. Gli indici sono auto-incrementanti e nella
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
utilizzato a causa di
al file cordova_plugins.js. Uno studio ulteriore ha evidenziato che la
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.
P R O T O T I PA Z I O N E
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
predisposte le view
le singole viste1 e successivamente caricate nel viewport. Si os-
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 });
C O N S I D E R A Z I O N I S U I F R A M E W O R K U S AT I
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.
ANALISI DEL PROBLEMA
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: UC1.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: UC2.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: UC2.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: UC2.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: UC2.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: UC2.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);
P R O G E T TA Z I O N E
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
gestione del
array, il nome di tutti i SyncStore1 presenti nell’applicazione. L’ordi-
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 è presto 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
pattern Observer.
proxy provoca l’aggiornamento automatico di tutti gli store che rac-
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


A N A L I S I D E L P R O D O T T O U LT I M O
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
cui e’ 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: elimino i 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 con i nuovi nomi
del modello e 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 creazione e 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 con i nuovi nomi
del modello e 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 creazione e 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 che i 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 download e 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 inviare i 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 restituendo 0 --> fallimento
if(Ext.getStore(this.getCommitStore()).getCount()
== 0)
213 {
return 0;
}

//assenza di connettivita’. Il metodo termina


restituendo 0 --> 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 testing o 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 per l’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 tutti i
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
}
//che l’invio abbia successo o meno, il
download viene sempre riabilitato, ma
solo in risposta alla risposta del
server, o inseguito allo scadere del
timeout (condizione che provoca l’
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 per l’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 che e’ stato aggiunto Notes, lo
store caricato all’inizio

38 //creazione ed avvio del viewport


Ext.Viewport.add([notesList,noteEditor,noteAuthor
]);
}
});
V E R I F I C A E VA L I D A Z I O N E
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
M O D U L E PAT T E R N
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
dell’ information
proprietà e dei metodi all’interno di un oggetto. Linguaggi come Java
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

<html>
<head>
4 </head>
<body>

<script type= " text/javascript " >

9 //definizione di un oggetto rappresentante una persona


var MiaPersona = function(nome, eta)
{
//qui vengono definite le variabili e i metodi privati
var private = {
14 nome : nome,
eta : eta
}

//qui vengono definite le variabili e i metodi pubblici


19 var public = function()
{

var publicInit =
{
24 getName: function()
{
return private.nome;
},

29 getEta: function()

159
160 module pattern

{
return private.eta;
},

34 setName: function(newName)
{
private.nome = newName;
},

39 printName: function()
{
alert(private.nome);
}
}
44
return publicInit;
}();

return public;
49 }

//esempio di utilizzo dell’oggetto Mia Persona


var Andrea = MiaPersona( "Andrea" , 22);
Andrea.printName();
54 //alert(Andrea.private.nome); ERRORE - questo metodo non e’
visibile da questo contesto
Andrea.setName( "Andrea Rizzi " );//OK
Andrea.printName();//OK

</script>
59
</body>
</html>
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” ]
TEST SUL WEBSQL
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 <html>
<head>
<script type=’text/javascript’>

var db = window.openDatabase(’mydb’, ’1.0’, ’my first


database’, 1);
6
console.log(’dbCreato’);

db.transaction(function(tx)
{
11 tx.executeSql(’CREATE TABLE test (id unique, text
)’);

console.log(’tabella test creata’);


console.log(’------------------’);

16 for (i=0; i<7000; i++)


{
tx.executeSql(’INSERT INTO test (id, text
) VALUES (’+i+’, "Lorem ipsum dolor
s i t amet, consectetur adipiscing e l i t
. Ut nec nunc nisl . In eget est et
arcu pharetra vulputate . Cras nunc
e l i t , volutpat at molestie eu,
fermentum et massa. Praesent ac v e li t
id lorem malesuada pretium at quis
ipsum. Sed ut nibh non erat
adipiscing commodo tristique eu ve l it
. Pellentesque u l t r i c i e s interdum
quam et vulputate . Cras sodales
viverra turpis , eget venenatis est
egestas eu . Vestibulum tellus diam,
f r i n g i l l a sed semper quis , tincidunt
ut nibh . Phasellus id scelerisque leo
. Fusce ac ante non augue imperdiet
ullamcorper . " )’);
console.log(’inserimento num’ + i);
}
21
console.log(’Inserimento terminato’);
});

</script>
26 </head>
<body>
</body>
</html>
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
limitazione dei
nell’errato modo di riferirsi al WebSQL. Molti sviluppatori tendono a
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.
LE BASI DI JASMINE
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
testing di
tempo fino a diventare uno dei framework BDD più usati per gli
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
expect() e dal tipo di
funzioni. Tali valori possono essere di diverso tipo (nell’esempio sot-
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
essere utili per
spec rispettivamente, all’avio e al termine della spec stessa. Ecco un
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( " i s just a function , so i t 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( " i s just a function , so i t 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 i t s number of c a l l s " , function() {


expect(foo.setBar.calls.length).toEqual(2);
});
25
it( " tracks a l l the arguments of i t s c a l l s " , function() {
expect(foo.setBar).toHaveBeenCalledWith(123);
expect(foo.setBar).toHaveBeenCalledWith(456, ’another param’)
;
});
30
it( "allows access to the most recent c a l l " , function() {
expect(foo.setBar.mostRecentCall.args[0]).toEqual(456);
});

35 it( "allows access to other c al l s " , function() {


expect(foo.setBar.calls[0].args[0]).toEqual(123);
});

it( " stops a l l 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 a l l the arguments of i t s c a l l s " , 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 debugger, 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 Software Engineering”


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/
INDICE ANALITICO

—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

Potrebbero piacerti anche