Nella prima parte di questa serie di tre articoli ho descritto la genesi del progetto "site". V1, la prima versione, mi ha permesso di avere il mio sito personale giandisa.it e di presentare un altro mio progettino: l'app Rilassicelle per iphone e ipad. Il sito V1 era "responsive" grazie a Bootstrap e distribuito su due datacenter ai due lati dell'oceano grazie al database NoSql CouchDB. Ho anche fatto cenno al fatto che ho sviluppato un apposito modulo software per poter distribuire e aggiornare la webapp "site" nei due datacenter.

The Sacred Grail of Programming

Approfitto, ora, per rivelare che nelle ultime release di V1, avevo implementato anche alcuni servizi http per fornire autenticazione e gestione dei punteggi ad un'altra app mobile che stavo sviluppando. Il database degli utenti e dei punteggi era costruito su CouchDB. L'idea era di far sì che l'app di ogni utente comunicasse col server più vicino e lasciare che CouchDB distribuisse i dati tra i vari nodi. Se un nodo fosse caduto, l'altro sarebbe stato attivo, registrando "eventually" i dati. Quando il nodo mancante sarebbe stato nuovamente attivo, CouchDB avrebbe riallineato i dati tra i nodi, mentre un mio modulo avrebbe gestito la risoluzione di eventuali conflitti. Questo sistema avrebbe dovuto essere in grado di gestire, situazioni di "split-brain", quando due nodi sono temporaneamente isolati tra di loro per problemi di rete.

Stavo, quindi, lavorando molto sulle basi tracciate da V1. Ma, nuovi venti stavano spazzando i cieli di internet e così, venni tentato di rivedere il progetto "site" dalle fondamenta.

V2 Blocking contro Non-Blocking: essere “reactive” e il "nuovo" modello a loop di eventi

In quei tempi, Node.js stava guadagnando popolarità. Node.js è un runtime JavaScript event driven, progettato per creare applicazioni di rete scalabili. Un possibile vantaggio sarebbe stato poter usare JavaScript sia sul client, il browser, che sul server. Ma la parte realmente interessante era un'altra: la riscoperta di un modello di concorrenza basata su operazioni di I/O non bloccanti in cui routine di callback vengono richiamate in corrispondenza a specifici eventi. Questo, differentemente dal modello di concorrenza, popolare nei precedenti vent'anni, basato su thread multipli con operazioni di I/O bloccanti. I thread forniscono astrazioni relativamente semplici per ottenere concorrenza e gestire la sincronizzazione nell'accedere a risorse condivise senza conflitti. Si veda per esempio il concetto di "Monitor" implementato nativamente nel linguaggio Java. Il tutto a prezzo di un cospicuo uso di memoria, di elvato uso di CPU per gli scambi di contesto ed il rischio di deadlock. La concorrenza basata su eventi riduce di molto le pretese sulle risorse, ma al rischio del cosiddetto "callback hell", quando multiple calback sono annidate una dentro l'altra. Altro rischio è che una routine computazionalmente intensa, blocchi l'esecuzione di tutti gli altri compiti, a meno che non si ricorra ad un qualche stratagemma.

Anch'io volevo che il mio sito e i sui servizi potessero rispondere a milioni di richieste al secondo come promesso dalle tecnice di programmazione asincrona!!! Sì..., lo so che il traffico del mio sito è di circa dieci richieste l'ora, fatte per lo più da robot (sob!), ma lasciatemi sognare!!!

Anche se JavaScript ha dimostrato la sua utilità nel dare contenuti dinamici alle pagine web, personalmente preferisco utilizzare un linguaggio a tipizzazione statica. La tipizzazione statica a mio umile avviso è molto utile perché:

  • un analizzatore di codice, il compilatore nel caso di linguaggi compilati, può rilevare molti errori prima dell'esecuzione
  • un editor/IDE può fornire utili aiuti come il completamento contestuale del codice, suggerimenti e avvertimenti sul codice scritto

Inoltre, node.js forniva, così com'era, un solo loop degli eventi per processo e necessitava di un po' di lavoro, clustering etc..., per evitare che una routine computazionalmente intensa potesse bloccare il sistema.

Dopo qualche ricerca scoprii Vert.x di RedHat, adesso portato nell'ambito di Eclipse Foundation. Vert.x è un tool-kit per realizzare applicazioni "reattive" che girano sulla JVM. Si può scegliere tra molti linguaggi: Java, JavaScript, Groovy, Ruby, Ceylon, Scala and Kotlin con API che seguono i tipici idiomi di ciascun linguaggio.

È di uso generale e non vuole imporre l'uso di particolari librerie e framework. In inglese viene usato il termine "unopinionated". Un'altra cosa veramente importante: Vert.x ha una straordinaria documentazione!!! Decisi di usare il linguaggio Java, in modo da far tesoro della mia esperienza e di un po' di codice del progetto V1.

In V2, avrei tenuto Bootstrap per fornire un'interfaccia web "responsive" e CouchDB per la persistenza dei dati. Le pagine web dovevano essere create dinamicamente lato server. Non potevo usare le JSP e Stripes. In passato avevo usato un "Template engine" fatto da me, ma avevo anche considerato qualche libreria open source. Scelsi Chunk Templates che era molto flessibile e che stavo già utilizzando in un altro mio progetto. Apprezzavo la sua particolarità di permettere più sezioni per file oltre ad offrire le comuni direttive essenziali per inserire condizioni e iterazioni. Per interagire con CouchDB dovetti abbandonare la libreria sincrona LightCouch e sviluppare una mia libreria per accedere a CouchDB via chiamate http REST.

Per usare Vert.x, ho dovuto padroneggiare il, per me, nuovo paradigma asincrono. E' stata una sfida, ma alla fine pubblicai il mio sito web con un nuovo cuore asincrono. Nelle successive release di V2, aggiunsi anche la gestione di articoli scritti in markdown. Tutte le altre funzionalità di V1 furono portate in V2, compreso il sistema per ditribuire la web app tra i datacenter usando CouchDB e gran parte dei servizi sperimentali per un mio gioco per smartphone.

Il principale problema che avvertii fu gestire le varie callback per ottenere un codice pienamente asincrono. Adesso capisco cosa sia l'inferno delle callback!!! La programmazione asincrona è complessa anche usando Promises/Futures che aiutino a comporre per parti la gestione degli eventi.

Dopo qualche mese considerai le altre alternative offerte da Vert.x, per evitare una gestione diretta della gestione degli eventi, come il supporto per RxJava o Vert.x Sync.

Vert.x Sync era molto interessante perchè prometteva di mantenere uno stile sincrono di programmazione anche se l'esecuzione sarebbe stata asincrona grazie alle cosiddette “fiber”. Le Fiber sono una sorta di thread minimali che possono essere bloccati senza bloccare i thread del kernel. Purtroppo all'epoca, Vert.x Sync, non mi sembrava molto maturo e necessitava di ulteriori componenti come un agente Quasar e modifiche del bytecode Ahead Of Time, così lasciai perdere.

Sentivo veramente il bisogno di un modo più semplice per sviluppare nuove funzionalità nel mio progetto "site". La programmazione asincrona ad eventi era molto interessante, ma mi richiedeva troppo sforzo. Così continuai la mia ricerca verso altre soluzioni.

V3 Ritorno al futuro: un minimale approccio tradizionale

Cercando un approccio più semplice per estendere le funzionalità del progetto "site", decisi, tristemente, di tornare alle origini, fondendo V1 e V2, usando le lezioni che avevo imparato.

Tomcat, servlet, no JSP, ma un "Template engine", no Spring, ma una classe che facesse da ApplicationContext per collegare i componenti come da pattern IoC. tutto sincrono e multithread.

Ma non ne ero convinto pienamente. V3 non giunse mai ad una conclusione e non venne mai rilasciato.

Stavo cercando qualcosa di differente, ma descriverò i passi successivi della mia ricerca nella terza e ultima parte di questo articolo.

Gianni Di Sanzo

Vai alla: Parte 1Parte 3
Condividi Twitta