Il mestiere di progettare per componenti
Come si progetta una libreria di componenti che si adatta a progetti, designer e sviluppatori?
Il successo di un’applicazione non è una questione di tecnologia, di librerie o di framework: a far la differenza agli occhi dell’utente non sono gli aspetti tecnici, ma la qualità dell’esperienza e dell’interfaccia: è quindi fondamentale che ogni persona che prende parte al processo di sviluppo di un prodotto possa lavorare al meglio e contribuire con la propria cultura e la propria sensibilità. La creazione di un ambiente mirato a strutturare la cooperazione di figure professionali diverse come designer e sviluppatori è un obiettivo tanto auspicabile quanto complesso da raggiungere: permettere a queste figure di lavorare in cicli brevi e iterativi su una singola funzionalità o un determinato aspetto del prodotto non solo ottimizza il flusso di lavoro, ma ne migliora anche la qualità. Questo risultato può essere ottenuto tramite la creazione di un sistema a componenti, ovvero scomponendo il sito Web o l'applicazione in elementi riutilizzabili, definendone alcuni o tutti gli aspetti come stile, semantica e funzionalità.
Passare a un approccio modulare e lavorare sulla coerenza del sistema ha risolto molte delle problematiche che negli anni si erano manifestate nel nostro team: la sensazione di “pericolo” nell’aggiungere una funzionalità a un sito o il vero e proprio senso di panico nel momento in cui si rendeva necessario un aggiornamento delle tecnologie usate: rilasciare aggiornamenti e miglioramenti è diventato più semplice grazie alla riusabilità dei componenti, così come rimettere mano al codice e allo stile in seguito a un allineamento tecnologico trasversale a molti progetti è diventato più preciso e performante, migliorando anche le nostre pratiche di debug, ottimizzazione e testing.
Questa trasformazione non è stata indolore: abbiamo sperimentato con strumenti, metodologie e rapporti personali; abbiamo sbagliato più volte strada, a volte abbiamo dovuto rallentare per poi raggiungere grandi traguardi in tempi inaspettati. In questo articolo raccogliamo spunti per migliorare il flusso di lavoro e consigli per scegliere le tecnologie più adatte ai team, raccontando come abbiamo costruito la struttura che ci permette, nella nostra realtà artigianale, di mantenere, aggiornare e sviluppare siti, Web application, Design System e Microfrontend con una base di codice solida e condivisa, costituita da più di cento componenti.
Il laboratorio
Conoscere le condizioni dell’ambiente in cui si lavora, interpretare i bisogni dei colleghi e capire quelli dei clienti. Esempi della metodologia e dei momenti di condivisione.
Comunicare
Il primo e più grande errore che si possa fare nello sviluppare componenti è pensare che basti utilizzare un framework per sviluppare componenti: come in ogni metodologia, non basta applicare le regole: bisogna combinarle con l’ambiente e soprattutto con le persone per ottenere un risultato soddisfacente sotto tutti i punti di vista. Design, sviluppo, comunicazione, tutte le aree del laboratorio svolgono la propria funzione determinante per la riuscita del progetto e in quanto tale devono condividere esigenze, soluzioni e informazioni.
Quando la comunicazione funziona bene:
- lo sviluppatore che ha un progetto da implementare conosce anche le motivazioni per cui sono state prese certe decisioni. Può quindi stabilire con maggiore chiarezza quali componenti vanno creati e quali vanno migliorati, pianificare aggiornamenti e introduzione di nuovi strumenti;
- il designer sa come verrà implementato il proprio progetto e può fornire indicazioni specifiche per alcuni aspetti. Può contare su una raccolta di componenti già progettati e documentati per realizzare prototipi o aggiornamenti al sistema;
- designer e sviluppatore conoscono le necessità del cliente, non solo il risultato che devono raggiungere; sono quindi più ricettivi e propositivi. Entrambi possiedono la competenza per individuare punti deboli nella comunicazione di alcuni prodotti o dell’immagine stessa del cliente.
In alcuni ambienti, dove questa condivisione potrebbe essere resa difficile da dipartimenti e/o lavoro da remoto, è assolutamente necessario che gli strumenti sopperiscano eventuali problemi di comunicazione: chi lavora a un progetto deve avere la possibilità di accedere in maniera rapida allo storico delle scelte progettuali senza perdersi in thread o dettagli di implementazione.
Condividere
I momenti di condivisione sono quindi fondamentali non solo per risolvere problematiche legate alle lavorazioni, ma anche per monitorare l’efficacia della comunicazione. Per i team che già utilizzano la metodologia Agile, la retrospettiva diventa un momento importantissimo in questo senso: il team può raccogliere e gestire tempestivamente problemi nel flusso di lavoro, pianificare momenti di formazione (tech talk, raccolte di risorse o di esempi) e valutare strumenti già in uso o novità da integrare.
Più in generale, l’utilizzo di un framework come Scrum è fortemente consigliato per la natura delle lavorazioni che seguono un processo iterativo con flussi di rilascio periodici, per evitare inceppamenti, degrado tecnologico delle piattaforme e competenze centralizzate – i peggiori nemici di un sistema di componenti.
Soprattutto nei primi tempi di rodaggio, raccogliere i feedback dei propri colleghi è cruciale: tanto più il team cresce in affiatamento, tanto più il sistema diventa solido ed efficace. In un certo senso, si può dire che la qualità dei componenti rifletta la stabilità dei rapporti professionali tra le persone che li hanno progettati e implementati.
La mano, la testa e l’esperienza
Valorizzare il talento del singolo, migliorare la sensibilità al progetto e capire come funziona l’ecosistema per formulare tempistiche, individuare le tipologie di intervento e valutare le soluzioni.
La mano
Uno dei miti che circondano la tecnica è la credenza che le persone che la sviluppano a livelli superiori debbano essere dotati di un fisico speciale. Per ciò che riguarda la mano, questo non è del tutto vero. [...] Le dita possono impegnarsi in una tattilità proattiva, di sondaggio, anche senza intenzionalità cosciente, come quando le dita esplorano un oggetto in cerca di un punto particolare che stimoli il cervello a pensare.
Richard Sennett, L’uomo artigiano, 2008
Come Sennett ci presenta la mano dell’artigiano che esprime il proprio talento e la propria sensibilità nel riconoscere la funzionalità e la qualità del materiale che tratta, allo stesso modo uno sviluppatore può impostare il codice di un componente in modo che svolga le funzionalità per cui è stato creato ma soprattutto con l’attenzione e la qualità richiesta perché aggiunga valore al progetto.
Sebbene sia impossibile possedere la competenza tecnica per trattare l’intero sistema di componenti, chi vi lavora deve condividere i concetti e i funzionamenti che lo governano, perché è proprio in questa conoscenza che può esprimere il proprio talento. Il “talento” principale di uno sviluppatore non è quindi legato alla complessità del problema computazionale che deve risolvere, ma alla capacità di individuare una soluzione che migliori l’intero prodotto (o in questo caso, il sistema di componenti) combinando le diverse “aree” del laboratorio.
Uno sviluppatore che conosce le decisioni progettuali è anche in grado di rilevare problemi prima di implementarle, così come un progettista esperto riconosce e trova soluzioni semplici per problemi tecnologici complessi. Il lavoro in coppia di designer e sviluppatore migliora drasticamente la qualità dei componenti grazie a una sensibilità estesa al progetto che consente di trattare tutti i dettagli implementativi in un unico ciclo. Infatti, spostare parte della lavorazione dello sviluppatore nella fase di design consente di scrivere specifiche più complete e coerenti. Inoltre, la condivisione di competenze che si mette in atto in questo passaggio è anche un momento di crescita professionale per entrambe le figure, non solo nella costruzione di un vocabolario comune ma anche nell’approccio al progetto successivo.
Schemi mentali
Siccome i componenti di un’interfaccia o di un’applicazione possono essere di diverse tipologie, anche le implementazioni possono essere molteplici. Diventa necessario che il team definisca le differenze strutturali delle possibili applicazioni in modo da riconoscere l’approccio più indicato in termini di coerenza con il sistema. Per esempio, seguendo la suddivisione in atomi, molecole e organismi proposta in Atomic Design (Brad Frost, Atomic Design, 2016), il nostro team ha individuato per ogni categoria gli aspetti da curare in termini grafici, di navigazione, di funzionalità e di accessibilità:
Atomi: sono gli elementi più semplici di tutti, per questo sono anche quelli più riutilizzabili. Non definiscono un’azione specifica, né si curano che sia eseguita, semplicemente suggeriscono come interagire con l’elemento. Nel caso di un bottone, vengono definiti tutti gli stati come focus o pressed ma non viene in nessun modo agganciato un comportamento all’azione di click sullo stesso. Generalmente trattiamo questa tipologia usando solo gli elementi primitivi del HTML (accessibili per natura), individuandone gli stili di base necessari alla definizione del componente;
Molecole: non molto più complesse degli atomi, definiscono elementi dove il tipo di interazione dell’utente è più delineato. Anche qui, dove possibile utilizziamo le strutture complesse presenti in HTML per definire micro-template che implementino correttamente le regole di accessibilità con una navigazione lineare: quando lavoriamo a un form verifichiamo l’utilizzo combinato corretto di label e input così come la presenza di placeholder e testi alternativi per gli strumenti assistivi, mentre l’aspetto grafico si limita a descrivere un layout per gli elementi;
Organismi: a questo livello conosciamo con relativa sicurezza come l’utente interagirà con il componente, possiamo quindi impostare una navigazione alternativa a quella lineare e quali azioni può compiere. È probabile che il template sia definitivo e semi-statico, per questo occorre anche progettare un’interfaccia programmatica di accesso dall’esterno, per personalizzare alcuni aspetti con un set controllato di opzioni e proprietà e/o un sistema di eventi o di callback per integrare funzionalità.
L’esperienza
Grazie a una suddivisione di questo tipo, diventa più semplice per designer e sviluppatore capire funzionalità e competenze del componente che stanno implementando. Siccome si possono descrivere sia aspetti formali che strutturali, occorre lavorare in fase di progetto per individuare in quali contesti l’elemento può essere utilizzato, capire come può evolvere dal punto di vista grafico e dove invece l’aspetto visivo deve essere declinato all’interno del prodotto, concentrandosi unicamente sulla funzionalità dell’elemento. Lavorando sull’astrazione di questi aspetti è possibile definire i livelli di implementazione necessari per ogni componente e creare fondamenta solide e allo stesso tempo snelle per un sistema che necessariamente deve evolvere coerentemente e velocemente.
Per implementare la vista a calendario di una serie di eventi, il nostro team ha lavorato alla realizzazione di un componente di base costituito unicamente da un organismo che facesse uso di atomi come etichette e bottoni e molecole come il dettaglio dell’evento su cui costruire l’esperienza di navigazione. Questo ci ha consentito poi di inserire il componente in diversi siti semplicemente applicando le regole del progetto grafico agli elementi atomici, snellendo il processo di aggiornamento e di validazione che si sarebbe invece dilungato laddove l’aspetto formale fosse stato intrinsecamente combinato con quello strutturale.
Gli strumenti
Linguaggi, strumenti, macchine e accessori che aiutano lo sviluppatore, il designer e il cliente. Le documentazioni utili e quelle indispensabili.
I validatori automatici di accessibilità e di coding style che aiutano designer e sviluppatori nelle loro lavorazioni quotidiane si rivelano molto utili anche in altri campi, come quello della formazione e della condivisione. Inoltre, possono essere usati dal team come supporto per un cambio di metodologia, per esempio per il passaggio da un flusso top-down a uno iterativo.
Per questo la scelta degli strumenti e delle tecnologie è importante che avvenga in seno al team che li dovrà adoperare. Questo passaggio richiede documentazione, libertà di sperimentazione e metodo. A volte conviene crearsi i propri strumenti invece di forzare il team ad utilizzarne uno che non riconosce come funzionale, altre bisogna sapere riconoscere quando le problematiche sono dovute a una mancanza di familiarità, altre ancora quando occorre abbassare la soglia delle funzionalità e delle potenzialità per rendere questi strumenti ancora più adoperabili.
Quanto più uno strumento è integrato nel processo, tanto più è efficace: quando abbiamo sviluppato DNA avevamo bisogno di una libreria per definire componenti Web che non ci imponesse un pattern stabilito da altri sviluppatori ma che fosse basata sui nostri schemi mentali, versatile nell’utilizzo vista la natura mista del team e che evolvesse secondo i nostri ritmi.
Unit test, visuali e di accessibilità
Quando possibile, avvalersi di validatori automatici, anche implementati a un livello base e non completo, costituisce un grande aiuto per il team di design/sviluppo. Nel particolare caso dello sviluppo a componenti i test più importanti sono quelli che verificano il corretto funzionamento dell’interfaccia programmatica di accesso, il rispetto delle regole di accessibilità dell’elemento e la presenza di regressioni grafiche.
I validatori non sono solo strumenti di controllo, ma anche di condivisione e formazione: integrare regole relative all’utilizzo del linguaggio di programmazione tramite un linter o impostare uno standard di accessibilità richiesto permettono di assimilare nuove specifiche direttamente nel contesto di lavoro.
Per esempio, il nostro team approccia gli aggiornamenti del linguaggio JavaScript tramite l’introduzione di nuove regole per ESLint in modo da acquisire a livello di gruppo non solo come funziona la nuova sintassi, ma anche quando e perché usarla. Queste regole ci aiutano anche nella costruzione dei template per le viste, ricordandoci di aggiungere gli attributi HTML richiesti per migliorare l’accessibilità del componente. Tramite controlli sull’ordinamento semantico e funzionale delle regole CSS, Stylelint ci aiuta invece a ridurre errori e conflitti nei fogli di stile altrimenti inevitabili quando si lavora a diverse decine di file in un progetto. L’utilizzo di un coding style sia per la parte JavaScript che per quella CSS migliora inoltre la ricerca nel codebase, facendoci risparmiare tempo ed energie.
Pratiche e automazioni
Se da un lato i risultati del pair programming in termini di qualità sono evidenti nel panorama della programmazione, la pratica di lavorare in coppia con un designer è molto meno comune, ma altrettanto efficace. Abituati a lavorare con strumenti diversi, il fatto di dedicarsi a un artefatto comune, che sia una proposta grafica o l’implementazione di un componente, è un buon modo per trattare nella loro completezza gli aspetti formali e strutturali. Sempre in quest’ottica, la scelta di uno strumento comune è sempre più efficace di uno strumento di collegamento, che aggiungerebbe un ulteriore passaggio e che potrebbe diventare un potenziale ostacolo alla comunicazione e alla condivisione.
Sempre nell’ottica di favorire l’integrazione, impostare un flusso di DevOps per automatizzare le operazioni migliora l’esperienza di sviluppo, riduce il rischio di errori e consente anche ai progettisti di mettere mano al codice con maggior sicurezza. Anche se la maggior parte delle lavorazioni avviene in ambiente isolato, per eseguire alcuni controlli occorre verificare il comportamento del componente direttamente nel sito Web. Per questo motivo ogni componente costituisce un modulo sganciabile dall'intero sistema per essere testato in un ambiente di validazione senza richiedere un aggiornamento dell'intera libreria: ad ogni modifica il sistema di continuous delivery pubblica la versione aggiornata dell'elemento su un registro remoto (nel nostro caso NPM) a cui il validatore può accedere per scaricare la versione specifica da testare. Lo scopo di questo meccanismo è quello di ridurre le operazioni manuali, il rischio di errori o incompatibilità e le tempistiche richieste per eseguire la validazione, anche quando si tratta di effettuare un rilascio urgente per risolvere un problema.
Un’altra pratica che nel lungo periodo porta vantaggi nel processo di aggiornamento e manutenzione di un componente è quella di usare Pull Request: incaricare un membro del team di revisionare gradualmente la coerenza del sistema migliora l’interoperabilità degli elementi e ne semplifica la documentazione. Revisione del codice, validazione funzionale e test automatici servono a verificare che tutti i criteri di accettazione, anche quelli impliciti, siano stati rispettati prima di introdurre una modifica nel sistema di componenti.
Documentazione
Redigere una documentazione tecnica porta sempre dei benefici per il team, ma farlo per un sistema di componenti può servire anche a ridurre il gap fra il lavoro del designer e dello sviluppatore. Grazie a strumenti come Storybook, che consentono di integrare le scelte progettuali con un’anteprima dell’elemento, si semplificano i punti di accesso al progetto, prevenendo i rischi di disallineamenti tra design e implementazione.
Anche la scelta di uno strumento per la documentazione di progetto deve tenere presente il flusso di lavoro: se la soluzione scelta non si integra con il processo rischia di deteriorarsi nel tempo. Tuttavia, vanno evitati anche strumenti il cui contenuto è estemporaneo e strettamente legato al contesto come Slack e chat varie. Alcuni software utili sono Confluence (che si integra con Jira) e Basecamp.
Conclusioni
In passato la separazione forzata di design e sviluppo ha imposto la costruzione di ponti fragili, poco praticabili e che nessuno aveva piacere ad attraversare o curare. Quando si costruiscono ponti è necessario investire molte risorse e molto tempo nella comunicazione fra le due figure, quando invece si costruiscono laboratori l'efficienza della condivisione porta vantaggi sia in termini di tempo che di qualità. Molto spesso, ancora oggi, il lavoro di uno sviluppatore viene visto unicamente per la sua funzione ingegneristica, mentre il ruolo di un progettista viene altrettanto spesso definito come quello del “creativo”. Seppur questi aspetti siano caratteristiche del lavoro di entrambe le figure, non bastano a descrivere il reale apporto che insieme danno al progetto. Questo si manifesta nella sua totalità quando si segue un flusso di sviluppo a componenti, dove l’abilità dei professionisti risiede nell’implementare una soluzione coerente, funzionale e piacevole, sia per gli utenti che per chi lavora al progetto.
In linea con quelli che sono i principi della metodologia Agile, lo sviluppo a componenti richiede cicli di progettazione, sviluppo, rilascio e test molto brevi e mirati, con l’obiettivo di migliorare il prodotto tramite un approccio realmente iterativo e collaborativo.
Edoardo Cavazza