Cosa perdo adottando il design test driven?
Elenco solo negativi; non elencare i benefici scritti in una forma negativa.
Cosa perdo adottando il design test driven?
Elenco solo negativi; non elencare i benefici scritti in una forma negativa.
Risposte:
Diversi aspetti negativi (e non sto affermando che non ci sono benefici - specialmente quando si scrive la fondazione di un progetto - alla fine si risparmierebbe molto tempo):
Se vuoi fare un TDD "reale" (leggi: prova prima con i passaggi rosso, verde, refactor), allora devi anche iniziare a usare mock / stub, quando vuoi testare i punti di integrazione.
Quando inizi a usare i mock, dopo un po ', vorrai iniziare a usare Dependency Injection (DI) e un contenitore Inversion of Control (IoC). Per fare ciò è necessario utilizzare le interfacce per tutto (che hanno molte insidie).
Alla fine, devi scrivere molto più codice, che se lo fai semplicemente alla "vecchia maniera". Invece di una semplice classe cliente, devi anche scrivere un'interfaccia, una classe simulata, una configurazione IoC e alcuni test.
E ricorda che anche il codice di test dovrebbe essere mantenuto e curato. I test dovrebbero essere leggibili come tutto il resto e ci vuole tempo per scrivere un buon codice.
Molti sviluppatori non capiscono bene come fare tutto questo "nel modo giusto". Ma poiché tutti dicono loro che TDD è l'unico vero modo per sviluppare software, provano solo il meglio che possono.
È molto più difficile di quanto si possa pensare. Spesso i progetti realizzati con TDD finiscono con un sacco di codice che nessuno capisce davvero. I test unitari spesso verificano la cosa sbagliata, nel modo sbagliato. E nessuno è d'accordo su come dovrebbe essere un buon test, nemmeno i cosiddetti guru.
Tutti questi test rendono molto più difficile "cambiare" (al contrario del refactoring) il comportamento del tuo sistema e le semplici modifiche diventano troppo difficili e richiedono molto tempo.
Se leggi la letteratura TDD, ci sono sempre alcuni esempi molto validi, ma spesso nelle applicazioni della vita reale, devi avere un'interfaccia utente e un database. È qui che TDD diventa davvero difficile e la maggior parte delle fonti non offre buone risposte. E se lo fanno, implica sempre più astrazioni: oggetti finti, programmazione su un'interfaccia, schemi MVC / MVP ecc., Che richiedono ancora molta conoscenza e ... devi scrivere ancora più codice.
Quindi fai attenzione ... se non hai un team entusiasta e almeno uno sviluppatore esperto che sa scrivere buoni test e sa anche alcune cose sulla buona architettura, devi davvero pensarci due volte prima di percorrere la strada del TDD .
Quando arrivi al punto in cui hai un gran numero di test, la modifica del sistema potrebbe richiedere la riscrittura di alcuni o tutti i test, a seconda di quelli che sono stati invalidati dalle modifiche. Ciò potrebbe trasformare una modifica relativamente rapida in una che richiede molto tempo.
Inoltre, potresti iniziare a prendere decisioni di progettazione basate più su TDD che su principi di progettazione realmente validi. Considerando che potresti aver avuto una soluzione molto semplice e impossibile da testare nel modo richiesto dal TDD, ora hai un sistema molto più complesso che in realtà è più soggetto agli errori.
if part of the system is covered by tests and they pass, then everything is fine (including design)
.
Penso che il problema più grande per me sia l'enorme perdita di tempo che ci vuole per "entrarci". Sono ancora all'inizio del mio viaggio con TDD (vedi il mio blog per aggiornamenti sulle mie avventure di test se sei interessato) e ho letteralmente passato ore a iniziare.
Ci vuole molto tempo per mettere il cervello in "modalità test" e scrivere "codice testabile" è un'abilità in sé.
TBH, non sono rispettosamente d'accordo con i commenti di Jason Cohen sul rendere pubblici i metodi privati, non è questo il punto. Nel mio nuovo modo di lavorare non ho creato più metodi pubblici di prima . Tuttavia, comporta modifiche architettoniche e consente di "moduli hot plug" di codice per rendere tutto più semplice da testare. Si dovrebbe non essere fare le parti interne del codice più accessibile per fare questo. Altrimenti torniamo al punto di partenza con tutto ciò che è pubblico, dov'è l'incapsulamento in quello?
Quindi, (IMO) in breve:
PS: Se desideri collegamenti a aspetti positivi, ho chiesto e risposto a diverse domande al riguardo, dai un'occhiata al mio profilo .
Nei pochi anni in cui ho praticato Test Driven Development, dovrei dire che i maggiori svantaggi sono:
Il TDD è fatto meglio in coppia. Per uno, è difficile resistere all'impulso di scrivere semplicemente l'implementazione quando SAPI come scrivere un'istruzione if / else . Ma una coppia ti terrà in attività perché lo tieni in attività. Purtroppo, molte aziende / manager non pensano che questo sia un buon uso delle risorse. Perché pagare per due persone per scrivere una funzione, quando ho due funzioni che devono essere fatte contemporaneamente?
Alcune persone semplicemente non hanno la pazienza di scrivere unit test. Alcuni sono molto orgogliosi del loro lavoro. Oppure, alcuni proprio come vedere metodi / funzioni contorti eliminano la fine dello schermo. TDD non è per tutti, ma vorrei davvero che lo fosse. Renderebbe il mantenimento delle cose molto più semplice per quelle povere anime che ereditano il codice.
Idealmente, i test si interrompono solo quando si prende una decisione sbagliata sul codice. Cioè, hai pensato che il sistema funzionasse in un modo, e si scopre che non ha funzionato. Interrompendo un test o un (piccolo) set di test, questa è in realtà una buona notizia. Sai esattamente come il tuo nuovo codice influenzerà il sistema. Tuttavia, se i tuoi test sono scritti male, strettamente accoppiati o, peggio ancora, generati ( test di tosse VS), mantenere i tuoi test può diventare rapidamente un coro. E, dopo che un numero sufficiente di test inizia a causare più lavoro del valore percepito che stanno creando, i test saranno la prima cosa da eliminare quando i programmi vengono compressi (ad esempio, arriva a ridurre il tempo)
Idealmente, ancora una volta, se aderisci alla metodologia, il tuo codice sarà testato al 100% per impostazione predefinita. In genere, ho pensato, finisco con una copertura del codice fino al 90%. Questo di solito accade quando ho un'architettura in stile modello e la base viene testata e provo a tagliare gli angoli e non testare le personalizzazioni del modello. Inoltre, ho scoperto che quando incontro una nuova barriera che non avevo mai incontrato in precedenza, ho una curva di apprendimento nel testarla. Ammetterò di scrivere alcune righe di codice alla vecchia maniera skool, ma mi piace davvero avere quel 100%. (Immagino di essere stato un grande successo a scuola, er skool).
Tuttavia, con ciò direi che i vantaggi di TDD superano di gran lunga i negativi per la semplice idea che se riesci a ottenere una buona serie di test che coprono la tua applicazione ma non sono così fragili che una modifica li rompe tutti, lo farai essere in grado di continuare ad aggiungere nuove funzionalità nel giorno 300 del progetto come nel giorno 1. Questo non accade con tutti coloro che provano TDD pensando che sia un proiettile magico a tutto il loro codice pieno di bug, e quindi pensano che possa lavoro, punto.
Personalmente ho scoperto che con TDD scrivo codice più semplice, passo meno tempo a discutere se una particolare soluzione di codice funzionerà o meno e che non ho paura di cambiare nessuna riga di codice che non soddisfa i criteri stabiliti da Il gruppo.
TDD è una disciplina difficile da padroneggiare, e ci sono stato per alcuni anni, e continuo a imparare nuove tecniche di test in ogni momento. È un enorme investimento in termini di tempo, ma, a lungo termine, la tua sostenibilità sarà molto maggiore rispetto a se non avessi test unitari automatizzati. Ora, se solo i miei capi potessero capirlo.
Nel tuo primo progetto TDD ci sono due grandi perdite, tempo e libertà personale
Perdi tempo perché:
Perdi la libertà personale perché:
Spero che questo ti aiuti
TDD richiede che tu pianifichi come funzioneranno le tue classi prima di scrivere il codice per superare quei test. Questo è sia un vantaggio che un aspetto negativo.
Trovo difficile scrivere i test in un "vuoto", prima che qualsiasi codice sia stato scritto. Nella mia esperienza, tendo a superare i miei test ogni volta che penso inevitabilmente a qualcosa mentre scrivo le mie lezioni che ho dimenticato mentre scrivevo i miei test iniziali. Quindi è tempo non solo di riformattare le mie classi, ma anche i miei test. Ripeti l'operazione tre o quattro volte e può essere frustrante.
Preferisco scrivere prima una bozza delle mie lezioni, quindi scrivere (e mantenere) una batteria di test unitari. Dopo che ho una bozza, TDD funziona bene per me. Ad esempio, se viene segnalato un bug, scriverò un test per sfruttarlo e quindi correggere il codice in modo che il test passi.
La prototipazione può essere molto difficile con TDD: quando non si è sicuri della strada da percorrere per una soluzione, scrivere i test in anticipo può essere difficile (oltre a quelli molto ampi). Questo può essere un dolore.
Onestamente non penso che per lo "sviluppo di base" per la stragrande maggioranza dei progetti ci sia un vero svantaggio, tuttavia; è discusso molto più di quanto dovrebbe essere, di solito da persone che credono che il loro codice sia abbastanza buono da non aver bisogno di test (non lo è mai) e le persone che semplicemente non possono essere disturbate a scriverle.
Bene, e questo allungamento, è necessario eseguire il debug dei test. Inoltre, c'è un certo costo in termini di tempo per scrivere i test, anche se la maggior parte delle persone concorda sul fatto che si tratta di un investimento iniziale che ripaga nel corso della vita dell'applicazione sia in termini di debug risparmiati in termini di tempo che di stabilità.
Il problema più grande che ho avuto personalmente con esso, tuttavia, è alzare la disciplina per scrivere effettivamente i test. In una squadra, in particolare una squadra consolidata, può essere difficile convincerli che il tempo trascorso è utile.
Se i tuoi test non sono molto accurati, potresti cadere in un falso senso di "tutto funziona" solo perché i test superano. Teoricamente se i tuoi test superano, il codice funziona; ma se potessimo scrivere perfettamente il codice la prima volta non avremmo bisogno di test. La morale qui è assicurarsi di fare un controllo di integrità da soli prima di chiamare qualcosa di completo, non limitarsi a fare affidamento sui test.
In quella nota, se il tuo controllo di integrità trova qualcosa che non è stato testato, assicurati di tornare indietro e scrivere un test per questo.
L'aspetto negativo di TDD è che di solito è strettamente associato alla metodologia "Agile", che non attribuisce importanza alla documentazione di un sistema, piuttosto la comprensione dietro perché un test "dovrebbe" restituire un valore specifico piuttosto che qualsiasi altro risiede solo nello sviluppatore testa.
Non appena lo sviluppatore lascia o dimentica il motivo per cui il test restituisce un valore specifico e non un altro, sei fregato. TDD va bene SE è adeguatamente documentato e circondato da documentazione leggibile dall'uomo (ad es. Manager dai capelli a punta) a cui si può fare riferimento in 5 anni quando il mondo cambia e anche l'app deve farlo.
Quando parlo di documentazione, questo non è un errore nel codice, questa è la scrittura ufficiale che esiste all'esterno dell'applicazione, come casi d'uso e informazioni di base a cui possono fare riferimento manager, avvocati e la povera linfa che deve aggiornare il tuo codice nel 2011.
Ho incontrato diverse situazioni in cui TDD mi fa impazzire. Per citarne alcuni:
Manutenibilità del test case:
Se sei in una grande impresa, molte probabilità sono che non devi scrivere tu stesso i casi di test o almeno la maggior parte di essi sono scritti da qualcun altro quando entri in azienda. Le funzionalità di un'applicazione cambiano di volta in volta e se non si dispone di un sistema, come HP Quality Center, per seguirle, diventerai pazzo in pochissimo tempo.
Ciò significa anche che i nuovi membri del team impiegheranno un bel po 'di tempo per capire cosa succede con i casi di test. A sua volta, questo può essere tradotto in più soldi necessari.
Test complessità automazione:
Se automatizzi alcuni o tutti i casi di test in script di test eseguibili dalla macchina, dovrai assicurarti che questi script di test siano sincronizzati con i corrispondenti casi di test manuali e in linea con le modifiche dell'applicazione.
Inoltre, impiegherai del tempo per eseguire il debug dei codici che ti aiutano a rilevare i bug. A mio avviso, la maggior parte di questi bug proviene dall'incapacità del team di test di riflettere le modifiche dell'applicazione nello script di test di automazione. I cambiamenti nella logica aziendale, nella GUI e in altre cose interne possono far interrompere l'esecuzione o l'esecuzione irregolare degli script. A volte i cambiamenti sono molto sottili e difficili da rilevare. Una volta tutti i miei script riportano errori perché hanno basato il loro calcolo sulle informazioni dalla tabella 1 mentre la tabella 1 era ora la tabella 2 (perché qualcuno ha scambiato il nome degli oggetti della tabella nel codice dell'applicazione).
Il problema più grande sono le persone che non sanno come scrivere test unitari adeguati. Scrivono test che dipendono l'uno dall'altro (e funzionano alla grande con Ant, ma poi all'improvviso falliscono quando li eseguo da Eclipse, solo perché corrono in un ordine diverso). Scrivono test che non testano nulla in particolare: eseguono il debug del codice, controllano il risultato e lo cambiano in test, chiamandolo "test1". Ampliano l'ambito di classi e metodi, solo perché sarà più facile scrivere test unitari per loro. Il codice dei test unitari è terribile, con tutti i classici problemi di programmazione (accoppiamento pesante, metodi lunghi 500 righe, valori codificati, duplicazione del codice) ed è un inferno da mantenere. Per qualche strana ragione le persone trattano i test unitari come qualcosa di inferiore al codice "reale", e non non mi preoccupo affatto della loro qualità. :-(
Perdi molto tempo a scrivere test. Ovviamente, questo potrebbe essere salvato entro la fine del progetto catturando più rapidamente i bug.
Il più grande svantaggio è che se vuoi davvero fare correttamente il TDD dovrai fallire molto prima di riuscire. Dato il numero di aziende produttrici di software (dollaro per KLOC), alla fine verrai licenziato. Anche se il tuo codice è più veloce, più pulito, più facile da mantenere e ha meno bug.
Se lavori in un'azienda che ti paga con i KLOC (o requisiti implementati - anche se non testati) stai lontano da TDD (o revisioni del codice, o accoppia la programmazione, o l'integrazione continua, ecc. Ecc.).
Perdi la possibilità di dire che hai "finito" prima di testare tutto il tuo codice.
Si perde la capacità di scrivere centinaia o migliaia di righe di codice prima di eseguirlo.
Perdi l'opportunità di imparare tramite il debug.
Perdi la flessibilità di spedire il codice di cui non sei sicuro.
Perdi la libertà di accoppiare strettamente i tuoi moduli.
Si perde la possibilità di saltare la scrittura di documentazione di progettazione di basso livello.
Si perde la stabilità fornita con il codice che tutti hanno paura di cambiare.
Secondo la risposta sui tempi di sviluppo iniziale. Si perde anche la capacità di lavorare comodamente senza la sicurezza dei test. Sono stato anche descritto come un nutbar TDD, quindi potresti perdere alcuni amici;)
Rifocalizzare su requisiti difficili e imprevisti è la rovina costante del programmatore. Lo sviluppo guidato dai test ti costringe a concentrarti sui requisiti già noti e banali e limita il tuo sviluppo a ciò che è già stato immaginato.
Pensaci, probabilmente finirai per progettare casi di test specifici, quindi non sarai creativo e inizi a pensare "sarebbe bello se l'utente potesse fare X, Y e Z". Pertanto, quando l'utente inizia a entusiasmarsi per i potenziali requisiti interessanti X, Y e Z, il progetto potrebbe essere troppo rigido per casi di test già specificati e sarà difficile da regolare.
Questa, ovviamente, è un'arma a doppio taglio. Se passi tutto il tuo tempo a progettare per ogni immaginabile, immaginabile, X, Y e Z che un utente possa desiderare, inevitabilmente non completerai mai nulla. Se fai qualcosa, sarà impossibile per chiunque (incluso te stesso) avere idea di cosa stai facendo nel tuo codice / design.
Può essere difficile e richiede tempo scrivere test per dati "casuali" come feed e database XML (non così difficile). Ultimamente ho trascorso del tempo a lavorare con i feed di dati meteorologici. È abbastanza confuso scrivere test per questo, almeno perché non ho troppa esperienza con TDD.
Perderai grandi lezioni con più responsabilità. Probabilmente perderai anche grandi metodi con responsabilità multiple. Potresti perdere qualche capacità di refactoring, ma perderai anche parte della necessità di refactoring.
Jason Cohen ha detto qualcosa del tipo: TDD richiede una certa organizzazione per il tuo codice. Questo potrebbe essere architettonicamente sbagliato; ad esempio, poiché i metodi privati non possono essere chiamati al di fuori di una classe, è necessario rendere i metodi non privati per renderli verificabili.
Dico che questo indica un'astrazione mancata: se il codice privato deve davvero essere testato, dovrebbe probabilmente essere in una classe separata.
Dave Mann
Devi scrivere le applicazioni in un modo diverso: quello che le rende testabili. Saresti sorpreso di quanto sia difficile all'inizio.
Alcune persone trovano l'idea di pensare a ciò che scriveranno prima di scriverlo troppo. Concetti come il deridere possono anche essere difficili per alcuni. Il TDD nelle app legacy può essere molto difficile se non sono state progettate per i test. Anche il TDD in contesti non compatibili con il TDD può essere una lotta.
TDD è un'abilità quindi gli sviluppatori più giovani possono inizialmente lottare (principalmente perché non gli è stato insegnato a lavorare in questo modo).
Nel complesso, però, i contro vengono risolti man mano che le persone diventano abili e si finisce per sottrarre il codice "puzzolente" e avere un sistema più stabile.
Ci vuole un po 'di tempo per affrontarlo e un po' di tempo per iniziare a farlo in un progetto ma ... Mi pento sempre di non aver seguito un approccio Test Driven quando trovo bug stupidi che un test automatico avrebbe potuto trovare molto velocemente. Inoltre, TDD migliora la qualità del codice.
Buone risposte a tutti. Aggiungerei alcuni modi per evitare il lato oscuro del TDD:
Ho scritto app per fare il proprio autotest randomizzato. Il problema con la scrittura di test specifici è che anche se ne scrivi molti coprono solo i casi che pensi. I generatori di test casuali trovano problemi a cui non hai pensato.
L'intero concetto di numerosi test unitari implica la presenza di componenti che possono entrare in stati non validi, come strutture dati complesse. Se stai lontano da strutture dati complesse, c'è molto meno da testare.
Nella misura in cui la tua applicazione lo consente, sii timido rispetto al design che si basa sul corretto ordinamento di notifiche, eventi ed effetti collaterali. Questi possono essere facilmente lasciati cadere o rimescolati quindi hanno bisogno di molti test.
TDD richiede una determinata organizzazione per il tuo codice. Questo potrebbe essere inefficiente o difficile da leggere. O anche architettonicamente sbagliato; ad esempio, poiché i private
metodi non possono essere chiamati al di fuori di una classe, è necessario rendere i metodi non privati per renderli verificabili, il che è semplicemente sbagliato.
Quando il codice cambia, è necessario modificare anche i test. Con il refactoring questo può richiedere molto lavoro extra.
Consentitemi di aggiungere che se si applicano i principi BDD a un progetto TDD, è possibile alleviare alcuni dei principali inconvenienti elencati qui (confusione, incomprensioni, ecc.). Se non hai familiarità con BDD, dovresti leggere l'introduzione di Dan North. Ha elaborato il concetto in risposta ad alcuni dei problemi sorti dall'applicazione del TDD sul posto di lavoro. L'introduzione di Dan su BDD è disponibile qui .
Faccio solo questo suggerimento perché BDD affronta alcuni di questi aspetti negativi e funge da gap-stop. Ti consigliamo di considerare questo quando raccogli il tuo feedback.
Devi assicurarti che i tuoi test siano sempre aggiornati, il momento in cui inizi a ignorare le luci rosse è il momento in cui i test diventano insignificanti.
Devi anche assicurarti che i test siano completi, o nel momento in cui appare un grosso bug, il tipo di gestione soffocante che hai finalmente convinto di farti passare del tempo a scrivere più codice si lamenterà.
La persona che ha insegnato allo sviluppo agile del mio team non ha creduto nella pianificazione, hai scritto solo per il più piccolo requisito.
Il suo motto era refattore, refattore, refattore. Ho capito che refactor significava "non pianificare in anticipo".
Il tempo di sviluppo aumenta: ogni metodo necessita di test e, se si dispone di un'applicazione di grandi dimensioni con dipendenze, è necessario preparare e pulire i dati per i test.