Ho letto con interesse il lungo dibattito ancora in corso al post di Alessandro "My life with TDD". Purtroppo però mi sembra che ci sia tanta confusione su cosa è e cosa non è il TDD e i molti dubbi arrivano da chi non l'ha mai provato.
La prima volta che ho sentito parlare di TDD lavoravo con Claudio e fu proprio lui a girarmi il link ad un articolo che parlava di questa pratica: liquidai la cosa con un "non credo che funzionerebbe" (o forse con una frase più colorita).
Dopo qualche anno ho iniziato a scrivere UnitTest e scoraggiato dal fatto che non sempre riuscivo a scrivere i test che volevo ho voluto dare una possibilità al TDD e dopo alcuni mesi di pratica ho inziato a prenderci gusto e a trarne enormi benefici.
Riporto quindi un elenco "fiume" in ordine sparso di mie opinioni su cosa è e cosa non è il TDD per provare dare una risposta a tutti i "commentatori" di Alessandro e magari sollevare altre discussioni.
- Il TDD non è una pratica di Test (anche se il nome lo fa presupporre) è prima di tutto una pratica di design
- Il TDD ha come gradito effetto collaterale il fatto di far nascere una suite di test
- I test ottenuti con il TDD non coprono tutti i casi, ma si possono sempre aggiungere altri test man mano che identifico altri casi o che trovo bug nel codice
- Il codice ottenuto in TDD è in quantità minore e si focalizza solo su ciò che serve
- Il codice ottenuto in TDD è più ortogonale e più semplice da mantenere
- La prima barra rossa (del ciclo Test->Rosso->implemento->Verde->Refactoring) è il segnale che il test sta testando qualcosa (e vi garantisco che è importantissimo)
- I test non possono contenere if, switch ecc...quindi vuol dire che sono semplici metodi di 5-6 righe di codice
- Imparare il TDD è difficile: secondo me il passaggio al TDD ha lo stesso impatto del passaggio dalla programmazione funzionale strutturata a quella ad oggetti
- Imparare il TDD richiede tempo e costanza
- Il TDD non si impara leggendo articoli o libri ma praticandolo
- Ogni unita del nostro codice è testabile (è matematica)
- Testare che la sfumatura di rosso del pulsante sia quella che piace al cliente non è compito del TDD
- Con un opportuno uso dei Mock Object posso testare che il gradiente sia applicato in modo corretto
- I test case nascono dalle user story raccolte con il cliente e quindi rispondono ai requisiti del cliente
- Il team che applica il TDD deve essere opportunamente skillato se non tutti lo sono c'è sempre il pair programming
- Il codice di Test è in quantità maggiore di quello testato
- Il TDD ti obbliga a ragionare prima di scrivere del codice
- Il TDD ti obbliga a dichiarare quello che vuoi ottenere prima di scrivere del codice
- Il TDD ti mette dalla parte dell'utente del tuo stesso codice e quindi ti obbliga a scrivere interfacce facilmente usabili
- Il TDD ti spinge a scrivere codice semplice e chiaro con piccoli metodi e classi ben disaccoppiate
- I test di integrazione ti permettono di capire come la tua classe interagisce con le altre
- Quando devo apportare modifiche al codice posso partire dai test e capire quindi cosa devo modificare nel codice esistente e dove lo devo fare
- I test hanno anche il compito di documentare il codice: leggere un test per capire come usare una classe è molto efficace
- Il TDD non garantisce che il programma non contenga bug
- Il TDD garantisce che vecchi bug corretti tramite test non si ripresentino
- Il TDD è un costo iniziale che viene ammortizzato sulla vita del progetto
- Il TDD abbatte notevolmente il tempo richiesto per il test manuale
- Con il TDD il debugger è usato molto meno e solo per operazioni chirurgiche
- Il TDD permette di spezzare il problema in piccoli passi e risolvere ogni passo andando sempre verso la soluzione
- Ogni test case rappresenta una singola funzionalità o una parte di essa: quindi quando un test fallisce ho un solo problema
- Se ho due test rossi ho due problemi distinti
- Ogni nuovo test aggiunge una nuova funzionalità al codice esistente
- E' difficile testare applicazioni multithread per il loro aspetto non deterministico
- E' costoso testare le UI, ma esistono dei pattern che riducono la "superficie" non testata (MVP/MVC)
- I test di integrazione con il database vanno scritti e permettono di testare le query e lo schema del database
- Il TDD ti costringe a scrivere codice meno incapsulato per poter essere testato
- Il TDD ti constringe a scrivere oggetti indipendenti e ad iniettare le dipendenze
- Scrivere i test dopo non è sempre possibile
- Il TDD non è il "silver bullet" (ma sicuramente aiuta il successo del progetto)
NOTE:
1) L'elenco sopra è stato scritto di getto basandomi su ciò che ho imparato in questi anni di TDD ed è personale
2) Se volete posso argomentare su ognuno di questi punti, mi piace discutere perchè dalle discussioni nasce il miglioramento. Vi invito però a non usare il blog ma ad usare un forum o una mailing list, magari quella di UgiALT.Net o quella di ExtremeProgramming.
UPDATE: ho aperto un thread sulla mailing list: http://tech.groups.yahoo.com/group/ugialtnet/message/1393