Metà ottobre, giornata autunnale. Fuori piove e tu ringrazi di lavorare da remoto. Musica nelle cuffie per concentrarsi. Le dita che battono sulla tastiera.
All’improvviso la notifica di una mail distoglie l’attenzione dal codice che, stranamente, aveva qualcosa che non andava: è un’altra pull request inclusa nel branch principale.
Questa ha qualcosa di particolare però. La pipeline di rilascio ha eseguito con successo 1000 test. Messaggio al team. Vassoio di brioches per festeggiare l’evento 🥳.
La mattina in cui in Aton ci siamo accorti di aver scritto mille test nella code base del backend è andata più o meno così. E’ stato un piccolo ma significativo traguardo, reso possibile da un percorso ed un cambiamento di mindset che cercherò di raccontarvi in questo articolo.
Iniziamo!
I test ed il TDD (Test Driven Development) sono argomenti particolarmente diffusi all’interno della comunità tech e la letteratura a riguardo è decisamente cospicua. Semplificando all’osso la questione, scrivere test significa scrivere del codice che verifica e cristallizza il comportamento di altro codice.
Verificare il comportamento significa controllare che dato un certo input venga prodotto sempre lo stesso output. Sia nei casi più semplici e lineari che in quelli più articolati e subdoli. Inoltre, permette anche di constatare se il comportamento di quanto scritto aderisce alle specifiche definite in fase di analisi.
Cristallizzare, invece, assume un’importanza maggiore in termini di manutenibilità di una code base. Essa infatti evolve nel tempo e viene utilizzata da più persone contemporaneamente – che possono modificare logiche comuni o pregresse. Avere dei test a testimonianza di quanto fatto nel passato garantisce allo sviluppatore la sicurezza che ciò che ha implementato non rompa la compatibilità con quanto già esistente.
Tutto questo non è privo di fatica! Scrivere test significa anche dilatare il tempo di sviluppo per poter includere le attività legate al setup dei test stessi (es. dati di mockup, popolamento database, parametri di configurazione, etc.), alla loro scrittura vera e propria e al fix del comportamento della logica di business quando, inevitabilmente, qualche test fallisce.
Allo stesso tempo, questa dilatazione dello sviluppo viene ammortizzata quando il codice non fallisce drammaticamente in produzione e risparmia qualche notte insonne di debug allo sviluppatore.
Ok, bella la teoria. Ma in Aton come si scrivono i test?
Da quando in Aton abbiamo iniziato a sviluppare le nuove linee di prodotto basate su stack tecnologici moderni (Java/Kotlin e Spring Boot per il backend ed Angular 2 per il frontend), scrivere test è diventato un’attività quotidiana per gli sviluppatori.
Cerchiamo, per quanto possibile, di seguire il TDD: data una funzionalità, vengono scritti prima i test e solo in seguito la logica di business relativa alla funzionalità stessa. Una volta completato lo sviluppo si lanciano i test e si verifica se il comportamento definito inizialmente è rispettato dall’implementazione.
Se tutti i test passano, allora la funzionalità può definirsi completata.
Altrimenti, quando qualche test fallisce, le possibilità sono due:
1. L’implementazione non aderisce alle specifiche. Ad esempio non gestisce dei corner case, oppure restituisce un set di dati non coerente con le aspettative;
2. La definizione dei test è errata, ovvero sono stati definiti dei test non aderenti alle specifiche oppure con dati di input non coerenti con l’output atteso.
A prescindere da quale sia la motivazione che ha portato i test a fallire, lo sviluppatore deve rimettere mano al codice per fare in modo che tutti i test relativi alla funzionalità che sta sviluppando risultino verdi. Quando questo accade il lavoro può ritenersi completato e lo sviluppatore può aprire una pull request con quanto fatto.
E’ in questo momento che entra in gioco la seconda fase del processo di sviluppo del backend.
La creazione di una pull request scatena una pipeline in Azure DevOps la quale, diligentemente, esegue i test della nuova funzionalità e di tutte le funzionalità precedenti. Questa operazione lavora sul piano della cristallizzazione: viene verificato che la nuova logica non strida con quella già esistente.
Se qualcosa viene rotto, la pipeline s’interrompe ed impedisce il rilascio nel branch principale.
La scrittura di test è un’attività che ha portato grande valore ad Aton, e quindi intendiamo continuare a sostenerla nel tempo.
Tuttavia, non è detto che il modo in cui scriveremo i test rimarrà sempre lo stesso.
Il tema delle intelligenze artificiali generative e di come esse possano diventare strumenti di supporto per gli sviluppatori (e non solo) migliorandone la produttività, è molto discusso e rilevante nella comunità tech.
Tra tutti gli strumenti attualmente disponibili, GitHub Copilot è sicuramente quello più utile a chi scrive codice per professione, anche nella scrittura dei test. E’ infatti possibile, fornendo il contesto adeguato, far generare a GitHub Copilot unit test (ed altre tipologie) per una determinata funzionalità.
Utilizzare questo approccio ha una serie di pro e di contro:
👍🏻 Tempi di sviluppo più brevi. Lo sviluppatore dedica meno tempo alla scrittura di test e più tempo alla logica di business;
👍🏻 Casi di test non previsti. L’intelligenza artificiale può generare dei casi di test non previsti dallo sviluppatore, aumentando quindi la solidità della code base;
👍🏻 Casi di test imparziali. Lo sviluppatore tende ad essere amorevole nei confronti del codice e quindi è propenso a scrivere dei test conservativi che non lo mettono realmente alla prova (questo è ancora più marcato quando chi scrive i test e chi implementa sono la stessa persona);
👎🏻 Falso senso di sicurezza. I test generati dall’intelligenza artificiale devono essere sempre rivisti dallo sviluppatore per correggere eventuali errate interpretazioni o contesti troppo vaghi per l’IA.
Se questa sarà la strada definitiva per il testing, ad ora non ci è dato saperlo. Tuttavia, in Aton sono state avviate delle attività di ricerca e sviluppo proprio su GitHub Copilot per capire che impatto esso possa avere nel daily life di uno sviluppatore.
Se all’inizio dell’articolo vi siete chiesti perché abbiamo festeggiato così tanto all’avvento del millesimo test, ora dovrebbe essere un po’ più chiaro.
Mille test non sono solo una statistica, ma sono la testimonianza di un percorso che ha cambiato il nostro modo di lavorare. Un percorso che sta pian piano industrializzando il processo di sviluppo in Aton e che, anche grazie ai test, riesce a produrre software di qualità.
Se ti stai ancora chiedendo se vale la pena scrivere i test, noi di Aton possiamo risponderti di sì.
Ne vale la pena perché cambia il tuo modo di lavorare. Ne vale la pena perché cambia il tuo modo di pensare. Ne vale la pena perché aumenta la qualità del codice che scrivi. Ne vale la pena perché ti dà la sicurezza che quello che hai scritto non rompe quello che era già scritto. Ne vale la pena perché, in fondo, vedere tutte quelle spunte verdi quando passano i test provoca un picco di dopamina non indifferente!