Bit #1 - Il software funzionante "è uno dei principali" metri di misura del progresso
Assicurare il corretto funzionamento del software è un obbligo etico e morale di ogni sviluppatore.
Il Costo dei bug nel software
Immagina di prendere un volo e, poco dopo il decollo, il tuo aereo entra in picchiata a causa di un bug nel software di pilotaggio automatico. Oppure, pensa a un paziente che riceve una dose di radiazioni 100 volte superiore a quella necessaria a causa di un errore nel software di una macchina per la radioterapia. Questi non sono scenari da film di fantascienza; sono disastri reali causati da bug nel software.
Prendiamo ad esempio il Boeing 737 Max, un aereo di linea moderno. Questo velivolo è stato coinvolto in due incidenti mortali che hanno causato la morte di 346 persone. Il problema nel software del Boeing 737 MAX riguardava il sistema di controllo di volo noto come MCAS (Maneuvering Characteristics Augmentation System). MCAS era progettato per prevenire stallo aerodinamico, ma aveva difetti di progettazione che facevano sì che reagisse in modo eccessivo a dati errati del sensore di angolo d'attacco, spingendo il muso dell'aereo verso il basso in modo incontrollato. Questo problema ha portato a due incidenti fatali nel 2018 e nel 2019, causando la perdita di 346 vite umane e il ritiro temporaneo del 737 MAX dal servizio fino a quando non è stato implementato un aggiornamento software correttivo.
Questi incidenti sono solo la punta dell'iceberg. Ci sono stati altri casi in cui errori software hanno causato danni considerevoli. Un altro esempio è l'ARIANE 5, un razzo spaziale europeo che è esploso 37 secondi dopo il lancio a causa di un errore nella conversione dei dati a virgola mobile nel software di guida.
Potrei citare decine di casi simili a questo, o comunque gravi danni a business, persone o ambiente causati da software di scarsa qualità e bug presenti nel codice.
Nel 2020, negli Stati Uniti, si è stimato che il costo totale associato ai software di bassa qualità ammontasse a 2,08 trilioni di dollari.
Inoltre, il debito tecnico causato da bug e difetti nei software è stato quantificato in 1,31 trilioni di dollari, contribuendo così a un totale di 3 trilioni di dollari spesi in quel solo anno.
USA 2020 - CISQ - Consortium for Information & Software Quality™
Questi numeri sottolineano l'enorme impatto economico e finanziario dei software di scarsa qualità. La mancanza di attenzione al testing e alla qualità del codice può portare a gravi conseguenze, tra cui costi elevati di manutenzione, perdita di clienti e danni alla reputazione aziendale.
La Piramide dei Test e la Qualità del Software
Per evitare disastri come quelli menzionati, è essenziale garantire che il software sia di alta qualità1 ma soprattutto privo di bug. Qui entra in gioco la "piramide dei test"2, un concetto cruciale nello sviluppo del software introdotto da Mike Cohn nel suo libro Succeeding with Agile
La base della piramide è costituita dai "Test Unitari". Questi test sono piccoli e mirano a verificare il comportamento delle singole unità di codice, come funzioni o metodi, in isolamento. La ragione di questa enfasi sui test unitari è che forniscono un rapido feedback sulle porzioni più piccole del codice. Questi test dovrebbero essere scritti in modo tale che siano veloci da eseguire e devono coprire ogni aspetto della logica di una singola unità. Se un bug si nasconde in una di queste unità, verrà rilevato rapidamente e risolto.
Il livello successivo è composto dai "Test di Servizio". Qui ci spostiamo verso test più ampi che mirano a verificare l'interazione tra diversi servizi o componenti del software. Questi test sono utili per garantire che le varie parti del software funzionino correttamente quando sono integrate. Se hai un sistema complesso che coinvolge molte parti interconnesse, i test di servizio sono essenziali per rilevare potenziali problemi di comunicazione tra le unità. Sono più lenti dei test unitari. Tuttavia, sono essenziali per garantire che le diverse parti del software lavorino correttamente insieme.
Nel livello superiore della piramide, troviamo i "Test di Interfaccia" e i "Test di Accettazione". Questi test sono più rivolti all'esperienza dell'utente finale. I test di interfaccia verificano che l'interfaccia utente funzioni come previsto, mentre i test di accettazione si concentrano su scenari reali di utilizzo del software.
I test di interfaccia sono importanti perché sono ciò che l'utente vede e utilizza direttamente. Un'interfaccia utente disfunzionale può compromettere l'usabilità del software e portare a insoddisfazione degli utenti. I test di accettazione, d'altra parte, valutano se il software soddisfa i requisiti e le aspettative dell'utente finale.
La Pratica TDD: Un Ciclo di Sviluppo Iterativo
Ora che abbiamo esaminato la struttura della piramide dei test, concentriamoci su una pratica di sviluppo che è fondamentale per garantire la qualità del software: il "Test Driven Development" (TDD), inventato da
e descritto nel suo libro Test-Driven Development by ExampleIl TDD è un approccio che inizia con la scrittura dei test prima di scrivere il codice effettivo. Il ciclo TDD è semplice ma potente:
Scrivi un Test: Inizia scrivendo un test che descriva il comportamento che desideri implementare. Questo test inizierà sicuramente come un test fallito, poiché il codice non esiste ancora.
Scrivi il Codice Minimale: Scrivi il codice minimo necessario per far passare il test. In questa fase, non preoccuparti troppo della qualità del codice; l'obiettivo è far passare il test.
Rifattorizza il Codice: Ora che il test è passato, puoi iniziare a migliorare la qualità del tuo codice. Rimuovi duplicazioni, migliora la leggibilità e assicurati che il codice sia pulito e ben strutturato.
Questo ciclo di sviluppo iterativo assicura che ogni parte del codice sia testata e che il software funzioni correttamente. Inoltre, i test continueranno a verificare il comportamento anche quando il software subisce modifiche o aggiornamenti futuri.
I Vantaggi del TDD
Il Test-Driven Development (TDD) offre una serie di vantaggi significativi che migliorano la qualità e l'efficienza dello sviluppo software.
Innanzitutto, il TDD promuove un buon design del codice. Scrivere i test equivale a progettare il software in modo dettagliato, trasformando un processo mentale in un'azione pratica e utile. Questo approccio favorisce la costruzione di un software più solido e ben strutturato.
Inoltre, l'uso dei test come strumenti per definire il comportamento previsto del software porta a una maggiore qualità del software. Il codice viene convalidato rispetto a criteri ben definiti, garantendo che funzioni correttamente in base alle specifiche.
Il TDD contribuisce anche alla riduzione dei bug. Grazie all'esecuzione automatica dei test ad ogni modifica del codice, i problemi vengono individuati e risolti prontamente, riducendo la probabilità di introdurre errori nel software.
I test stessi fungono da documentazione tecnica dinamica per il codice, rendendo più accessibile la comprensione del comportamento desiderato del software, specialmente per i nuovi sviluppatori.
Inoltre, il TDD promuove uno sviluppo incrementale, in cui si inizia con un test che fallisce e quindi si scrive il codice necessario per farlo passare. Questo ciclo iterativo consente uno sviluppo passo dopo passo e il continuo raffinamento del software.
La pratica di scrivere i test prima del codice spinge gli sviluppatori a pensare attentamente alla progettazione dell'interfaccia e dell'architettura, portando a un codice più modulare e ben strutturato.
Avere un insieme completo di test consente ai programmatori di apportare modifiche con maggiore sicurezza, poiché i test rivelano rapidamente se le modifiche interferiscono con il comportamento esistente.
Il ciclo di sviluppo del TDD implica esecuzioni di test molto frequenti, fornendo feedback immediato, il che aiuta a individuare e risolvere problemi rapidamente.
Grazie alla scoperta precoce e alla risoluzione tempestiva dei bug, la manutenzione del software diventa meno costosa e meno stressante, contribuendo alla riduzione dei costi di manutenzione complessivi.
Nonostante la percezione che scrivere test richieda più tempo, il TDD spesso porta a una maggiore produttività complessiva, poiché riduce il tempo necessario per individuare e risolvere bug più avanti nel ciclo di sviluppo.
Infine, con un solido set di test, gli sviluppatori hanno maggiore fiducia nell'apportare aggiornamenti o modifiche al software, sapendo che i test agiranno come un "paracadute" in caso di problemi. Questo aumento della fiducia favorisce l'evoluzione sicura del software nel tempo.
In sintesi, la piramide dei test e la pratica del TDD sono strumenti fondamentali per costruire software di alta qualità. Mentre il software funzionante è uno dei principali metri di misura del progresso, non possiamo trascurare l'importanza di tutti gli altri aspetti della sviluppo software. Lavorando in modo collaborativo e olistico, possiamo costruire un futuro digitale più affidabile ed efficiente per tutti.
Conclusioni
Il nostro obiettivo come programmatori è quello di fare un lavoro impeccabile, dove ogni dettaglio è curato, dove ogni funzionalità è testata e dove ogni possibile scenario è preso in considerazione. Ma questa dedizione va oltre la semplice scrittura del codice.
Il nostro dovere è garantire che il software che creiamo non produca danni a persone, al nostro ambiente, alle organizzazioni o a qualsiasi altra cosa che tocchi. Dobbiamo essere consapevoli dell'importanza della nostra responsabilità. Come abbiamo visto, anche un piccolo bug può avere gravi conseguenze. Pertanto, dobbiamo adottare una mentalità etica nella nostra pratica di sviluppo. Dobbiamo essere consapevoli dei possibili impatti delle nostre decisioni e fare tutto il possibile per evitare danni.
Questo significa scrivere test accurati e completi, ma significa anche essere diligenti nella progettazione, nella verifica incrociata e nell'identificazione delle vulnerabilità. Significa prendere sul serio ogni segnale di allarme che i test ci forniscono e agire tempestivamente per risolvere i problemi.
In conclusione, il software funzionante è sicuramente uno dei principali metri di misura del progresso, ma come programmatori, dobbiamo fare un passo ulteriore. Dobbiamo essere guardiani del digitale, promotori della qualità e campioni dell'etica. Il nostro lavoro può avere un impatto straordinario, ma solo se lo affrontiamo con la massima competenza, responsabilità e attenzione.
Ci vediamo al prossimo bit,
Raffaele.
Mi piacciono le newsletter dove si parla di PROGRESSO. Subscribed.
Utili gli esempi pratici e la distensione delle varie definizioni di test.
Se possibile, mi piacerebbe vedere un articolo su come strutturare dei test utilizzando il TDD partendo da zero.
Grazie per la condivisione!