Elogio al TDD

_Logo Il TDD è una pratica molto affascinate perché permette agli sviluppatori, propensi più a scrivere codice che a valutarne gli effetti, di fare quello che preferiscono: scrivere codice, appunto. Il TDD coinvolge tanti concetti in un unico e continuo processo di sviluppo... Un'esplosione di creatività, insomma.

Avere sviluppatori che perdono tempo ad avviare un intero sistema per verificare anche la più piccola modifica ha un costo enorme e non sempre è possibile o sostenibile poter verificare un sistema utilizzando il lavoro dei tester. Inoltre, considerando un test manuale, è assai improbabile che possa coprire tutte le possibilità che un software mediamente complesso ha: di qui la necessità di creare test automatici, ripetibili e indipendenti, necessità che un bel po' di tempo fa ha portato all'idea delle Unit Test: codice ripetibile e automatizzabile per verificare il proprio software.

L'evoluzione di questa visione ha portato al Test Driven Development, che più che una pratica di testing è una metodologia di sviluppo, una pratica di design. Con design non si intende naturalmente la progettazione a 360° dell'applicazione e della sua architettura. Si intende il design di quella parte di codice necessario per soddisfare un insieme di requisiti, generalmente collegato ad una singola funzionalità ma non necessariamente: è possibile eseguire il design a partire da una visione di più alto livello e scendere via via nei dettagli delle singole classi.

Uno degli aspetti più interessanti del TDD è la possibilità di intervenire su un sistema senza aver paura di rompere il suo attuale stato. In pratica di avere a disposizione tutto un insieme di regression test che permette di aggiungere una nuova funzionalità senza comprometterne altre… e se i test esistenti falliscono si apre la necessità di un re-disegn di una parte del sistema per accogliere le nuove richieste. Il fatto di scoprirlo durante l’implementazione e non in produzione è notevole....

I regression test sono particolarmente utili durante il fixing degli errori: non è raro che il fix di un bug ne generi un altro. Situazione paradossale e tragica che il TDD allevia. Tra l’altro creando la UT per tracciare un bug e disegnare la sua risoluzione, permette di evitare spiacevoli ritorni.

Comunque, il TDD ha come scopo principale quello di guidare lo sviluppatore nella realizzazione del sistema, cercando di farlo concentrare su un singolo problema alla volta: spesso la smania del creare si protrae oltre al necessario.

Ciò che si ottiene, fin dalla prima release, è un software di alta qualità. Difficile che non abbia alcun tipo di problema e la perfezione come si dice non è di questo mondo. Ma dover spendere un intero ciclo di sviluppo per correggere la prima release è una procedura che dovrebbe appartenere al passato. La seconda release, come predicano le metodologie agili, dovrebbe portare miglioramenti e nuove funzionalità, inserite nel sistema senza compromettere l'esistente.

Siccome sono anni che sviluppo software conosco perfettamente la frustrazione di dover andare in produzione con codice abbozzato velocemente e conosco anche la frustrazione di dover correggere un errore già risolto in passato. Proprio per questo posso garantire che le più moderne metodologie di sviluppo possono fare la differenza e permettere agli sviluppatori di dedicarsi al miglioramento dell'applicazione, del processo di sviluppo e di se stessi.

Dimentichiamo quindi la consuetudine di sopravvivere: alle nuove richieste, agli inspiegabili errori e alla disorganizzazione. Il consiglio è seguire quelle pratiche, come il TDD, che tracciano un solco entro cui muoversi al riparo da consuetudini maligne.

Sempre dalla mia esperienza so che la documentazione relativa all'analisi, al progetto e all'implementazione sono una chimera e se dovessero mai esistere, nel senso di essere utili in qualche modo, allora è quasi certo che dopo un po' di tempo tale documentazione diventi obsoleta. Le vari forme di automatic testing permettono di creare una documentazione direttamente nei sorgenti: il semplice uso di nomi parlanti per le Unit Testing piuttosto che forme più evolute come il BDD e derivati, permettono di indicare chiaramente cosa ci si aspetti dal software. E siccome il cosa ci si aspetta può cambiare nel tempo, è probabile che la documentazione non cambi ma il codice sì e quindi, in presenza di Unit Test, anche le cosiddette specifiche integrate: si parla di documentazione viva, molto utile anche per metter mano a codice esistente scritto da altri o da passare ad altri.

Mi è già successo di dover metter mano a del codice difficile da comprendere... magari codice scritto proprio dal sottoscritto qualche anno prima. Il TDD allieva questi tipi di problemi, assieme all’applicazione dei principi SOLID, all’uso dei design pattern e al clean code in generale. In realtà, una delle forze del TDD è che la sua adozione porta necessariamente ad utilizzare tali tecniche, altrimenti risulta totalmente impraticabile: il TDD porta al cosiddetto well-crafted code, perché testare una classe che ha troppi compiti ed fortemente accoppiata con altre classi è improponibile.

Dimentico sempre di fare una puntualizzazione: nessuno scrive codice perfetto e anche quando si conoscono e si applicano tante utili nozioni bisogna scontrarsi con tanti fattori che possono dar vita a codice migliorabile. Succede. Il refacotring è proprio un processo che ben si sposa con il TDD, perché lo si può affrontare con sicurezza grazie ai regression test e applicando sempre la pratica first test: scrivo il test, modifico, verifico, miglioro.

Se poi si hanno la forza e la costanza di affiancare altre due tecniche importanti come le code review e il pair programming i risultati sono garantiti.

Tag: TDD