In questo articolo ti descrivo l'anatomia di una node.js webapp realizzata con mongoDB, node.js e backbone.js.
Per far ciò userò come riferimento la webapp www.darkroomlocator.com che ho da poco rilasciato e che ho realizzato proprio con queste tecnologie.
L'articolo è molto lungo e molto tecnico, per cui se non hai tempo di leggerlo tutto puoi crearti un pdf, scaricarlo e leggerlo con calma in seguito ciccando sull'icona rossa “pdf“.
Se invece vuoi leggerlo subito di seguito trovi il tutorial completo, puoi aiutarti nella lettura anche con il sommario di lato.
Vuoi ulteriori informazioni su come implementare questa architettura? Allora contattami.
I contenuti dell'articolo
1. Architettura
L’architettura di una webapp basata su mongoDB, node.js e backbone.js è articolata secondo lo schema riportato in figura:
Tale architettura prevede :
- una componente dati che utilizza mongoDB come data base non relazione
- una componente server realizzata in node.js
- una componente client realizzata con backbone.js
caratterizzate tutte dall' usare javascript come (unico) linguaggio di programmazione.
La componente server svolge prevalentemente le seguenti cose:
- Si occupa di colloquiare con la base dati fornendo lo strato software di modellizzazione dei dati
- Espone le API (RESTful webservice) di comunicazione con la componente client (o le componenti client)
- Gestisce la SEO per le applicazioni ajax a pagina singola
- Gestisce una eventuale comunicazione real-time attraverso l’utilizzo delle WebSocket
La componente client è realizzata interamente in javascript con la tecnica della SPA application ossia della applicazione web a pagina singola.
I framework di costruzione della stessa sono :
- backbone.js come framework applicativo
- twitter bootstrap come framework grafico
- altre librerie javascript specifiche per alcune funzionalità
Una SPA application o SPAs application o applicazione a pagina singola (single page application) è una webapp interamente realizzata in javascript la cui logica applicativa è interamente implementata lato client.
Tutta l’app viene scaricata durante la prima connessione con il server dopodichè sia la logica che il routing, ossia la navigazione web, è gestita lato client senza effettuare continue call http con il server (request-response).
L’unica interfaccia di comunicazione con il server è rappresentata dalle chiamate asincrone alle API Rest (AJAX) e/o dalla componente WebSocket di comunicazione in real-time (socket.io).
Tale architettura presenta numerosi vantaggi quali:
- Effettiva separazione della componente dati, applicativa e grafica
- Semplice portabilità della SPAs app sui vari dispositivi mobili (smartphone/tablet/desktop) attraverso framework quali phonegap/cordova
- Elevata scalabilità dell’applicazione
- Medesimo linguaggio di programmazione per tutta la filiera applicativa (full-stack programming language)
Nel tutorial farò riferimento, ove possibile, all’applicazione www.darkroomlocator.com realizzata con tale architettura, ad esclusione della comunicazione via WebSocket e della componente mobile (phonegap) che non è stata implementata.
Vediamo nel dettaglio le varie componenti.
1.1 componente dati
Per la componente dati ho utilizzato MongoDB sulla piattaforma cloud mongohq.com (DB as a Service)
generalità su mongoDB
MongoDB è un sistema gestionale di basi di dati non relazionale, orientato ai documenti, di tipo NoSQL.
Il data base si caratterizza per essere altamente performante (embedded data models, indici e query veloci), estremamente affidabile (failover automatico e ridondanza dati) e facilmente scalabile anche orizzontalmente (sharding automatico, replica sets).
Il linguaggio utilizzato per la gestione dei dati è JavaScript, del quale sfrutta in particolare la notazione BSON (JSON).
MongoDB è un gestore di database schemaless, il che significa che i dati, anche all'interno di una stessa tabella, possono essere strutturati in qualsiasi modo e non devono rispettare alcuna regola. Per questa ragione rientra nella famiglia NoSQL e utilizza JavaScript come linguaggio di interrogazione.
I documenti (analogo delle righe nei db relazionali) vengono archiviati in collection che hanno un set comune di indici (analogo delle tabelle nei db relazionali) ; pertanto le collection sono insiemi di documenti ed un insieme di documenti forma un data base.
schema dati
Lo schema dei dati di darkroomlocator è molto semplice, in quanto è composto di solo tre Collections (tabelle) :
- reports … collection delle segnalazioni
- types … collection delle tipologie di segnalazioni (camera oscura privata, fotografo, … )
- users … collection degli utenti
la collection reports è rappresentata secondo il seguente schema json:
la collection types è rappresentata secondo il seguente schema json:
la collection users è rappresentata secondo il seguente schema json:
oggetti geometrici
Importante è il campo “loc” della collection reports, che rappresenta un oggetto geometrico (Punto) utilizzato per memorizzare la posizione della segnalazione in termini di latitudine e longitudine.
L’utilizzo di questo oggetto geometrico permette poi di effettuare query spaziali complesse.
mongoDB supporta i seguenti oggetti geometrici
- Punto (Point)
- Spezzata (LineString)
- Poligono (Polygon)
memorizzati come oggetti “GeoJson” il cui sistema di riferimento è il WGS84
Le query spaziali disponibili sono di
- Prossimità
- Inclusione
- Intersezione
grazie agli ’indici spaziali “2d” e “2dsphere” che mongoDB offre.
Maggiori info sugli oggetti geometrici sono reperibili all’indirizzo:
http://docs.mongodb.org/manual/applications/geospatial-indexes/
1.2 componente server
Per la componente server ho utilizzato node.js in hosting su piattaforma cloud Heroku.com (Platform as a Service)
La componente server di darkroom locator svolge prevalentemente le seguenti cose:
- Si occupa di colloquiare con la base dati fornendo lo strato software di modellizzazione dei dati
- Espone le API (RESTful webservice) di comunicazione con la (le) componente client
- Gestisce la SEO per le applicazioni ajax a pagina singola
Vediamo prima alcune generalità su node.js poi andremo nel dettaglio delle funzionalità appena descritte.
generalità su node.js
Node.js è una piattaforma software basata sul runtime JavaScript di Chrome (V8 JavaScript Engine) particolarmente adatta alla realizzazione di applicazioni di rete scalabili e performanti.
Node.js utilizza un modello di I/O orientato agli eventi (event-driven) pertanto non bloccante, che lo rende leggero ed efficiente, perfetto per applicazioni real-time.
Node.js gestisce nativamente una libreria server HTTP, rendendo possibile l'esecuzione di un server web senza l'utilizzo di software esterni, come Apache o Lighttpd, e consentendo quindi un maggiore controllo sul funzionamento del web server stesso.
node package manager (npm)
Uno dei punti di forza di node.js è la possibilità di utilizzare moduli aggiuntivi o node package manager (npm), che ne estendono le funzionalità e le potenzialità.
Esistono due tipologie di npm, moduli nativi e moduli sviluppati da terze parti e disponibili nella directory pubblica :
I pacchetti nativi sono inclusi nell’installazione base di node (Es. http) e sono utilizzabili nell’applicazione semplicemente richiamandone il contenuto :
var http = require("http");
I pacchetti di terze parti (Es. express) invece devono prima essere installati utilizzando il comando :
npm install [nome pacchetto]
una volta installato il modulo può essere utilizzato nella nostra applicazione allo stesso modo dei moduli di base.
I principali npm utilizzati per darkroomlocator sono:
express … uno dei principali web application framework per node.js
mongodb … modulo per la gestione della connection con mongoDB
mongoose … modulo per modellizzazione dei dati
phantomjs … modulo per la cattura di pagine web, utilizzato per tecniche SEO
bcrypt … modulo per la criptazione delle password
ejs … modulo per gestione dei template per pagine web
email-templates … modulo per gestione di template per email
moment … modulo per la gestione delle date
node-uuid … modulo per la gestione di UUIDS RFC4122
postmark … modulo per la gestione dell’invio mail
modellizzazione dei dati
Come accennato sopra la componente server ha, tra le sue peculiarità, quella di fornire la componente applicativa dedicata al colloquio con la base dati mongoDB.
Questa funzionalità è stata realizzata attraverso la modellizzazione delle collections descritte sopra per il data base :
- reports
- types
- users
modellizate nell’app node.js mediante l’ausilio del npm mongoose
mongoose consente di modellizzare il database nell’app node.js fornendo un’interfaccia per la validazione e tipizzazione dei dati, per la costruzione di query e più in generale per consentire la gestione della logica di business dell’applicazione senza accedere direttamente al database mongoDB.
La modellizzazione delle collection sopra descritte è realizzata attraverso il seguente codice javascript
/** user model **/
var userSchema = mongoose.Schema({
first_name : String,
last_name : String,
username : { type: String, required: true, unique: true },
password : { type: String, required: true },
email : { type: String, unique: true },
registration_date : { type: Date, default: moment() },
auth : {
authkey : String,
ipaddress : String,
login_date : Date,
activate_date : Date
},
verified : { type: Boolean, default: false }
});
/** report type model **/
var typeSchema = mongoose.Schema({
value : Number,
description_en : String,
description_it : String,
description_es : String,
description_fr : String,
description_de : String,
sort : Number
});
/** report model **/
var reportSchema = mongoose.Schema({
username_id : { type: mongoose.Schema.Types.ObjectId, required: true, ref:'User'},
username : { type: String, ref:'User'},
report_date : { type: Date, required: true, default: moment()},
type_id : { type: mongoose.Schema.Types.ObjectId, required: true, ref:'Type' },
description : String,
note : String,
keywords : [String],
contact_email : String,
website : String,
formatted_address : String,
country : String,
country_short : String,
region : String,
province : String,
postal_code : String,
lng : Number,
lat : Number,
loc: {
type: {
type: String
},
coordinates: []
}
});
mongoDB in quanto database noSql non supporta nativamente le foreign keys (integrità referenziale)
Tuttavia l’integrità del dato è garantita dalla modellizzazione stessa del data base, come indicato sopra, attraverso l’ausilio delle regole di validazione fornite da mongoose.js
Si faccia riferimento, ad esempio, al campo username della collection report:
username : { type: String, ref:'User'}
come si vede il campo username si riferisce (ref:’User’) alla collection User, pertanto non sarà possibile inserire una segnalazione riferendola ad un utente che non esiste.
In questo modo siamo riusciti a creare delle foreign keys “applicative” che ci permettono di validare e referenziare il contenuto dei documenti inseriti.
RESTful webservice e api
La seconda funzionalità implementata nella componente server è quella relativa
al colloquio con la componente client (o le componenti client).
Tale colloquio è reso possibile attraverso la pubblicazione di API REST (RESTful webservice) che definiscono quanti e quali servizi darkroom locator espone sia pubblicamente che privatamente ai client.
Per maggiori dettagli sull’architettura REST si faccia riferimento alla seguente documentazione:
http://it.wikipedia.org/wiki/Representational_State_Transfer
Per far ciò ho utilizzato l’npm express che fornisce un framework semplice ed intuitivo (ma anche estremamente potente) per la creazione di API REST e più in generale per la creazione di web application in node.js.
Di seguito le api implementate
risorsa | metodo | uri | tipo | descrizione | body | lang |
User | get | /api/users | privato | Ritorna tutti gli utenti | no | si |
User | get | /api/user/id/:id | privato | Ritorna l’utente per l’id impostato | no | si |
User | get | /api/user/username/:username | privato | Ritorna l’utente per lo username impostato | no | si |
User | post | /api/login | pubblico | Effettua il login e ritorna il token di autenticazione | si | si |
User | post | /api/user | pubblico | Effettua la registrazione dell’utente e ritorna il token di autenticazione | si | si |
User | put | /api/user/id/:id | privato | Aggiorna le informazioni dell’utente per l’id impostato | si | si |
User | put | /api/user/activate/id/:id/key/:key | pubblico | Attiva l’utente registrato con id e chiave di attivazione | no | si |
User | put | /api/user/resetpwd/email/:email | pubblico | Effettua il reset password per l’utente con la mail impostata | no | si |
User | delete | /api/user/id/:id | privato | Cancella l’utente per l’id impostato | no | si |
Type | get | /api/types | pubblico | Ritorna tutti i tipi segnalazione | no | no |
Type | get | /api/type/id/:id | pubblico | Ritorna il tipo segnalazione per l’id impostato | no | no |
Report | get | /api/reports | pubblico | Ritorna tutte le segnalazioni | no | no |
Report | get | /api/report/id/:id | pubblico | Ritorna la segnalazione per l’id impostato | no | no |
Report | get | /api/reports/username/:username | pubblico | Ritorna le segnalazioni dello username impostato | no | no |
Report | get | /api/reports/geo/:lat/:lng/:km | pubblico | Ritorna le segnalazioni nell’intorno del punto e del raggio impostato | no | no |
Report | get | /api/reports/text/:text | pubblico | Ritorna le segnalazioni per il testo di ricerca impostato | no | no |
Report | get | /api/reports/params/:lat/:lng/:km/:text/:id | pubblico | Ritorna le segnalazioni nell’intorno del punto e del raggio impostato, per il testo di ricerca impostato e per tipo segnalazione | no | no |
Report | post | /api/report | privato | Effettua la registrazione della segnalazione | si | no |
Report | put | /api/report/id/:id | privato | Aggiorna le informazioni della segnalazione per l’id impostato | si | no |
Report | delete | /api/report/id/:id | privato | Cancella la segnalazione per l’id impostato | no | no |
Image | get | /api/images/dir/:dir | pubblico | Ritorna le immagini della segnalazione impostata | no | no |
Image | post | /api/image | privato | Carica l’immagine | si | no |
Image | delete | /api/image/dir/:dir/file/:file | privato | Cancella l’immagine per segnalazione e nome file impostati | no | no |
Image | delete | /api/images/dir/:dir | privato | Cancella tutte le immagini per la segnalazione impostata | no | no |
Tutti i metodo privati per essere invocati necessitano di un token di autenticazione da inserire nell’header della call HTTP, il token di autenticazione lo si ottiene attraverso i due metodi pubblici di accesso (login e registrazione) e prevede una chiave privata e lo username di riferimento.
La chiave privata viene rigenerata ad ogni login e/o scade dopo 24 ore.
Per tutte le chiamate verso la risorsa User, siano essere pubbliche o private, è necessario impostare la lingua di riferimento (“it”, “en”, “de”, “fr”, “es”)
Una tipica call via curl per un metodo privato è:
curl -i -X GET -H 'authkey: 98509d60-e49b-11e2-a13d-2b6c6a52a6bf' -H 'username: etrusco' -H 'lang: it' http://www.darkroomlocator.com/api/user/id/511a3156f58108696e000001
Mentre una tipica call per un metodo pubblico è:
curl -i -X GET http://www.darkroomlocator.com/api/reports
Per i metodi il cui campo body risulta obbligatorio è necessario includere nella call http la risorsa di riferimento nel campo body : -d “{ … }” (ovviamente in formato json)
Ad esempio per inserire una nuova segnalazione è possibile fare la seguente chiamata:
curl -i -X POST -H 'Content-Type: application/json' -H 'authkey: 9e5cea20-ea0d-11e2-8ceb-850a018479f4' -H 'lang: it' -d '{"username":"etrusco","type_id":"51da8a4af942487b04000087","formatted_address":"Los Angeles, California 90025, Stati Uniti","country":"Stati Uniti","country_short":"US","region":"California","province":"Contea di Los Angeles","postal_code":"90025","lng":-118.4484367,"lat":34.0448583,"loc":{"type":"Point","coordinates":[-118.4484367,34.0448583]},"description":"9","note":"9","website":"https://www.pensando.it"}' http://www.darkroomlocator.com/api/report
Il “Content-Type” deve essere sempre nel formato “application/json”
SEO e phantom.js
L’ultima funzionalità implementata nella componente server è quella relativa all’ottimizzazione della SEO per le applicazioni ajax a pagina singola (SPAs application)
Questa funzionalità è stata realizzata attraverso l’utilizzo del npm phantomjs che consente alla node application di invocare il processo phantom.js, esterno al node framework.
Per utilizzare questa funzionalità è pertanto necessario utilizzare un service provider che abbia preconfigurato phantom.js in maniera nativa (Es. Heroku, Modulus.io).
Facciamo ora un passo indietro e cerchiamo di capire perché è necessario phantom.js per la gestione della SEO in applicazioni ajax a pagina singola ovvero per applicazioni web interamente realizzate in javascript che non hanno una componente server di render del codice HTML ad ogni call di un uri ma che gestiscono tutta la logica dell’applicazione lato client (per maggiori info si faccia riferimento al paragrafo successivo).
Questo tipo di applicazioni web, non avendo un render della componente HTML lato server ad ogni call, gestiscono tutta la logica applicativa lato client, compreso il routing ossia la gestione delle rotte e degli indirizzi (url) di riferimento.
Dove sta il problema per questo tipo di applicazioni in relazione alla gestione della SEO?
Il problema sta nel fatto che google indicizza i website alla perfezione, peccato però che tralasci il codice javascript utilizzando solo il codice HTML.
Nelle applicazioni a pagina singola il codice HTML non è renderizzato dal server ad ogni call HTTP ma viene “generato” lato client attraverso il javascript stesso (o meglio con la prima get HTTP viene renderizzata sul client tutta la webapp che comprende l’index, le librerie javascript ed i template utilizzati per “costruire” la webapp stessa)
Il risultato è che Google non è in grado di indicizzare applicazioni di questo tipo perché basate interamente sul javascript. Semplice ma terribile per chi sviluppa questa tipologia di applicazioni.
Così Google è venuta incontro alla community di developer mondiale stabilendo un formato da utilizzare nella composizione della url dell’applicazione per far comprendere a google stesso ed ai suoi crawler che l’applicazione in oggetto è di tipo SPAs.
Pertanto una classica url :
http://www.darkroomlocator.com/#it/mapdashboard
Deve essere trasformata in :
http://www.darkroomlocator.com/#!it/mapdashboard
Attraverso l’aggiunta del punto esclamativo (!) dopo il simbolo # che, in questo tipo di applicazioni, sta ad indicare l’inizio della parte variabile della url stessa (rotte e parametri).
I crawler di Google, trovando la coppia di caratteri #! effettueranno una sostituzione temporanea degli stessi generando una nuova url :
http://www.darkroomlocator.com/?_escaped_fragment_it/mapdashboard
Dove al posto di #! è stata sostituita la stringa ?_escaped_fragment_
A questo punto il crawler effettuerà una get http al nostro sito utilizzando la nuova url appena descritta.
Applicativamente quindi dobbiamo predisporre la componente server dell’applicazione affinché sia in grado di capire se la call http è canonica (#!) oppure proviene da un crawler (?_escaped_fragment_).
Nel primo caso dobbiamo fare il render della nostra index come facciamo normalmente, nel secondo caso invece dobbiamo invocare il processo phantom.js, renderizzare applicativamente la singola pagina web e restituirla corretta al crawler ossia fornendo l’HTML correttamente interpretato ( HTML snapshot).
Per far ciò, con node.js ed un service provider abilitato all’utilizzo di phantom.js, è necessario gestire i due casi con un codice simile al seguente:
/** phantom **/
var phantomjs = require('phantomjs');
var path = require('path');
var childProcess = require('child_process');
if(typeof(req.query._escaped_fragment_) !== "undefined") {
var query_str = req.query._escaped_fragment_;
var lang = query_str.substring(0,2);
/* phantom call */
var binPath = phantomjs.path;
var childArgs = [
path.join(__dirname, 'phantom-script.js'), lang, query_str
];
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
console.log('done phantomjs!');
console.log('stderr: ' + stderr);
console.log('stdout: ' + stdout);
res.send(stdout);
});
}
else
res.render('app/index');
Come si vede se la query string non contiene la query _escaped_fragment_ viene fatto il normale render dell’applicazione :
res.render('app/index');
Mentre in caso contrario viene gestita la call al processo phantom.js esterno a node.
Lo script phantom.js vero e proprio, poi, dovrà fare una cosa del tipo:
var system = require('system');
var page = require('webpage').create();
var url = 'http://www.darkroomlocator.com/#!' + system.args[2];
/** get request page **/
page.open(url, function (status) {
if (status !== 'success') {
console.log('Unable to access network');
} else {
var p = page.evaluate(function () {
return document.getElementsByTagName('html')[0].innerHTML
});
console.log(p);
}
phantom.exit();
});
Lo script appena descritto ritorna l’intera pagina HTML alla node.js application che effettua cosi il render corretto:
res.send(stdout);
Ho testato altri modi per cercare di gestire correttamente la componente SEO di una webapp a pagina singola con componente server node.js, ma questa è non solo la più elegante ma anche l’unica valida e perfettamente funzionante.
WebSocket
Nel caso in cui la nostra webapp richieda una comunicazione “real-time” è possibile sfruttare le potenzialità di node.js in ambito “WebSocket” ossia attraverso il protocollo di comunicazione che va oltre il classico paradigma “Request” – “Response” tipico dell’HTTP.
Grazie alle WebSocket è possibile stabilire un canale di comunicazione TCP di tipo “full-duplex” (bidirezionale simultaneo) tra client e server attraverso il quale scambiare dati in tempo reale, insomma una vera e propria rivoluzione per il web.
Non è il caso di darkroom locator ma credo sia comunque opportuno dedicare un paragrafo a questa tecnologia.
Per maggiori info sulle websocket : http://it.wikipedia.org/wiki/WebSocket
Come detto node.js “sposa” alla perfezione questa tecnologia anzi è in grado di estenderne le funzionalità attraverso dei framework javascript specifici come ad esempio “socket.io”
socket.io estende ed amplia le funzionalità delle WebSocket in primis in termini di compatibilità con tutti i browser disponibili (fino ad IE 5.5).
Una tipica istanza di socket.io lato server:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
e la relativa istanza client
I principali metodi sono “emit” e “on” con i quali inviare e ricevere dati in tempo reale.
Una vera e propria rivoluzione “concettuale” per chi da sempre è stato abituato a lavorare sul classico paradigma “Request” – “Response” dell’HTTP.
1.3 componente client
La componente client è stata realizzata interamente in javascript con la tecnica della SPA application ossia della applicazione web a pagina singola.
I framework di costruzione della stessa sono stati :
- backbone.js come framework applicativo
- twitter bootstrap come framework grafico
- altre librerie javascript specifiche per alcune funzionalità
Facciamo prima una breve panoramica sulle principali caratteristiche delle applicazioni a pagina singola e poi vediamo nel dettaglio i framework utilizzati.
SPA, applicazioni a pagina singola
Una SPA application o SPAs application o applicazione a pagina singola (single page application) è una webapp interamente realizzata in javascript la cui logica applicativa è interamente implementata lato client.
Come dice il nome stesso una single page application gestisce tutto il codice (HTML, javascript e CSS) in una sola pagina web, solitamente definita “index” application, che effettua il load di tutte le risorse allo startup dell’applicazione stessa, rendendo la navigazione del website estremamente veloce e fluida.
La index page pertanto include tutte le librerie javascript e css che permettono di generare l’applicazione, sfruttando il concetto di “HTML templating” in sostituzione del più canonico “HTML paging”.
Sfruttando l’ HTML templating è possibile gestire lato client la componente grafica (GUI), renderla dinamica e soprattutto sganciarla completamente dalla componente applicativa, realizzando il paradigma delle view nell’ambito del design pattern mvc.
Sempre nell’ambito del design pattern mvc, con applicazioni ajax a pagina singola, il paradigma del “model” ossia della componente dati è realizzato sfruttando le potenzialità messe a disposizione da ajax stesso e dall’interazione con le API Rest realizzate lato server.
La componente “controller” è gestita sempre via javascript ed altro non è che la logica di business dell’applicazione che include anche il concetto di routing (navigazione, rotte, url).
Per realizzare applicazioni di questo tipo è buona pratica utilizzare uno dei tanti framework mvc disponibili in rete.
Nel caso di darkroom locator, come framework mvc, ho scelto ed utilizzato backbone.js.
backbone.js
Backbone.js è una libreria (framework) in grado di fornire al programmatore delle strutture standard per lo sviluppo dell’applicazione web.
Le strutture standard prevedono :
- Backbone.Collection (liste di modelli dati)
- Backbone.Model (modelli dati)
- Backbone.View (viste dell’applicazione)
- Backbone.Router (gestione centralizzata del routing ossia navigazione, indirizzi e rotte)
Inoltre con Backbone.js è possibile gestire :
- Backbone.Events (eventi personalizzati)
ed altre funzionalità quali ad esempio Backbone.history e Backbone.sync nonchè un sistema di templating.
Può essere eseguito sia lato server che lato client ed ha come unica dipendenza la libreria underscore.js
Il design pattern mv* lato client
Backbone.js rientra nella categoria delle librerie che implementano il design pattern MV*, ossia implementa Model (modelli e collezioni) e View (viste), ma non ha un vero e proprio componente Controller come accade per i numerosi framework mvc diponibili in rete.
Pertanto le funzionalità di business (controller) sono delegate alle View e soprattutto alla componente di routing utilizzata per definire centralmente rotte, indirizzi e navigazione della webapp.
twitter bootstrap GUI
Per quanto concerne la componente grafica dell’applicazione (GUI) ho utilizzato Twitter Bootstrap, molto probabilmente il framework per lo sviluppo della componente front-end più popolare ed utilizzato al mondo.
Bootstrap nasce come progetto interno a Twitter ma poi ne diventa indipendente; oggi è uno dei progetti di maggior successo su gitHub con ben 65.000 like e oltre 23.000 fork.
Boostrap permette di realizzare webapp mobile ready, responsive e graficamente pulite, semplici e fluide attraverso l’ausilio di un framework che è diventato “de-facto” uno standard.
Quando incluso nel progetto prevede la seguente struttura di file:
e può essere facilmente utilizzato attraverso un template HTML simile a questo
A questo punto è possibile strutturare la GUI della nostra webapp usando le classi e gli stili bootstrap.
Maggiori dettagli sul framework li trovate al sito ufficiale : http://getbootstrap.com/
altre librerie javascript
Per il progetto, oltre alle librerie appena descritte ovvero backbone e bootstrap, ho usato anche altre librerie per l’attivazione di specifiche funzionalità, quali:
jquery … la più famosa libreria javascript cross-browser per la manipolazione e la gestione delle webapp lato client (CSS, HTML, Ajax, …)
underscore … dipendenza necessaria di backbone, è una libreria che offre più di 80 funzioni per la manipolazione di Array, Oggetti e Collection.
backbone.localStorage … plugin per l’utilizzo del local storage via backbone (persistenza dei dati in locale via cookies).
https://github.com/jeromegn/Backbone.localStorage
oauth.io … libreria per la gestione della login attraverso un processo di autenticazione esterna che supporta più di 100 provider diversi (facebook, G+, twitter, … ) – funzionalità non ancora in linea.
jquery.validate – plugin jquery per la validazione lato client dei form html.
http://bassistance.de/jquery-plugins/jquery-plugin-validation/
crypto-js – libreria per l’utilizzo dell’algoritno md5 lato client (utile per la gestione di password, dei token di autorizzazione e come dipendenza per jquery.gravatar).
https://code.google.com/p/crypto-js/
jquery.gravatar – plugin jquery per l’utilizzo degli avatar via gravatar api.
https://github.com/zachleat/jQuery-Gravatar
maps.googleapis – libreria per l’utilizzo delle google maps api.
https://developers.google.com/maps/?hl=it
geocomplete – libreria per l’utilizzo delle funzionalità di autocomplete degli indirizzi via google maps.
http://ubilabs.github.io/geocomplete/
infobubble – libreria per la creazione di infobubble dinamici su mappe google.
http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobubble/examples/example.html/
animatescroll – libreria per la creazione di animazioni “scroll”.
http://plugins.compzets.com/animatescroll/
moment – libreria per la gestione delle date.
bootbox – libreria per la gestione dei popup con bootstrap.
dropzone – libreria per la gestione del caricamento immagini lato client.
responsiveslides – libreria per la gestione delle slides animate di immagini.
Da webapp ad app nativa
Nel caso in cui si voglia realizzare una app nativa per dispositivi mobili è necessario conoscere il linguaggio di programmazione supportato dal sistema operativo del dispositivo stesso.
Ogni sistema operativo di ogni dispositivo supporta un diverso linguaggio di programmazione, per cui realizzare una app nativa che giri contemporaneamente su Android , iOs e Windows Phone è possibile solo a patto che si conoscano Java, Objective-C e C#.
Tuttavia, come già accennato in precedenza, uno dei principali vantaggi della tecnologia appena descritta è la possibilità di “migrare” in maniera relativamente semplice una webapp a pagina singola in “app nativa” per uno o più dispositivi mobile, consentendo “de facto” la realizzazione di app multi-piattaforma sfruttando HTML5, CSS3 e javascript.
Il processo di “traduzione” è relativamente semplice attraverso framework specifici quali ad esempio phonegap, apache cordova e titanium.
Nel caso di phonegap, che conosco meglio, si ha a disposizione una libreria completa di funzionalità javascript che consentono di inglobare la nostra webapp nel framework e poi compilarla per il linguaggio nativo prescelto (java / Android, Objective-C / iOs, C# Windows Phone, …)
Si tratta quindi di un vero e proprio wrapper (contenitore) che ci permette di inglobare una webapp HTML5/CSS3/javascript in una app nativa senza particolari sforzi e conoscenze del linguaggio di programmazione target.
I sistemi operativi supportati da questi framework sono moltissimi, quali ad esempio Android, iOs, Windows Phone, Win 8, Amazon Fire OS, BlackBerry 10, Firefox OS, Ubuntu e Tizen.
Per maggiori info:
http://phonegap.com/
http://en.wikipedia.org/wiki/PhoneGap
2. sviluppo
Per gli sviluppi ho utilizzato il cloud IDE c9.io e come sistema di versioning git in cloud hosting su bitbucket.org
c9.io
c9.io è un IDE gratuito, cloud e di qualità per lo sviluppo collaborativo di applicazioni web in molti linguaggi di programmazione.
I linguaggi server side supportati sono: node.js, php, python, ruby, java e molti altri ancora.
Come detto è un cloudIDE ossia un ambiente di sviluppo fruibile attraverso il browser web, da qualsiasi postazione di lavoro e che quindi non richiede alcun tipo di installazione locale.
Molto comodo per una serie di motivi:
- non richiede installazione
- non richiede configurazioni e personalizzazioni
- ci permette di lavorare da qualsiasi postazione a prescindere dal sistema operativo (mac, lnx, win, …)
è gratuito nella versione standard che comprende:
- Un workspace privato
- Accesso completo da terminale e da shell
- Tre workspace FTP
- Illimitati Workspaces pubblici
- Illimitati collaboratori
e molto altro ancora.
git
Per il versioning del software di darkroom locator ho utilizzato git.
Git è un sistema software di controllo delle versioni distribuito, creato da Linus Torvalds nel 2005; è probabilmente il sistema più utilizzato in ambito open (ma non solo) e sicuramente uno dei più performanti e sicuri in circolazione.
I punti di forza di git sono :
- Forte supporto allo sviluppo non lineare
- Sviluppo distribuito
- I repository possono essere pubblicati facilmente tramite HTTP, FTP, ssh, rsync, o uno speciale protocollo git
- Gestione efficiente di grandi progetti
- Autenticazione crittografica della cronologia
- Salvaguardia dalla corruzione dei dati
- Altissime prestazioni
Esistono in rete molti provider cloud per l’archiviazione delle repository, i più famosi sono gitHub e bitbucket, ma anche Heroku offre una sua piattaforma git di versioning integrata.
La versione in esercizio di darkroom locator è gestita proprio con Heroku, in quanto questa sinergia mi permette di effettuare i deploy in modo veloce ed istantaneo, ne parlo in questo articolo:
come fare il deploy di un'app node.js da Heroku
Tuttavia ho rilasciato una versione del codice anche su gitHub, liberamente consultabile.
3. Sorgente
Come descritto sopra ho rilasciato tutto il codice sorgente in forma pubblica sulla mia repository git, per visionare il codice (sia client che server ) basta accedere al seguente link, troverai tutti i riferimenti al sorgente dell'applicazione
4. Riferimenti
data base
http://www.mongodb.org/
http://mongoosejs.com/
http://it.wikipedia.org/wiki/MongoDB
http://nicolaiarocci.com/mongodb/il-piccolo-libro-di-mongodb.pdf
server
http://nodejs.org/
https://npmjs.org/
http://expressjs.com/
http://socket.io/
http://it.wikipedia.org/wiki/WebSocket
http://phantomjs.org/
http://it.wikipedia.org/wiki/Representational_State_Transfer
https://developers.google.com/webmasters/ajax-crawling/docs/getting-started?hl=it
http://it.wikipedia.org/wiki/Git_(software)
client
http://backbonejs.org/
http://underscorejs.org/
http://getbootstrap.com/
http://phonegap.com/
http://en.wikipedia.org/wiki/PhoneGap
Platform as a service
https://www.mongohq.com/home
https://mongolab.com/welcome/
https://www.heroku.com/
https://www.nodejitsu.com/
https://modulus.io/
Che te ne pare di questa architettura software basata su javascript e node.js?
2 commenti
Pingback: Come scegliere il giusto framework javascript MVC?
Pingback: Come scegliere il giusto framework javascript MVC?