Test Driven Development

Il test driven development (TDD) è una tecnica di progettazione del software che mira a far emergere “dal basso” il design più semplice in grado di risolvere un dato problema. Non si tratta ne un’attività di verifica ne di scrittura del codice, quanto piuttosto un approccio alla scrittura di questi ultimi.

Il TDD si fonda su due concetti fondamentali, esplicitati nella seguente citazione:

TDD = test-first + baby steps

Il significato di questa espressione è che per scrivere del codice che esalti la semplicità della soluzione è necessario scrivere prima il test rispetto al codice (test-first) e procedere a piccoli passi (baby steps), realizzando cioè piccole porzioni di codice, testandole e solo allora andando avanti. Questa tecnica mira infatti a stabilire un ciclo di feedback istantaneo: facendo piccoli passi e testando ogni volta ciò che si appena scritto è meno probabile buttare molto tempo su una soluzione che non funziona, e anche in caso di errore è più facile individuare cosa lo genera e come risolverlo.

Per applicare questo approccio test-driven allo sviluppo effettivo di software, il TDD ha sviluppato il seguente “mantra”: rosso, verde, refactoring. Quando si scrive codice bisogna infatti seguire le seguenti tre fasi:

  • Ogni volta che si deve aggiungere una feature si scrive prima il test che la provi; non essendo ancora stata sviluppata, tale test dovrà fallire (rosso). In questa fase si crea già una parte di specifica, perchè descrive l’utilità la nuova feature o della parte di codice che si sta creando. L’eccessivo tempo impiegato in questa fase sta a significare che il problema è troppo complesso, ed è quindi necessario scomporlo per renderlo più semplice. In questa fase cerco di mettermi nei panni del cliente, per capire esattamente come voglia che il software funzioni e come debba rispondere a determinati input.

  • Si cerca poi di soddisfare il test il più velocemente possibile, facendolo diventare verde. Si ottiene così del codice corretto ma probabilmente molto brutto, quasi come fosse una bozza: tale codice serve però come feedback del fatto che l’algoritmo scelto funziona. Nonostante la rapidità nello sviluppo di questa soluzione, si deve comunque tenere conto, almeno minimamente, delle proprie scelte implementative, in quanto fungeranno da fondamenta per il prossimo step.

  • Si compie infine un’azione di refactoring (fattorizzazione), ovvero si riorganizza e si riscrive il codice in modo da renderlo migliore assicurandosi però che il test continui ad essere soddisfatto (in questa fase dobbiamo rimanere in uno stato di verde).

Questa ciclo in tre fasi va ripetuto con una cadenza frequente, ogni 2-10 minuti: ciò obbliga a concentrarsi su compiti semplici evitando così di perdersi in costruzioni software complicate che magari non funzionano neanche. Si preferisce invece prima fare qualche piccolo progresso (increment) e poi semplificare per migliorare il codice (simplify).

È importante inoltre capire perché quel passaggio intermedio, la “bozza” menzionata al secondo punto dell’elenco precedente, è tanto importante: concentrarsi in primo luogo sulla creazione di una base funzionante permette subito di capire se si è scelta la strategia giusta per risolvere il problema corrente. Scrivere direttamente il codice “in bella” impiegherebbe molto più tempo e potrebbe non produrrebbe neanche un codice funzionante, siccome maggiore è la complessità del codice che si scrive più è probabile commettere errori.

In virtù di quanto appena detto, l’uso del TDD come tecnica di progettazione garantisce inoltre due importanti vantaggi:

  • Spesso capita di scrivere codice difficilmente testabile: scrivere il test prima e il codice dopo aiuta invece a progettare prodotti la cui correttezza può essere provata.

  • Scrivere prima i test aiuta a definire chiaramente le interfacce del programma e come queste comunicano tra di loro, mentre se non dovessimo farlo potremmo avere delle dipendenze complicate da rimuovere.