it-swarm.it

Come eseguire il debug del codice nel modo più efficace?

I bug che si insinuano nel codice possono essere minimizzati, ma non completamente eliminati come è scritto - i programmatori sono, sebbene molti sarebbero in disaccordo , solo umani.

Quando rileviamo un errore nel nostro codice, cosa possiamo fare per eliminarlo? Come dovremmo affrontarlo per sfruttare al meglio il nostro tempo prezioso e consentirci di dedicare meno tempo alla ricerca di esso e più tempo alla programmazione? Inoltre, cosa dovremmo evitare durante il debug?

Nota qui che non stiamo parlando di prevenire bug; stiamo parlando di cosa fare quando compaiono dei bug . Questo è un campo ampio, lo so, e può dipendere fortemente dal linguaggio, dalla piattaforma e dagli strumenti. In tal caso, continua a comprendere risposte come mentalità e metodi generali.

33
gablin

La mentalità e l'atteggiamento nei confronti del debug è forse la parte più importante, perché determina l'efficacia con cui risolverai l'errore e cosa imparerai da esso, se non altro.

I classici sullo sviluppo del software come The Pragmatic Programmer e Code Complete sostengono sostanzialmente lo stesso approccio: ogni errore è un'opportunità per imparare, quasi sempre su di te (perché solo i principianti danno la colpa prima al compilatore/al computer).

Quindi trattalo come un mistero che sarà interessante da decifrare. E spezzare quel mistero dovrebbe essere fatto sistematicamente, esprimendo i nostri presupposti (a noi stessi o agli altri) e quindi testando i nostri presupposti, uno per uno, se necessario, utilizzando tutti gli strumenti a nostra disposizione, in particolare i debugger e i framework di test automatizzati. Quindi, dopo che il mistero è stato risolto, puoi fare ancora meglio cercando in tutto il tuo codice gli errori simili che potresti aver commesso; e scrivere un test automatizzato per garantire che l'errore non si verifichi nuovamente inconsapevolmente.

Un'ultima nota - preferisco chiamare errori "errori" e non "bug" - Dijkstra ha rimproverato i suoi colleghi per aver usato quest'ultimo termine perché è disonesto, sostenendo l'idea che le fate dannose e volubili hanno piantato bug nei nostri programmi mentre eravamo guardare, invece di essere lì a causa del nostro pensiero (sciatto): http://www.cs.utexas.edu/users/EWD/transcriptions/EWD10xx/EWD1036.html

Potremmo, ad esempio, iniziare a ripulire la nostra lingua non chiamando più un bug un bug ma chiamandolo un errore. È molto più onesto perché mette esattamente la colpa a cui appartiene, vale a dire. con il programmatore che ha commesso l'errore. La metafora animistica del bug che si insinuava maliziosamente mentre il programmatore non stava guardando è intellettualmente disonesta in quanto nasconde che l'errore è la creazione stessa del programmatore. La cosa bella di questo semplice cambio di vocabolario è che ha un effetto così profondo: mentre, prima, un programma con un solo bug era "quasi corretto", dopo un programma con un errore è semplicemente "sbagliato" (perché in errore).

38
limist
  1. Scrivi test. Il test non è solo ottimo per prevenire i bug (nella mia esperienza, TDD fatto correttamente elimina quasi tutti i bug banali e stupidi), ma aiuta anche molto nel debugging. I test costringono il tuo progetto ad essere piuttosto modulare, il che rende molto più semplice isolare e replicare il problema. Inoltre, controlli l'ambiente, quindi ci saranno molte meno sorprese. Inoltre, una volta che si verifica un caso di test fallito, si può essere ragionevolmente sicuri di aver inchiodato il motivo reale del comportamento che ti dà fastidio.

  2. Scopri come usare un debugger. Le istruzioni print possono funzionare ragionevolmente bene ad un certo livello, ma un debugger il più delle volte è molto utile (e una volta che sai come usalo, è molto più comodo delle istruzioni print).

  3. Parla di qualcuno del tuo problema, anche se è solo un paperella di gomma . Costringersi ad esprimere il problema su cui si sta lavorando a parole fa davvero miracoli.

  4. Concediti un limite di tempo. Se, ad esempio, dopo 45 minuti senti di non andare da nessuna parte, passa ad altre attività per qualche tempo. Quando torni al tuo bug, si spera che tu possa vedere altre possibili soluzioni che non avresti considerato prima.

16
Ryszard Szopa

C'è un eccellente libro che ho letto su questo argomento chiamato Why Programs Fail , che delinea varie strategie per trovare i bug che vanno dall'applicazione del metodo scientifico per isolare e risolvere un bug, al delta debugging. L'altra parte interessante di questo libro è che elimina il termine "bug". L'approccio di Zeller è:

(1) Un programmatore crea un difetto nel codice. (2) Il difetto provoca un'infezione (3) L'infezione si propaga (4) L'infezione provoca un fallimento.

Se vuoi migliorare le tue abilità di debug, consiglio vivamente questo libro.

Nella mia esperienza personale, ho trovato molti bug nella nostra applicazione, ma il management semplicemente ci spinge in avanti per ottenere nuove funzionalità. Ho sentito spesso "Abbiamo trovato questo bug da soli e il client non lo ha ancora notato, quindi lascialo fino a quando non lo fanno". Penso che essere reattivi rispetto a proattivi nel correggere i bug sia una pessima idea, poiché quando arriva il momento di mettere effettivamente una soluzione, hai altri problemi che devono essere risolti e più funzioni di gestione vogliono uscire dalla porta il più presto possibile, quindi rimani sorpreso in un circolo vizioso che può portare a una grande quantità di stress, a esaurirsi e, infine, a un sistema guidato da difetti.

La comunicazione è anche un altro fattore quando vengono rilevati dei bug. Inviare un'e-mail o documentarla sul bug tracker va bene e va bene, ma nella mia esperienza, altri sviluppatori trovano un bug simile e invece di riutilizzare la soluzione che hai messo per correggere il codice (poiché si sono dimenticati di tutto ), aggiungono le loro versioni, quindi hai 5 diverse soluzioni nel tuo codice e di conseguenza sembra più gonfio e confuso. Quindi, quando risolvete un bug, assicuratevi che alcune persone rivedano la correzione e vi forniscano un feedback nel caso in cui abbiano risolto qualcosa di simile e trovato una buona strategia per affrontarla.

limist ha menzionato il libro The Pragmatic Programmer che contiene materiale interessante sulla correzione di bug. Usando l'esempio che ho dato nel paragrafo precedente, guarderei questo: Software Entrophy , dove viene usata l'analogia di una Vedova spezzata. Se compaiono due finestre rotte, la tua squadra potrebbe diventare apatica per non correggerlo mai a meno che tu non prenda una posizione proattiva.

3
Desolate Planet

Mi piacciono la maggior parte delle altre risposte, ma ecco alcuni suggerimenti su cosa fare PRIMA di farlo. Ti farà risparmiare tempo.

  1. Determina se esiste davvero un bug. Un bug è SEMPRE una differenza tra comportamento del sistema e requisiti; il tester dovrebbe essere in grado di articolare il comportamento previsto e reale. Se non è in grado di fornire supporto per il comportamento previsto, non vi è alcun requisito e non esiste alcun bug: solo l'opinione di qualcuno. Mandalo indietro.

  2. Considera la possibilità che il comportamento previsto sia sbagliato. Ciò potrebbe essere dovuto a un'interpretazione errata del requisito. Potrebbe anche essere dovuto a un difetto del requisito stesso (un delta tra un requisito dettagliato e un requisito aziendale). Puoi anche rispedirli.

  3. Isolare il problema. Solo l'esperienza ti insegnerà il modo più veloce per farlo: alcune persone possono quasi farlo con il loro intestino. Un approccio di base è quello di variare una cosa mantenendo tutte le altre cose costanti (il problema si verifica in altri ambienti? Con altri browser? In una regione di test diversa? In diversi momenti della giornata?) Un altro approccio è quello di esaminare i dump dello stack o messaggi di errore - a volte puoi dire solo dal modo in cui è formattato quale componente del sistema ha generato l'errore originale (ad esempio se è in tedesco puoi dare la colpa a quella terza parte con cui lavori a Berlino).

  4. Se è stato ridotto a due sistemi che collaborano, ispezionare i messaggi tra i due sistemi tramite il monitor del traffico o i file di registro e determinare quale sistema si sta comportando in base alle specifiche e quale no. Se nello scenario sono presenti più di due sistemi, è possibile eseguire controlli a coppie e spostarsi verso il basso nello stack dell'applicazione.

  5. Il motivo per cui isolare il problema è così critico è che il problema potrebbe non essere dovuto a un difetto del codice su cui si ha il controllo (ad esempio sistemi di terze parti o l'ambiente) e si desidera far sì che quella parte prenda il controllo il più rapidamente possibile . Ciò serve sia a risparmiare lavoro che a metterli immediatamente al punto in modo che la risoluzione possa essere raggiunta nel minor tempo possibile. Non vuoi lavorare su un problema per dieci giorni solo per scoprire che è davvero un problema con il servizio web di qualcun altro.

  6. Se si è determinato che esiste davvero un difetto ed è realmente nel codice che si controlla, è possibile isolare ulteriormente il problema cercando l'ultimo build "noto" e ispezionando i registri di controllo del codice per le modifiche che potrebbero aver causato il problema. Questo può far risparmiare molto tempo.

  7. Se non riesci a capirlo dal controllo del codice sorgente, ora è il momento di collegare il tuo debugger e scorrere il codice per capirlo. Ormai è probabile che tu abbia una buona idea del problema.

Una volta che sai dove si trova il bug e puoi pensare a una correzione, ecco una buona procedura per risolverlo:

  1. Scrivi un test unitario che riproduca il problema e fallisca.

  2. Senza modificare il test unitario, fallo passare (modificando il codice dell'applicazione).

  3. Mantenere il test unitario nella suite di test per prevenire/rilevare la regressione.

3
John Wu

Bug, errore, problema, difetto - qualunque cosa tu voglia chiamarlo, non fa molta differenza. Attaccherò al problema poiché è quello a cui sono abituato.

  1. Capire qual è la percezione del problema: tradurre da "Bob non è ancora nel sistema" di un cliente in "Quando provo a creare un record utente per Bob, fallisce con un'eccezione chiave duplicata, sebbene Bob non sia già lì dentro'
  2. Scopri se è davvero un problema o solo un malinteso (in effetti, Bob non è lì, non c'è nessuno chiamato bob e insert dovrebbe funzionare).
  3. Prova a ottenere passaggi affidabili minimi che puoi seguire per riprodurre il problema, ad esempio "Dato un sistema con un record utente" Bruce ", quando viene inserito un record utente" Bob ", si verifica un'eccezione"
  4. Questo è il tuo test - se possibile, mettilo in un cablaggio di test automatizzato che puoi eseguire ancora e ancora, questo sarà prezioso durante il debug. Puoi anche far parte della tua suite di test per garantire che quel particolare problema non riappaia in seguito.
  5. Ottieni il tuo debugger e inizia a creare punti di interruzione: scopri il percorso del codice quando esegui il test e identifica cosa non va. Mentre lo fai, puoi anche affinare il test rendendolo il più stretto possibile - idealmente un test unitario.
  6. Risolvilo: verifica i passaggi del test.
  7. Verifica che anche il problema originale descritto dal cliente sia risolto (molto importante: potresti aver risolto solo un sottoinsieme del problema). Verifica di non aver introdotto regressioni in altri aspetti del programma.

Se hai familiarità con il codice o se il problema o la correzione sono evidenti, puoi saltare alcuni di questi passaggi.

Come dovremmo affrontarlo per sfruttare al meglio il nostro tempo prezioso e consentirci di dedicare meno tempo alla ricerca di esso e più tempo alla programmazione?

Ne dubito, poiché implica che scrivere un nuovo codice è una mossa preziosa che avere un programma di lavoro di alta qualità. Non c'è niente di sbagliato nell'essere il più efficace possibile nel risolvere i problemi, ma un programma non migliora necessariamente semplicemente aggiungendo più codice ad esso.

3
ptyx

Penso che anche la riproduzione di un bug sia importante. Tutti i casi che riproducono il bug possono essere elencati e quindi puoi assicurarti che la correzione del bug copra tutti quei casi.

3
aslisabanci

Quando rileviamo un errore nel nostro codice, cosa possiamo fare per eliminarlo? Come dovremmo affrontarlo per sfruttare al meglio il nostro tempo prezioso e consentirci di dedicare meno tempo alla ricerca di esso e più tempo alla programmazione? Inoltre, cosa dovremmo evitare durante il debug?

Supponendo che ti trovi in ​​un ambiente di produzione, ecco cosa devi fare:

  1. Descrivere correttamente "l'errore" e identificare gli eventi che lo causano.

  2. Determina se "errore" è un errore di codice o un errore di specifica. Ad esempio, l'immissione di un nome di 1 lettera può essere considerata un errore per alcuni sistemi ma un comportamento accettabile per altri sistemi. A volte un utente segnala un errore che ritiene essere un problema, ma le aspettative dell'utente per il comportamento del sistema non facevano parte dei requisiti.

  3. Se hai dimostrato che si è verificato un errore e l'errore è dovuto al codice, puoi determinare quali parti di codice devono essere riparate per evitare l'errore. Esaminare anche l'effetto del comportamento sui dati attuali e sulle operazioni future del sistema (analisi dell'impatto su codice e dati).

  4. A questo punto probabilmente avresti una stima di quante risorse verranno consumate per correggere il bug. Puoi risolverlo immediatamente o pianificare una correzione in una prossima versione del software. Ciò dipende anche dal fatto che l'utente finale sia disposto a pagare per la correzione. È inoltre necessario valutare diverse opzioni disponibili per correggere l'errore. Potrebbe esserci più di un modo. È necessario selezionare l'approccio più adatto alla situazione.

  5. Analizzare i motivi che hanno causato la visualizzazione di questo errore (requisiti, codifica, test, ecc.). Applicare processi che impediscano il ripetersi della condizione.

  6. Documentare adeguatamente l'episodio.

  7. Rilascia la correzione (o la nuova versione)

1
NoChance

Ecco come lo faccio:

  1. utilizzare lo stesso metodo ogni volta per trovare il problema. Ciò migliorerà il tempo di reazione agli errori.
  2. Il modo migliore è probabilmente leggere il codice. Questo perché tutte le informazioni sono disponibili nel codice. Hai solo bisogno di modi efficaci per trovare la posizione corretta e la capacità di comprendere tutti i dettagli.
  3. il debug è molto lento e necessario solo se i programmatori non comprendono ancora come il computer esegue le istruzioni asm/non sono in grado di comprendere le pile di chiamate e le cose di base
  4. Prova a sviluppare tecniche di prova come l'uso di prototipi di funzioni per ragionare sul comportamento del programma. Ciò contribuirà a trovare più rapidamente la posizione corretta
1
tp1