Il codice di debug deve essere lasciato sul posto, sempre o aggiunto solo durante il debug e rimosso quando il bug è stato trovato?


35

Per esempio, aggiungo solo il codice di debug (come le istruzioni di stampa) quando sto cercando di individuare un bug. E una volta trovato, rimuovo il codice di debug (e aggiungo un caso di test che verifica specificamente quel bug). Sento che sta ingombrando il vero codice e quindi non ha spazio lì a meno che non stia eseguendo il debug.

Come si fa? Lasci il codice di debug in atto o lo rimuovi quando è obsoleto (che può essere difficile giudicare quando lo è)?

Risposte:


30

È necessario eliminare le dichiarazioni di stampa di debug; tuttavia, se è necessario aggiungerli per eseguire il debug di un problema di produzione, potrebbe valere la pena considerare se si dispone di informazioni sufficienti da inserire nel framework di registrazione. Informazioni su parametri, condizioni di errore e così via potrebbero essere utili in seguito quando viene visualizzato il bug successivo. L'utilizzo di un buon framework di registrazione in cui è possibile attivare il debug o la traccia dinamica dei messaggi di registro può essere molto utile in natura.


5
+1 Principalmente per aver menzionato la presenza di un ragionevole framework di debug. Se inizialmente è presente e ci sono vari livelli di debug, si spera che il codice di produzione possa essere eseguito senza chiamare costose routine di debug e che il codice di sviluppo possa essere eseguito con qualsiasi livello di controllo sia necessario, si spera sia registrato nel modo desiderato.
Orbling

1
D'accordo con Orbling. Inoltre, per il codice di debug diverso dalla sola visualizzazione delle informazioni che ha avuto un impatto sulle prestazioni o altri motivi non adatti alla produzione. (ad es. un'asserzione sul risultato della funzione, ad es. controllo del risultato di un ordinamento), è possibile prendere in considerazione due modalità di costruzione target. modalità di debug e modalità di rilascio.
Zekta Chan,

16

Il codice aggiunto specificamente per il debug deve essere rimosso dal software di produzione.

Che si tratti di rimozione completa o di essere inserito in sezioni di compilazione condizionale (come in C / C ++ / C #) dipende da te e dal tuo standard di codifica.

Ci sono diverse ragioni per questo:

  1. Potrebbero esserci conseguenze sulla sicurezza se questo codice viene eseguito o qualcuno può accedere al suo output.
  2. Potrebbe rallentare l'applicazione.
  3. Potrebbe essere fonte di confusione per gli altri sviluppatori che guardano il codice (o addirittura te stesso) 6 mesi dopo.

+1 per la compilazione condizionale, ma i blocchi di commenti funzioneranno in lingue che non li supportano. Non dovresti mai lasciarlo compilato in una versione prod, ma a volte è eccessivamente inefficiente continuare a eliminarlo completamente ogni volta che vuoi eliminare una build di rilascio.
Bill

1
Ho lavorato in ambienti in cui il codice C / C ++ veniva sempre compilato con opzioni di debug nel caso in cui fosse necessario eseguire il debug del codice di produzione o esaminare un coredump. A volte questo sempre pronto per il debug del mandato richiedeva che le dichiarazioni di debug fossero lasciate in modo che potessero essere attivate con un flag senza ricompilare il codice. Java consente sempre il debug se le opzioni JVM sono impostate per esso, quindi è necessario un lavoro di preparazione relativamente minore per eseguire il debug delle cose in un secondo momento.
Michael Shopsin

16

ChrisF e Alaric hanno entrambi punti validi; +1 per loro. Sono in grado di identificare almeno 5 diversi tipi di codice di debug che utilizzo.

  1. Utilizzo dei log per scaricare lo stato del sistema in un determinato momento.

    void function(...)
    {
        ...dump everything i know about.
    }
    
  2. Utilizzo dei registri per i punti di controllo dell'esecuzione.

    void function(...)
    {
        ...got here 1
        ...got here 2
    }
    
  3. Codice che impone effettivamente che una determinata condizione sia vera, ma rompe il comportamento normale. Esempio:

    • Supponiamo di avere alcuni registri relativi a un errore, ma non è possibile riprodurre il problema. È possibile provare a scrivere codice che imponga a determinate variabili di avere determinati valori che corrispondono alle informazioni nel registro.
  4. Registrazione di verifica: classificherei questo come una registrazione dettagliata che può essere utilizzata per convalidare la correttezza del software che non dovrebbe essere inclusa nella produzione, come ad esempio la convalida dei singoli passaggi di un algoritmo.

  5. Registrazione operazioni: fare riferimento al post di Alaric . Questo è praticamente ciò che intendo per "registrazione delle operazioni".

1, 2 e 3 dovrebbero essere eliminati completamente. Qualcosa come 4 probabilmente compilerei in modo condizionale dal codice. Per 5, Alaric ha avuto un grande punto sulla possibilità di disattivare dinamicamente i log. Questo potrebbe affrontare il punto di ChrisF nel suo secondo proiettile nella maggior parte dei casi.


1
Questo è un buon riassunto. Tuttavia, sarebbe meglio se si potesse formattare correttamente sostituendo 1)... con 1.... (in modo che la formattazione Markdown lo raccolga come un elenco) e indentando il codice di esempio di 8 spazi (di nuovo, in modo che Markdown lo raccolga come esempio codice all'interno di un elenco).
Konrad Rudolph,

@Konrad Rudolph: Fatto.
gablin

3

Dipende da cosa sta facendo il codice. Alcuni codici utilizzati per il debug possono essere lasciati così come sono e alcuni devono essere rimossi.

Il codice che verifica l'integrità dei parametri in un metodo non è sempre utile quando il codice funziona correttamente, ma spesso viene mantenuto per assicurarsi che il codice continui a funzionare correttamente.

A volte si scrive codice in modo diverso per semplificare il debug del codice, ad esempio calcolando un valore e inserendolo in una variabile locale, quindi si utilizza la variabile nella riga successiva, il che semplifica il controllo del risultato del calcolo quando si passa da un passo all'altro attraverso il codice. È possibile riscrivere il codice per utilizzare direttamente il valore calcolato, ma il costo dell'uso della variabile locale è così piccolo (se non del tutto) che non vi è motivo di riscrivere il codice. Inoltre, è utile lasciare invariato il codice dopo averlo testato, c'è sempre un piccolo rischio di introdurre un bug quando lo si modifica.

Il codice che aggiungi solo per rintracciare un bug specifico può spesso essere rimosso dopo aver trovato il bug.


2

Una volta utilizzavo molto codice di debug. Stavo quasi interamente prendendo di mira Windows, quindi c'era molto di questa funzione di output della stringa di debug che non ricordo più come si scrive, in modo da poter catturare la traccia con un particolare programma.

Rimaneva al suo posto un codice di debug, cose particolari che avevano lo scopo di fornire l'annidamento delle chiamate. Tuttavia, anche se la cosa della stringa di debug per lo più non sarebbe visibile su un sistema di produzione, era ancora tutto fatto sotto compilazione condizionale.

La realtà è, tuttavia, che tutto quel codice di debug è stato un grande sforzo per qualcosa che è idealmente gestito in un modo diverso - usando, ovviamente, un debugger. All'epoca, non ero così colpito dal debugger C ++ di Borland. Gli strumenti erano lì, ma troppo spesso davano risultati fuorvianti e l'uso del debugger non IDE (spesso necessario) significava memorizzare i tasti di scelta rapida, il che significava una distrazione dal lavoro da svolgere.

L'unica esperienza di debug che ho trovato che è peggio è GDB da riga di comando.

Essere un esperto con gli strumenti che usi ogni giorno è, ovviamente, importante - ma il debug non dovrebbe essere qualcosa che fai ogni giorno. Se usi il debugger così spesso stai bene con l'apprendimento di dozzine di comandi e / o scorciatoie da tastiera, mi sembra un po 'bandiera rossa.

Quando lavoravo in Visual Studio 7, tuttavia, era chiaro che il debug poteva essere molto pratico ed efficace. Se riesci a eseguire il debug in Visual Studio (incluse le versioni express), il debug è semplicissimo. Senza dubbio se riesci a trovare il front end GUI / IDE giusto, GDB è anche semplice ed efficace, anche se non ho ancora fatto quella ricerca.

C'è anche qualcosa da dire per i test unitari, con l'analisi della copertura usando gcov. Più sei sicuro del comportamento delle tue librerie, meno profondo deve essere il tuo debug - e meno spesso hai bisogno del debugger. E scrivere unit test è abbastanza ragionevole da fare quasi tutti i giorni.

Tool inaspettatamente importante = cmake, uno strumento di compilazione che mi consente di passare facilmente da un edificio all'altro per GCC e VC ++, tra le altre cose. Quindi posso fare i test delle mie unità e la copertura basata su gcov usando GCC, ma passare facilmente a VC ++ per usare il debugger.


Un debugger può essere piuttosto inutile se non pericoloso nelle applicazioni multi-thread, ma mi piace il tuo commento con bandiera rossa.
Pemdas,

@Pemdas - Non ho ancora avuto problemi seri in questo senso, anche se il multi-threading non è ovviamente adatto al debugger. Tuttavia, penso che gli strumenti giusti siano probabilmente una soluzione migliore del codice di debug in linea di principio. Sarebbe bello uno strumento di analisi statica in grado di individuare condizioni di gara, deadlock, condizioni in cui due thread possono combattere contemporaneamente sulla stessa memoria / risorsa e così via. Non ho idea di cosa sia disponibile in tal senso, anche se so che ci sono alcuni strumenti intelligenti là fuori. klee, per esempio - non lo capisco, ma la descrizione di base sembra molto impressionante.
Steve314

"Penso che gli strumenti giusti siano probabilmente una soluzione migliore del codice di debug in linea di principio" È un'affermazione pericolosa;). Avere strumenti che preformano alcune delle analisi potrebbe essere utile, ma temo che gli sviluppatori, specialmente quelli nuovi, inizino a diventare troppo dipendenti dagli strumenti, come qualcuno che ha bisogno di usare una calcolatrice per capire quale sia il 15% di 100.
Pemdas,

Essere troppo dipendenti dagli strumenti che non ho nemmeno studiato ma sembra improbabile. Nell'esempio della tua calcolatrice, sì, ma userò comunque OpenOffice Calc invece di scrivere il mio semplice foglio di calcolo. C'è un tempo per il codice di debug (anche con un debugger - ad esempio il tuo caso di creazione di condizioni bizzarre), ma se va oltre un certo punto, gli strumenti esistenti vincono. E quando si tratta di sottrarre il 15% da 115, userò anche quella calcolatrice - ciò che molte persone darebbero perché l'ovvia risposta (100) è sbagliato. Nel multithreading, ovviamente, le risposte giuste sono famose per essere talvolta sbagliate.
Steve314

1

La mia opinione su di esso: il codice di debug utilizzato per uccidere un bug all'interno del codice in questione che generalmente rimuovo completamente. Il codice di debug utilizzato per uccidere un bug derivante da forze esterne in genere semplicemente commento.


-1

Se il bug proviene dall'unità test o dall'interno, il codice di debug potrebbe essere rimosso del tutto. Ma se il bug proviene dalla produzione, è meglio che il codice di debug sia presente all'interno dei tag di compilazione. Metterlo all'interno dei tag di compilazione aiuterà gli altri sviluppatori a capire che questo codice è solo a scopo di debug.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.