Il web ha rivoluzionato la maggior parte degli aspetti della vita quotidiana di tutti nell’ambito privato, la velocità e semplicità che le grandi piattaforme garantiscono nella circolazione di informazioni per messaggistica ed acquisti hanno fatto passi da gigante negli ultimi 20 anni, cosa che non si può invece dire del settore pubblico.
In Europa, e all’interno di ciascuna nazione, ci sono a macchia di leopardo esempi virtuosi di adozione del digitale per semplificare l’amministrazione pubblica con la stessa efficienza ed “esperienza d’uso” che garantiscono i grandi colossi tecnologici, in Italia beh sappiamo come funziona…abbiamo degli apparati intrinsecamente lenti che non riescono e non possono reagire al cambiamento con la stessa velocità, capita quindi di andare sui siti della Pubblica Amministrazione (PA) e pensare di essere ancora negli anni 90.
Hack.Developers Italia, riavviare il sistema della PA
Se stai leggendo questa pagina sei molto probabilmente uno sviluppatore, quante volte ti è capitato di pensare:
“Io sta roba la facevo meglio in due giorni!”
A me tante, e si da il caso che ho acquisito esperienza proprio presso uno dei grandi player dell’IT a cui spesso ci si riferisce come esempi di efficienza come Expedia, allora mi son detto, perché non fare davvero qualcosa?
È ciò che ha pensato anche Diego Piacentini, ex Vice Presidente di Amazon tornato in Italia specificamente per condurre pro bono il nuovo Team Digitale della PA, per riavviare il “sistema digitale” del paese, ed è stato lo spirito con cui si è svolto l’evento Hack.Developers Italia 2017 che ha avuto luogo contemporaneamente in decine di sedi Italiane e all’estero, per chiamare quanti più sviluppatori Italiani a contribuire a progetti software di interesse pubblico.
Tra i vari progetti disponibili ospitati su GitHub a cui era possibile apportare il proprio contributo ho individuato quello relativo allo smart button per il sistema di identificazione SPID.
Così come gli onnipresenti social login buttons che siamo abituati a vedere ovunque, questo progetto ha come obbiettivo finale un JS importabile dall’esterno, autosufficiente in termini di risorse HTML, CSS e JavaScript, che si occupata di gestire in maniera centralizzata una UX consistente per autenticarsi presso i servizi della PA con delle credenziali uniche.
Partendo dalla bozza iniziale ho creato il mio branch per apportare un refactoring corposo, che non ha inciso sulle funzionalità originali per l’utente, se non per l’introduzione della possibilità di auto renderizzarsi senza riferimenti HTML sulla pagina e configurare l’invio POST/GET dei pulsanti accessibili.
Il mio obbiettivo principale era donare le nozioni di gestione e manutenzione di un progetto Front End orientate al lungo periodo, come le ho apprese in Expedia collaborando su progetti di lungo periodo insieme a decine di sviluppatori come me.
Code style e IDE agnostic
Anche all’interno di una stessa azienda non è detto che tutti usino gli stessi strumenti hardware e software per lavorare, si spazia tranquillamente tra Windows, Mac e Linux o commistioni dei tre tramite macchine virtuali di vario tipo, sia per lavoro sia per pipeline automatizzate. Per lo sviluppo in se, si sa, anche un text editor può fare il suo sporco lavoro, ma i ben più comodi IDE sono numerosi e con meta dati di progetto molto diversi tra loro.
Insomma per garantire che un progetto sia correttamente gestibile su una pluralità di piattaforme ed IDE è bene pensare ad un’ossatura che prescinda da tutto e sia facilmente malleabile in ciascun ambiente.
NodeJS ci viene incontro, definendo un package.json ci permette di esplicitare di quali moduli e controlli si compone il progetto e di quali strumenti si hanno a disposizione per verificare che tutto vada liscio, permettendo la creazione di un server localhost che funziona allo stesso modo in ogni ambiente, definendo anche operazioni di minifizzazione delle risorse, garantendo così una modalità di sviluppo e testing omogenea a tutti i dev.
Line Endings e version control
A molti è capitato di modificare un file su git e constatare che invece delle singole righe modificate, l’intero file viene identificato come completamente cambiato, ciò può accadere se il file che stiamo salvando è stato precedentemente modificato su un sistema operativo diverso dal nostro, ed ora il nostro OS/IDE modifica le invisibili proprietà di line ending.
Tuttavia è possibile istruire git per determinare in che modo questo ed altri aspetti relativi alla codifica dei file vengano gestiti al momento del commit da parte di chiunque, con il file .gitattributes.
Linting: Tabs, JS e CSS
Uno stesso obbiettivo può essere raggiunto scrivendo codice nei modi più disparati, tuttavia dover analizzare e discutere codice ogni volta diverso può comportare grossi costi in termini di tempo speso in irrisolvibili discussioni circa quale sia il modo “giusto” per scrivere una determinata cosa quando in realtà un modo più giusto non c’è, ed è qui che ci vengono in aiuto le convenzioni.
Adottare una convenzione scritta che viene automaticamente applicata dal proprio IDE ed automaticamente controllata prima dei commit può ridurre moltissimo il tempo speso sulle pull request, nonché salvare rapporti umani e di lavoro.
Per spazi vs tab abbiamo .editorconfig che viene automaticamente applicato in fase di digitazione nell’IDE (può servire un plugin), per JavaScript c’è .eslintrc mentre per i CSS abbiamo .stylelintrc, i quali si esplicitano sia come suggerimenti durante la scrittura nell’IDE (sempre via plugin), che come controllo formale prima del commit tramite git hook e grunt.
Evitare l’effetto FOUC
Come tutti sanno, HTML e CSS non sono linguaggi di programmazione in quanto non hanno caratteristiche Turing equivalenti, tuttavia ci sono obbiettivi di esperienza d’uso e di percezione di performance che si possono raggiungere solo tramite una intelligente combinazione dei due derivante da una buona conoscenza del modo in cui il browser li utilizza.
Dopo aver inizializzato il modulo JavaScript partirà una chiamata per ottenere la lista di provider ed etichette via Ajax, ottenuti i quali si può renderizzare i pulsanti nella pagina, contestualmente parte il caricamento del foglio di stile CSS minifizzato, ma appunto in quel momento non saranno ancora disponibili stili da applicare per cui il tasto apparirà inizialmente spoglio per poi rivestirsi progressivamente dei colori, altezze/larghezze e quant’altro, fenomeno noto in gergo tecnico come FOUC ovvero Flash of unstyled content:
Un pò come se Cenerentola si presentasse al ballo in stracci per poi farsi sfavillante direttamente sul posto davanti a tutti…
Renderizzando i pulsanti con l’attributo hidden verrà invece applicato all’elemento un display:none proveniente dal foglio di stile locale del browser, definendo lo stile di display del pulsante a valle del file CSS quindi dopo che tutte le altre regole sono state scaricate, ci assicuriamo che i pulsanti appaiano nella loro sfavillante interezza in un colpo solo.
CSS legacy compliant con Autoprefixer
L’uso dei pre-processori CSS come Sass garantisce una vasta gamma di potenzialità utili che il CSS da solo non possiede, ma con grandi poteri vengono anche grandi responsabilità, sopratutto perché il livello di astrazione fornito da Sass è un’arma a doppio taglio se si perde di vista il codice CSS che viene compilato e servito agli utenti.
A tal proposito, i due grandi errori che vedo spesso ricorrere sono relativi all’abuso dei mixin, il primo quando vengono utilizzati impropriamente al posto delle classi CSS, risultando in file di grandi dimensioni, e il secondo è la creazione di blocchi per apporre prefissi vendor a molteplici selettori, che di rado se non mai vengono rivisti in base al mutare delle condizioni dei browser supportati per tali proprietà, per altro in maniera incoerente perché alcune volte i suddetti mixin vengono usati e altre no.
Questo secondo aspetto in particolare, può essere più organicamente affrontato dopo la fase di compilazione con postcss ed autoprefixer, che in base alla baseline mobile di supporto definita in .browserslistrc arricchisce opportunamente le proprietà che lo richiedano.
Separation of concerns
Fermo restando la necessità primaria del progetto di avere un codice finale da includere quanto più leggero, minimalista, ed autosufficiente possibile, ciò non significa che sorgente di lavoro e prodotto finale debbano coincidere, considerando che le diverse necessità dei due elementi vanno in conflitto.
Il prodotto finale che si vuole ottenere è un singolo file JS che una volta caricato metta disposizione dei metodi per inizializzare il pulsante, a seguito di cui viene caricato il CSS nella pagina e renderizzato l’HTML necessario nella pagina, gestendo poi dinamicamente cosa mostrare e quando in base alle interazioni sulla pagina, tutto questo in 2 file appunto, un JS e un CSS (più assets esterni quali sfondi e loghi).
Più leggero è il file meglio è quindi assolutamente nessuna libreria e nessun framework per quanto compressi, minimalismo totale per risparmiare quanta più banda possibile.
Partendo da questa traccia ho creato i miei file separati per gestire questi distinti aspetti, all’interno dello stesso modulo, sfruttando l’estensione del prototype del mio oggetto/modulo JavaScript in modo da mantenere tutto all’interno dello stesso namespace:
- template HTML: src/js/agid-spid-enter-tpl.js
- localizzazione: src/js/agid-spid-enter-i18n.js
- logica JS: src/js/agid-spid-enter.js
Questi tre elementi messi insieme durante la minifizzazione vengono infine guidati da un file di configurazione, opportunamente differenziato tra sviluppo e produzione, che produce come risultato finale dei file con nome in semantic version sia per CSS che JS, ed un latest per ciascuno, sia per dev/ che per dist/.
Se non può essere testato si romperà
Unit tests: Jasmine
Se anche solo una piccola parte del codice è “troppo difficile da testare” significa che è non è stata impostata in maniera chiara, che funziona solo in base alla perfetta conoscenza di meccanismi che risultando oscuri al prossimo sviluppatore che ci metterà le mani avranno un’alta probabilità di essere involontariamente compromessi, il che è un male.
Gli unit test, oltre ad essere presenti, devono essere veramente “unitari” nel senso che l’ordine in cui i test vengono eseguiti deve essere irrilevante, per consentire di inserire/rimuovere/modificare qualunque parte senza che altri abbiano a risentirne.
Code coverage: Istanbul
Scrivere unit test è sicuramente un primo passo, ancora meglio sarebbe cominciare prima dai test e poi dal codice in stile TDD, tuttavia non si può sapere se ogni casistica è stata effettivamente coperta se non c’è un analisi statica del codice quando i test vengono eseguiti, qui entra in gioco Istanbul che a valle dell’esecuzione dei Jasmine test ci conferma che tutto sia stato adeguatamente coperto dai test.
Accessibility test: Axe
Il tema dell’accessibilità del web, conosciuto nel settore con l’acronimo di a11y, è uno di quei buoni propositi di cui si parla quasi sempre in ottica di futura adozione e blanda attenzione durante la fase di scrittura dei template, ma si da il caso che ad oggi esistono degli strumenti di automazione in gradi di effettuare dei controlli di base circa la validità dell’HTML prodotto.
Axe è una libreria JavaScript che usata in combinazione con Jasmine consente di validare una pagina HTML, sia che si tratti di una pagina remota o in esecuzione in localhost o di frammenti generati durante l’esecuzione del test Jasmine, permettendo quindi di attendere eventi dinamici sulla pagina e testare dunque anche quei template che non appaiono subito all’atterraggio ma che sono usati solo in specific contesti.
Così facendo, se manca qualcosa nell’HTML per essere accessibile o se viene introdotta inavvertitamente una regressione, ci sarà un test che fallirà, ci indicherà l’errore impedendo di committare codice inaccessibile.
Un sistema sicuramente più affidabile dei vaghi buoni propositi di ricordarsi dell’accessibilità, che è come promettersi di iniziare la palestra a Gennaio… 🙄
Tutto bello, ma quindi da dove comincio?
Dal terminale, i passi sono:
clona il progetto da GitHub
1 |
git clone https://github.com/srescio/spid-smart-button.git |
entra nella cartella del progetto ed installa le dipendenze
1 |
cd spid-smart-button && npm install |
se tutto è stato installato correttamente saranno generati i minifizzati, verrà avviato il server locale e il watch dei sorgenti per iniziare a lavorare, altrimenti se ci sono stati intoppi o comunque per avviare i tre step di cui sopra, esegui il comando:
1 |
npm start |
ora puoi visitare la pagina http://localhost:9000/ dalla quale puoi raggiungere:
- la demo/sviluppo: http://localhost:9000/index.html
- gli unit test Jasmine: http://localhost:9000/_SpecRunner.html
- la code coverage Istanbul: http://localhost:9000/coverage/dev/agid-spid-enter.min.js.html
Se vai a sviluppare una nuova feature, dopo aver creato un nuovo branch incrementa il numero di semantic versioning presente nel package.json#L3 il che verrà propagato anche ai nomi dei nuovi file minifizzati e nelle configurazioni preposte.
Modifica qualunque file che si trova sotto la cartella src/js ed src/scss e sei pronto per committare 🙂 .