Un barlume di speranza. Come mantenere il codice sano utilizzando l’unit testing

L’imbuto e le biglie, ovvero la metafora della produttività dei team

La verifica di singole unità di codice per individuare gli errori, semplificare le modifiche e facilitare l’integrazione soprattutto quando si lavora con le moderne architetture come i microservizi e il serverless. Non avere test di unità è come fumare. Le conseguenze si vedono solo dopo

A settembre 2003, mi trovavo nell’accogliente città di Aarhus, in Danimarca, per tenere un discorso alla famosa conferenza JAOO. All’epoca, JAOO era una conferenza sullo sviluppo software già da tempo affermata, alla quale partecipavano relatori famosi del calibro di Martin Fowler, Kent Beck, Linda Rising ed Erich Gamma. E me. Arrivato alla sede, un centro congressi appena fuori il cuore della città, uno degli organizzatori si offrì di farmi fare una visita guidata dell’edificio. Mentre passeggiavamo, mi vennero indicate con entusiasmo le sale principali in cui si sarebbero svolti i lavori. Poi, all’improvviso, l’organizzatrice si fermò davanti a una porta di legno in un piccolo corridoio, e aprendola quasi con devozione, mi invitò a guardare dentro. Era una stanza scarsamente illuminata con mobili accatastati alle pareti. «Sa cosa è successo in questa stanza?» – mi chiese sottovoce. Scossi la testa. Ovviamente, non ne avevo idea. «È qui che, durante la JAOO dell’anno scorso, Kent Beck ed Erich Gamma hanno concettualizzato l’unit testing e concepito JUnit». E questa è stata la mia prima introduzione ai test di unità.

TI PIACE QUESTO ARTICOLO?

Iscriviti alla nostra newsletter per essere sempre aggiornato.

La necessità dell’unit testing

L’impatto che JUnit ha avuto sul settore dello sviluppo del software è stato enorme. È stato il primo framework di unit testing praticabile. Di conseguenza, le persone hanno iniziato lentamente ad adottare i test di unità. Tuttavia, ci è voluto molto tempo per guadagnare terreno. Non molto tempo fa, stavo allenando un team di sviluppo che si era completamente bloccato. Non osavano cambiare un’altra riga di codice, temendo che il loro codice di cinque milioni di righe si sarebbe danneggiato. In oltre dieci mesi, non era stata consegnata ai clienti una sola funzionalità. Quando abbiamo analizzato il loro codice, abbiamo trovato pochi test di unità, un livello di copertura del codice quasi inesistente, un’elevata complessità ciclomatica e molti percorsi non testati nel codice. E anche in questo caso, quando ho ribadito l’importanza di scrivere test di unità per mantenere la qualità e la velocità di sviluppo, gli sviluppatori mi hanno guardato con il muso lungo e mi hanno chiesto se scrivere tutti questi test fosse davvero, ma proprio davvero, necessario. Lo è.

Ci vuole tempo

Per essere del tutto onesto, mi ci è voluto un po’ di tempo per convincermi degli effetti e dei benefici dei test di unità e, più avanti, dello sviluppo guidato dai test. Per gli autori Kent Beck ed Erich Gamma, l’obiettivo numero uno per la creazione di JUnit era “scrivere un framework all’interno del quale abbiamo qualche barlume di speranza che gli sviluppatori scrivano effettivamente dei test”. Hanno costruito JUnit con strumenti già esistenti e familiari, in modo che ci fosse poco da imparare. Semplicemente Java. Come hanno ribadito più volte: «Non deve richiedere più lavoro dello stretto necessario per scrivere un nuovo test». Gamma e Beck hanno reso la scrittura dei test unitari il più semplice possibile. Ma allora perché è così difficile iniziare a scrivere test di unità?

Leggi anche:  Intelco, il ruolo dei team leader nella gestione del personale

Nonostante la semplicità di strumenti come Jest che è la mia attuale “croce” per testare il mio codice TypeScript e JavaScrip, basandomi sulla mia esperienza personale, penso che uno dei problemi risieda nel fatto che la scrittura di test unitari richiede sempre e comunque competenze e comprensione. Ci vuole tempo per imparare a scrivere test unitari corretti. E il tempo è sempre una risorsa scarsa nello sviluppo software. C’è una pressione costante da parte degli stakeholder, dei manager e dei proprietari del prodotto per aggiungere e migliorare le funzionalità nei nostri prodotti. Non sembra mai esserci abbastanza tempo a disposizione per lavorare sulla qualità della nostra architettura e del nostro codice. Per questo motivo, tendiamo a saltare la scrittura dei test di unità.

Nel lungo periodo

I benefici di avere buoni test di unità si manifestano solo a lungo termine. E forse, li apprezziamo solo quando abbiamo avuto un codice sotto controllo per sei mesi o un anno. La facilità e la sicurezza con cui si può modificare ed estendere una base di codice completamente testata è una gioia. Ma solo dopo un po’ di tempo. Le persone non sono brave ad aspettare per vedere i benefici. Non avere test di unità è come fumare, e sappiamo tutti che fumare fa male. Però, le persone trovano estremamente difficile smettere di fumare. Questo perché gli svantaggi del fumo di solito si avvertono solo dopo anni. Nel caso dei test di unità, la situazione è molto simile. Avere test di unità per ogni cosa ripaga nel lungo periodo. Si ripaga dopo sei mesi, quando ci si accorge di poter modificare il codice senza soffrire. E si ripaga dopo un anno, quando si può ancora modificare il codice quasi senza sforzo e senza effetti collaterali. Anche dopo diversi anni, il vostro codice rimane stabile ed è persino diventato più robusto di quanto non sia mai stato. Purtroppo, un gran numero di sviluppatori rimandano la scrittura di test di unità fino a quando non è (troppo) tardi e le conseguenze di non avere un codice testato sono diventate importanti. Come nel caso del fumo.

Leggi anche:  Sanità digitale, nuovi modelli di cura e assistenza

Come mantenere il codice in buona salute

La situazione peggiora quando si lavora con le moderne architetture software, come i microservizi o il serverless, dove di solito non si ha un’unica base di codice, ma si lavora su una vasta collezione di piccole basi di codice. Con uno dei miei recenti clienti, il quadro complessivo consisteva in circa quaranta microapplicazioni, cinquanta microservizi e circa lo stesso numero di funzioni serverless, ognuna delle quali con le proprie codebase, pipeline e infrastrutture. In ambienti come questi, diventa ancora più importante mantenere le basi di codice in buona salute. Non mantenere in buona salute un ambiente così complesso si traduce rapidamente nella risoluzione di bug infiniti, nella creazione di workaround che nessuno ricorda il giorno dopo, in un forte calo della produttività, in persone demotivate che si limitano a mantenere un codice di scarsa qualità invece di creare nuove funzionalità. E infine, un blocco totale dell’innovazione di un’organizzazione. I test di unità sono essenziali per mantenere il codice sano. Per fare un esempio, mentre scrivo questo articolo, io e il mio team stiamo esaminando una piccola ma delicata modifica nella libreria principale della piattaforma del mio cliente. Questa libreria contiene circa millecinquecento righe di codice. Una trentina di applicazioni e microservizi in produzione dipendono fortemente da questa libreria. Senza pensarci due volte, abbiamo apportato la modifica; abbiamo eseguito i 385 test di unità sulla libreria; abbiamo visto che diventavano tutti verdi e abbiamo verificato il codice. Nessuna pipeline si è interrotta durante il processo. Senza test di unità adeguati, non avremmo avuto la sicurezza o il coraggio di fare un cambiamento radicale come questo. Avremmo semplicemente lasciato correre finché non saremmo più stati in grado di garantire la qualità e la manutenibilità delle nostre basi di codice. Proprio come ho visto fare a tanti clienti.

È ora di smettere di rimandare

Il mio consiglio? Smettere di lamentarsi dello sforzo e del tempo necessari per iniziare a scrivere test di unità. Basta lamentarsi che scrivere test di unità è noioso. Bisogna superare tutto questo. E anche se potrebbe sembrare che i test di unità non mantengano le loro promesse nell’immediato, a lungo termine daranno di sicuro enormi benefici. Non bisogna aspettare che il codice diventi impossibile da sistemare. Così come è meglio smettere di fumare oggi invece di aspettare di finire il  pacchetto prima, o rimandando fino al primo gennaio dell’anno prossimo. Non ci sono scuse. È sempre meglio iniziare a scrivere test di unità oggi. Ecco, adesso smettete di leggere e iniziate a scrivere test di unità.

Leggi anche:  Data governance e self-service. Il futuro dell’accesso ai dati in azienda

Sander Hoogendoorn

Mentore, allenatore, software architect, sviluppatore, speaker e scrittore, apprezzato come grande innovatore nello sviluppo software. Autore di best-seller come “This Is Agile” e “Pragmatic Modeling with UML”, ha pubblicato più di 250 articoli su riviste specializzate. Oltre a essere keynote speaker in molte conferenze internazionali, presenta seminari e corsi di formazione in tutto il mondo su diversi argomenti quali, tra gli altri: Agile, Scrum, Kanban, continuous delivery, architettura software, microservices, modeling e UML.

Sander Hoogendoorn presenterà per Technology Transfer il seminario “Progettare, sviluppare e implementare una Microservices Architecture” che si terrà online live streaming il 21 aprile 2023