giovedì 15 settembre 2016

Una Web-app single-page full javascript (ExtJs,Node,Nginx)

Negli ultimi anni ho progettato diverse applicazioni web utilizzando diverse tecnologie e nel corso del tempo le architetture utilizzate si sono evolute fino ad arrivare ad una webapp full-stack in javascript, con l'utilizzo di ExtJs, Node.js e Nginx


Architettura multilayer


Nel 2006 , quando ho iniziato con le prime note sulla tecnologia Ajax l'architettura di una webapp 2.0 era relativamente semplice: si utilizzavano chiamate ajax all'interno di una webapp scritta in php, asp, jsp o uno dei linguaggi web che andavano per la maggiore. Nel corso del tempo li ho utilizzati tutti, o quasi, trovando piu' facile sviluppare in php rispetto ad asp o jsp.

Man mano cominciavano a diventare noti i primi framework ajax: prototype, jquery,mootools che rendevano disponibili un set di librerie javascript che facilitavano lo sviluppo della logica di gestione dell'interazione della pagina con l'utente e standardizzavano le chiamate ajax al backend.

Parlando di webapp aziendali, in cui si doveva interagire con i dati presenti su un database, mi veniva quasi naturale cercare un modo per separare il client con la sua interfaccia grafica (GUI) da tutto cio' che riguardava l'interfaccia verso il DB. In piu' cercavo qualcosa che mi aiutasse a creare GUI professionali direttamente in javascript.

Il primo framework che ho utilizzato per lo sviluppo della GUI fu Activewidgets: in questo modo potevao separare il client scritto completamente in javascript dal backend che potevo scrivere indifferentemente con un linguaggio dinamico come php,jsp, asp. Solo che ora il backend si occupava di implementare unicamente la business logic di lettura/scrittura dei dati rispetto al DB sottostante.
Il client era composto di diversi file javascript quante erano le "viste" della GUI, ed aveva un suo motore javascript per gestire la logica di generazione dinamica degli elementi della GUI attraverso le librerie di ActiveWidgets, le interazioni con l'utente e le chiamate ajax verso il backend.

Il backend era progettato con una architettura tale per cui in un unica pagina dinamica, il connettore, si gestiva un proxy di chiamate RPC in arrivo dal client. Il connettore puo' essere una pagina jsp che sfrutta la persistenza dei javabeans, oppure un modulo HttpHandler scritto in C#, o un set di moduli php.

Il mio intento principale era quello di separare il piu' possibile il client dal backend , su una architettura a due o tre livelli. Ad esempio se si ha un DB Oracle si puo' sfruttare una business logic scritta in pl/sql richiamata dai moduli intermedi scritti in java/c# del connettore che agisce solo come layer di trasporto dei dati da e verso il client, magari incapsulati in messaggi in formato JSON.

In questo modo persone diverse potevano interagire nello sviluppo della webapp, rendendo anche piu' modulare il tutto anche rispetto agli skill richiesti. Cambiando il connettore iniziale poi si poteva collegare il client a qualsiasi tecnologia di backend il cliente avesse a disposizione, mantenendo allo stesso tempo le medesime librerie per il client.

Su questo modello di architettura ho iniziato ad utilizzare come framework javascript ExtJS (dalla versione 4.2 in poi)  migliorando molto le funzionalità che si possono implementare nel client. In pratica le webapp ora sono delle applicazioni su singola pagina che non hanno nulla da invidiare ai programmi che sviluppavo in C/C++ con architettura client/server.

ExtJs nel tempo ha reso disponibili e stabili tecniche avanzate per effettuare chiamate di tipo RPC, introducendo la tecnologia Ext.Direct. In pratica si tratta di un protocollo che permette di scrivere le chiamate alle funzioni remote scritte sul backend direttamente sul client. Basta che sia configurato ed installato un connettore adatto al linguaggio utilizzato con cui il motore di ExtJs mappa i metodi disponibili sul server di backend  scritti seguendo le convenzioni opportune in modo tale che la chiamata al metodo javascript venga reindirizzata alla funzione remota sul server.

Questa e' l'architettura che piu' o meno ho utilizzato finora.

Parallelamente nel tempo ho visto venire alla ribalta molti altri framework javascript, piu' o meno incentrati sulle funzionalità di creazione delle GUI.

Bootstrap, Meteor, Backbone.js, Angular.js, Ember.js e sicuramente qualcuno me lo sono dimenticato

Dovendo gestire webapp aziendali ho sempre trovato ExtJs ottimo, anche perche' secondo me ha una delle migliori Grid disponibili. Veloce, flessibile, e piena di funzionalità, ed i clienti di solito quando chiedono un componente di questo tipo tendono a pensare a funzionalità che nemmeno la griglia di excel possiede...

C'e' un aspetto che pero' ho sempre cercato di migliorare in una architettura di questo tipo: come minimo occorre poter gestire skill di javascript per il client, jsp/php/c# per il backend sull'application server e TSQL/plsql per la business logic sul DB. E senza considerare le varianti possibili sui vari layer. Ma se per TSQL/plsql non ci sono molte alternative in ambito enterprise (in altri ambiti si possono usare NoSqlDB javascript)

Full Stack Javascript


A questo punto ho pensato alla possibilità di utilizzare una architettura che utilizzasse solo javascript, dal client alla logica di business lato server.
Node.js sarebbe perfetto per utilizzare javascript anche sul server ed in piu' ha dei plus tra cui:
  • molto efficiente grazie alla struttura event-based
  • utilizzando Express e' semplicissimo scrivere un server HTTP
  • ci sono moduli per connettersi ai principali DB, tra cui SqlServer (effettivamente provato e non serve compilare i sorgenti),MySql ed Oracle
In questo modo si puo' creare un server HTTP che risponde alle chiamate effettuate dal client ExtJs, sia mantenendo call di tipo RPC sia modificando le chiamate in architettura REST.

Resta un ultimo problema da risolvere: come si puo' integrare il client javascript che utilizza le librerie ExtJs che deve essere servito come pagine statiche nel web server istanziato dal processo generato con Node.js

Node e' ottimizzato per gestire i contenuti dinamici, ma servire contenuti statici pone tutta una serie di problematiche e limitazioni, non ultimo il fatto che il loop degli eventi rimane bloccato finche' si completa il trasferimento di files di dimensioni considerevoli.

Nginx usato come reverse proxy


La soluzione che ho trovato e' quella di usare Nginx come webserver per i contenuti statici, e come reverse-proxy per utilizzare il server creato con Node per le chiamate REST che il client effettua per recuperare i dati dal backend.
In pratica Nginx serve i files statici iniziali (html piu' i vari engine javascript che compongono il client) poi le interazioni con l'utente che generano le call ajax vengono reindirizzate da nginx sul server Node che opera su un processo distinto. Occorre che i servizi nginx e node stiano in ascolto su due porte diverse e che le call ajax REST abbiano un entry point comune, ad esempio il percorso "http://nomesito/api/" .
Il tutto viene gestito , supponendo che node sia in ascolto sulla porta 3000, con una direttiva di configurazione che per nginx puo' essere come questa

location ~ ^/api|other1|other2 {
    proxy_pass   http://127.0.0.1:3000;
}
mentre per i contenuti statici, supponendo che tutte le librerie del client siano referenziate nel file index.html si puo' usare questa direttiva

location / {
    root html;
    index index.html index.htm;
}

Nessun commento: