Differenza di tempo tra lo sviluppo con test unitari e nessun test

130

Sono uno sviluppatore solista con un ambiente di lavoro piuttosto limitato nel tempo in cui i tempi di sviluppo variano solitamente da 1 a 4 settimane per progetto, a seconda dei requisiti, dell'urgenza o di entrambi. In qualsiasi momento gestisco circa 3-4 progetti, alcuni con timeline che si sovrappongono l'un l'altro.

Prevedibilmente, la qualità del codice soffre. Inoltre non ho test formali; di solito scende a camminare attraverso il sistema fino a quando non si rompe un po '. Di conseguenza, una notevole quantità di bug sfugge alla produzione, che devo correggere e, a sua volta, ripristina i miei altri progetti.

È qui che entra in gioco il test unitario. Se fatto bene, dovrebbe tenere a bada i bug, per non parlare di quelli che sfuggono alla produzione, al minimo. D'altra parte, i test di scrittura possono richiedere molto tempo, il che non suona bene con progetti a tempo limitato come il mio.

La domanda è: quanto di una differenza di tempo scriverebbe codice testato unitamente su codice non testato e in che modo tale differenza di tempo si ridimensiona man mano che il campo di applicazione si allarga?

    
posta Revenant 15.06.2016 - 04:37
fonte

12 risposte

144

Più tardi esegui un test, più costa scrivere test.

Più a lungo vive un bug, più è costoso da risolvere.

La legge dei rendimenti decrescenti ti assicura di metterti alla prova nell'oblio cercando di assicurarti che non ci siano errori.

Buddha ha insegnato la saggezza della via di mezzo. I test sono buoni C'è una cosa troppo buona. La chiave è essere in grado di dire quando sei fuori equilibrio.

Ogni riga di codice che scrivi senza test avrà costi significativamente maggiori per aggiungere test più tardi rispetto a se avessi scritto i test prima di scrivere il codice.

Ogni riga di codice senza test sarà significativamente più difficile da eseguire il debug o riscrivere.

Ogni test che scrivi richiederà del tempo.

Ogni bug richiederà del tempo per risolverlo.

I fedeli ti diranno di non scrivere una singola riga di codice senza prima aver scritto un test fallito. Il test assicura che stai ottenendo il comportamento che ti aspetti. Ti permette di cambiare rapidamente il codice senza preoccuparti di influenzare il resto del sistema poiché il test dimostra che il comportamento è lo stesso.

Devi pesare tutto questo sul fatto che i test non aggiungono funzionalità. Il codice di produzione aggiunge funzionalità. E le caratteristiche sono ciò che paga le bollette.

Pragmaticamente parlando, aggiungo tutti i test che riesco a farla franca. Ignoro i commenti a favore dei test. Non mi fido nemmeno del codice per fare ciò che penso che faccia. Mi fido dei test. Ma sono stato conosciuto per lanciare occasionalmente grandine Mary e avere fortuna.

Tuttavia, molti programmatori di successo non fanno TDD. Ciò non significa che non testano. Semplicemente non insistono ossessivamente sul fatto che ogni linea di codice ha un test automatico contro di essa. Anche lo zio Bob ammette di non testare la sua interfaccia utente. Ti insiste anche a spostare tutta la logica dall'interfaccia utente.

Come metafora del calcio (è il football americano) TDD è un buon gioco di terra. Solo test manuale dove scrivi una pila di codice e spero che funzioni è un gioco di passaggio. Puoi essere bravo in entrambi. La tua carriera non arriverà ai playoff a meno che tu non possa fare entrambe le cose. Non farà il superbowl finché non imparerai a sceglierne uno ciascuno. Ma se hai bisogno di una spinta in una direzione particolare: i funzionari chiamano contro di me più spesso quando sto passando.

Se vuoi provare TDD, ti consiglio vivamente di esercitarti prima di provare a farlo al lavoro. TDD fatto a metà strada, mezzo cuore, e metà assed è una grande ragione che alcuni non lo rispettano. È come versare un bicchiere d'acqua in un altro. Se non commetti e lo fai rapidamente e completamente, finisci per gocciolare acqua sul tavolo.

    
risposta data 15.06.2016 - 05:17
fonte
111

Sono d'accordo con il resto delle risposte, ma per rispondere direttamente alla domanda quale è la differenza di tempo .

Roy Osherove nel suo libro The Art of Unit Testing, seconda edizione pagina 200 ha realizzato un case study sull'implementazione di progetti di dimensioni simili con team simili (abilità sagge) per due diversi clienti in cui un team ha l'altro no.

I suoi risultati erano così:

Quindi alla fine di un progetto ottieni meno tempo e meno bug. Questo ovviamente dipende da quanto è grande un progetto.

    
risposta data 15.06.2016 - 11:11
fonte
30

Esiste solo uno studio uno che so di aver studiato in un "contesto reale": Realizzare il miglioramento della qualità attraverso lo sviluppo guidato dai test: risultati ed esperienze di quattro team industriali . È costoso farlo in un modo ragionevole, dal momento che in pratica significa che è necessario sviluppare lo stesso software due volte (o idealmente anche più spesso) con team simili, quindi lanciarne tutti tranne uno.

I risultati dello studio sono stati un aumento del tempo di sviluppo compreso tra il 15% e il 35% (che non è affatto vicino alla cifra 2x che viene spesso citata dai critici di TDD) e una diminuzione della densità dei difetti pre-rilascio dal 40% -90 % (!). Si noti che tutti i team non avevano precedenti esperienze con TDD, quindi si potrebbe supporre che l'aumento nel tempo possa almeno in parte attribuire all'apprendimento, e quindi scenderebbe ulteriormente nel tempo, ma questo non è stato valutato dallo studio.

Nota che questo studio riguarda TDD, e la tua domanda riguarda il test unitario, che sono cose molto diverse, ma è il più vicino che ho trovato.

    
risposta data 15.06.2016 - 10:44
fonte
24

Fatto bene, lo sviluppo con i test unitari può essere più veloce anche senza considerare i benefici derivanti dalla presenza di bug extra.

Il fatto è che non sono un programmatore abbastanza bravo per far funzionare il mio codice non appena viene compilato. Quando scrivo / modifica il codice, devo eseguire il codice per assicurarmi che faccia ciò che pensavo facesse. In un progetto, questo tendeva a sembrare:

  1. Modifica codice
  2. Compila l'applicazione
  3. Esegui l'applicazione
  4. Accedi all'applicazione
  5. Apri una finestra
  6. Seleziona un elemento da quella finestra per aprire un'altra finestra
  7. Imposta alcuni controlli in quella finestra e fai clic su un pulsante

E naturalmente, dopo tutto quello, di solito ci sono voluti alcuni round trip per farlo funzionare correttamente.

Ora, cosa succede se sto usando i test unitari? Quindi il processo sembra più simile a

  1. Scrivi un test
  2. Esegui test, assicurati che non funzioni nel modo previsto
  3. Scrivi codice
  4. Esegui nuovamente i test, verifica che passi

Questo è più facile e veloce quindi testare manualmente l'applicazione. Devo ancora eseguire manualmente l'applicazione (quindi non sembro stupido quando svolgo un lavoro che in realtà non funziona affatto), ma per la maggior parte ho già risolto i nodi, e sono solo verificando a quel punto. In realtà, in genere, questo ciclo è ancora più stretto utilizzando un programma che ripete automaticamente i miei test quando salvo.

Tuttavia, questo dipende dal lavorare in una base di codice facile da testare. Molti progetti, anche quelli con molti test, rendono difficili i test di scrittura. Ma se ci lavori, puoi avere una base di codice che è più facile da testare tramite test automatici che con test manuali. Come bonus, puoi tenere i test automatici in giro e continuare a eseguirli per evitare regressioni.

    
risposta data 15.06.2016 - 06:17
fonte
19

Nonostante ci siano già molte risposte, sono piuttosto ripetitive e vorrei prendere una decisione diversa. I test unitari sono preziosi, se e solo se , aumentano valore aziendale . Testare per il test (test triviali o tautologici) o per colpire alcune metriche arbitrarie (come la copertura del codice), è una programmazione di tipo cargo-cult.

I test sono costosi, non solo nel tempo necessario per scriverli, ma anche per la manutenzione. Devono essere sincronizzati con il codice che testano o sono inutili. Per non parlare del costo in termini di tempo per eseguirli ad ogni cambio. Questo non è un rompicapo (o una scusa per non fare quelli veramente necessari), ma deve essere preso in considerazione nell'analisi costi-benefici.

Quindi la domanda da porre al momento di decidere se testare o meno (o di quale tipo) testare una funzione / metodo, chiedersi 'quale valore dell'utente finale sto creando / salvaguardando con questo test?'. Se non puoi rispondere a questa domanda, in cima alla tua testa , allora quel test probabilmente non vale il costo di scrittura / mantenimento. (o non capisci il dominio del problema, che è un problema waaaay più grande di una mancanza di test).

link

    
risposta data 15.06.2016 - 17:24
fonte
9

Dipende dalla persona, così come dalla complessità e dalla forma del codice con cui stai lavorando.

Per me, nella maggior parte dei progetti, scrivere test di unità significa che il lavoro viene eseguito circa il 25% più velocemente. Sì, includendo anche il tempo per scrivere i test.

Perché il fatto è che il software non è fatto quando scrivi il codice. È fatto quando lo spedisci al cliente e ne sono felici. I test unitari sono di gran lunga il modo più efficiente che io conosca per catturare la maggior parte dei bug, isolare la maggior parte dei bug per il debug e per ottenere la certezza che il codice sia buono. Devi fare quelle cose comunque , quindi fallo bene.

    
risposta data 15.06.2016 - 05:26
fonte
4

Question is, how much of a time difference would writing unit-tested code over untested code, and how does that time difference scale as project scope widens?

Il problema peggiora man mano che l'età del progetto aumenta: perché ogni volta che aggiungi nuove funzionalità e / o ogni volta che rifatti un'implementazione esistente, devi ripetere il test di ciò che è stato precedentemente testato per assicurarti che funzioni ancora. Pertanto, per un progetto pluriennale di lunga durata, potrebbe essere necessario non solo testare la funzionalità ma testarla nuovamente 100 volte e oltre. Per questo motivo potresti trarre vantaggio dall'avere test automatici . Tuttavia, IMO è abbastanza buono (o anche meglio) se si tratta di test di sistema automatizzati, piuttosto che di test unitari automatizzati.

Un secondo problema è che i bug possono essere più difficili da trovare e correggere se non vengono scoperti presto. Per esempio se c'è un bug nel sistema e so che funzionava perfettamente prima di apportare le ultime modifiche, quindi concentrerò la mia attenzione sulle ultime modifiche per vedere come avrebbe potuto introdurre il bug. Ma se non so che il sistema funzionava prima di aver apportato le ultime modifiche (perché il sistema non era stato testato correttamente prima delle ultime modifiche), il bug potrebbe essere ovunque.

Quanto sopra si applica in particolare al codice profondo e meno al codice poco profondo, ad es. aggiunta di nuove pagine Web in cui è improbabile che nuove pagine possano influire sulle pagine esistenti.

As a result, a considerable amount of bugs escape to production, which I have to fix and in turn sets back my other projects.

Secondo la mia esperienza, sarebbe inaccettabile, quindi mi stai ponendo la domanda sbagliata. Invece di chiedere se i test renderebbero lo sviluppo più veloce dovresti chiedere cosa renderebbe lo sviluppo più privo di bug.

Una domanda migliore potrebbe essere:

  • Il testing delle unità è il giusto tipo di test, che devi evitare la "quantità considerevole di bug" che hai prodotto?
  • Esistono altri meccanismi di controllo / miglioramento della qualità (a parte i test unitari) da raccomandare o invece?

L'apprendimento è un processo a due fasi: impara a farlo abbastanza bene, quindi impara a farlo più rapidamente.

    
risposta data 16.06.2016 - 15:40
fonte
3

Alcuni aspetti da considerare, non menzionati nelle altre risposte.

  • Vantaggio extra / Costo extra dipende dall'esperienza con gli inventari di scrittura
    • con il mio primo progetto di test unitario i costi aggiuntivi sono stati triplicati perché ho dovuto imparare molto e ho fatto molti errori.
    • dopo 10 anni di esperienza con tdd ho bisogno del 25% in più di tempo di codifica per scrivere i test in anticipo.
  • con più tdd-modul c'è ancora bisogno di test manuale-gui-test e di integrazione
  • tdd funziona solo se fatto dall'inizio.
    • applicare tdd a un progetto già esistente è costoso / difficile. Ma puoi implementare invece i test di regressione.
  • test automatici (unittests e altri tipi di test) richiedono maintanace const per farli funzionare.
    • aver creato test tramite copia e incolla può rendere costoso il testcode-maintanace.
    • con l'esperienza crescente, il testcode diventa più modulare e più facile da mantenere.
  • con la crescente esperienza avrai la sensazione che valga la pena creare test automatici e quando no.
    • esempio non c'è un grande beneficio per l'unittest dei semplici getter / setter / wrapper
    • non scrivo test automatici tramite la gui
    • mi preoccupo che il business player possa essere testato

Riepilogo

Quando si inizia con tdd, è difficile raggiungere lo stato "più beneficio del costo" fintanto che si è in "ambiente di lavoro limitato nel tempo" soprattutto se ci sono "manager intelligenti" che ti dicono di "sbarazzarti delle costose e inutili prove"

Nota: con "test dell'unità" intendo "testare i moduli in isolamento".

Nota: con "test di regressione" intendo

  • scrivi del codice che produce un testo di output.
  • scrivi un codice di "test di regressione" che verifica che il risultato della generazione sia ancora lo stesso.
  • il test di regressione ti fa sapere quando cambia il risultato (che potrebbe essere ok o un indicatore per un nuovo bug)
  • l'idea di "test di regressione" è simile a approvaltests
    • ... scattare un'istantanea dei risultati e confermare che non sono stati modificati.
risposta data 15.06.2016 - 13:55
fonte
3

I programmatori, come le persone che hanno a che fare con la maggior parte delle attività, sottostimano il tempo necessario per completarlo. Con questo in mente, passare 10 minuti per scrivere un test può essere considerato come il tempo che si sarebbe potuto spendere per scrivere tonnellate di codice quando in realtà avresti speso quel tempo con lo stesso nome di funzione e i parametri che hai fatto durante il test . Questo è uno scenario TDD.

Non scrivere test, è come avere una carta di credito; tendiamo a spendere di più o scrivere più codice. Più codice ha più bug.

Invece di decidere di avere una copertura totale del codice o del tutto assenti, suggerisco di concentrarsi sulla parte critica e complicata della tua applicazione e di testare lì. In un'applicazione bancaria, potrebbe trattarsi del calcolo degli interessi. Uno strumento diagnostico del motore può avere complessi protocolli di calibrazione. Se hai lavorato su un progetto, probabilmente sai di cosa si tratta e dove sono i bug.

Inizia lentamente. Costruisci un po 'di fluidità prima di giudicare. Puoi sempre smettere.

    
risposta data 15.06.2016 - 14:09
fonte
3

C'è stata una lunga storia della scheda Programmer che promuove TDD e altre metodologie di test, non ricorderò i loro argomenti e sono d'accordo con loro, ma qui ci sono altre cose da considerare che dovrebbero sfumare un po ':

  • Il test non è altrettanto comodo ed efficiente a seconda del contesto. Sviluppo software web, dimmi se hai un programma per testare l'intera interfaccia utente ... in questo momento sto programmando excel macro, dovrei davvero sviluppare un modulo di test in VBA?
  • Scrivere e mantenere il software di test è un lavoro reale che conta nel breve termine (ripaga a lungo termine). Scrivere test rilevanti è anche una competenza per ottenere
  • Lavorare come una squadra e lavorare da soli, non ha gli stessi requisiti di test, perché nel team devi convalidare, comprendere e comunicare il codice che non hai scritto.

Direi che il test è buono, ma assicurati di testare prima e verificare dove si trova il guadagno.

    
risposta data 16.06.2016 - 13:51
fonte
1

Un vantaggio spesso trascurato di TDD è che i test fungono da salvaguardia per assicurarti di non introdurre nuovi bug quando apporti una modifica.

L'approccio TDD è indubbiamente più dispendioso in termini di tempo, ma il punto d'appoggio è che dovrai scrivere meno codice , il che significa meno cose da sbagliare. Tutti quei campanelli e fischietti che spesso includi, naturalmente, non faranno parte del codice base.

Nel film Swordfish c'è una scena in cui, se la memoria serve, un hacker deve lavorare con una pistola alla testa ed essere erm ... altrimenti distratto. Il punto è che è molto più facile lavorare quando il tuo spazio di testa è nel codice e hai tempo dalla tua parte piuttosto che mesi lungo la linea con un cliente che ti urla e altre priorità che vengono schiacciate.

Gli sviluppatori capiscono che correggere gli errori in un secondo momento è più costoso, ma capovolgerli. Se potessi essere pagato $ 500 al giorno per codificare come codifichi ora o $ 1000 se hai scritto in un modo TDD, ti mordere la mano dalla persona che ti rende la seconda offerta. Prima smetterai di vedere i test come un lavoretto e vedrai come un risparmio di denaro, meglio sarà.

    
risposta data 15.06.2016 - 12:26
fonte
0

Riesco a relazionarmi con la tua esperienza - la nostra base di codice non ha quasi avuto test ed è stata per lo più non testabile. Ci sono voluti letteralmente dei secoli per sviluppare qualcosa e correggere i bug delle produzioni, ci sono voluti tempo prezioso dalle nuove funzionalità.

Per una riscrittura parziale, ho promesso di scrivere test per tutte le funzionalità di base. All'inizio, ci è voluto molto più tempo e la mia produttività ha sofferto notevolmente, ma in seguito la mia produttività è stata migliore che mai.

Una parte di questo miglioramento era che avevo meno bug di produzione che a loro volta hanno portato a un minor numero di interruzioni - > Ho avuto una messa a fuoco migliore in qualsiasi momento.

Inoltre, l'abillity per testare il codice di debug in isolamento è davvero un bene - una suite di test è di gran lunga superiore a un sistema che non può essere debugato se non con l'installazione manuale, e. g. avvia la tua app e naviga sullo schermo e fai qualcosa ... forse qualche decina di volte

Notate che all'inizio c'è un calo della produttività, quindi iniziate ad imparare i test su alcuni progetti in cui la pressione del tempo non è già folle. Inoltre, prova ad avviarlo su un progetto greenfield, l'unità test del codice legacy è molto difficile, e aiuta quando sai come appare una buona suite di test.

    
risposta data 18.06.2016 - 17:41
fonte

Leggi altre domande sui tag