Molte persone sembrano considerare il debug come un'arte, piuttosto che una scienza. Per quelli qui che lo trattano come una scienza, piuttosto che un'arte - quale processo (s) usi normalmente di fronte a un nuovo problema / bug / problema?
Molte persone sembrano considerare il debug come un'arte, piuttosto che una scienza. Per quelli qui che lo trattano come una scienza, piuttosto che un'arte - quale processo (s) usi normalmente di fronte a un nuovo problema / bug / problema?
Risposte:
In termini molto generali, quello che faccio è:
Prova a isolare il problema. Pensa a cosa è cambiato quando il bug è apparso per la prima volta. A cosa stai lavorando? Quale parte del codice stavi cambiando? Il 99% dei miei bug è stato risolto in questo modo. Di solito è qualcosa di sciocco.
Se ho un'idea di dove sia il problema, dai un'occhiata al codice che sembra essere la causa. Leggilo. Leggilo anche a voce alta. Mi chiedo: "Cosa sto cercando di ottenere?". Per alcuni tipi di problemi: potrebbe avere alcuni effetti collaterali o potrebbe essere influenzato dal codice in qualche altro posto in un modo a cui non avevo pensato?
Prova in vari modi per analizzare cosa non va, dove e quando (vedi sotto).
Se non ho ancora idea, controllo se una versione precedente della mia fonte ha lo stesso problema, provo a trovare quando nella mia timeline di sviluppo è apparso il problema per la prima volta. Per fare questo devi lavorare con un buon sistema di controllo della versione, come git (git ha una funzione chiamata bisect esattamente per questo tipo di debug).
Se ancora non ne ho idea, fai una pausa ... in realtà spesso aiuta.
Torna al tavolo da disegno - rivedi come dovrebbe funzionare il tuo programma e se questo ha davvero senso.
Dipende davvero dal tipo di problema, ma supponendo che io abbia un'idea generale di dove potrebbe essere il problema, quindi:
Se sospetto che il problema si trovi in una parte del codice / modifica recente, provo prima a rimuovere / commentare / modificare o qualsiasi altra cosa per far scomparire il bug rendendo il codice più semplice, quindi riportare il codice problematico e prendere un buona visione.
Esegui un debugger con punti di interruzione (se possibile) e dai un'occhiata a come i miei dati sembrano cercare di trovare quando inizia a comportarsi male, per avere un'idea migliore di dove le cose vanno male.
bzr qdiff
comando.
Cerco di utilizzare lo sviluppo test-driven ( TDD ). Scrivo un test che replica il bug, quindi provo a far passare il test. A volte l'atto di scrivere il test aiuta a trovare il bug.
Questo mi tiene fuori dal debugger per la maggior parte del tempo e fornisce test di regressione per impedire la reintroduzione del bug.
Alcuni link:
Ci sono un certo numero di definizioni per la parola scienza, ma sembra che tu possa riferirti a quello che potrebbe essere definito più accuratamente il " metodo scientifico ". Il metodo scientifico potrebbe essere riassunto come l'osservazione di alcuni fenomeni (presumibilmente un bug o un comportamento inatteso del programma), la formulazione di un'ipotesi o ipotesi per spiegare il comportamento e la sperimentazione più probabile per dimostrarlo (scrivere un test che riproduca il problema in modo affidabile).
I tipi di bug (fenomeni) che possono verificarsi sono praticamente infiniti e alcuni non richiedono necessariamente un processo ben definito. Ad esempio, a volte osservi un bug e sai immediatamente cosa lo ha causato semplicemente perché conosci molto bene il codice. Altre volte, sai che dato un certo input (azione, serie di passaggi, ecc.), Si verifica un risultato errato (crash, output errato, ecc.). In questi casi, spesso non richiede molto pensiero "scientifico". Qualche pensiero può aiutare a ridurre lo spazio di ricerca, ma un metodo comune è semplicemente quello di scorrere il codice in un debugger e vedere dove le cose sono andate male.
Le situazioni che trovo più interessanti e forse degne di un processo scientifico sono quelle in cui ti viene consegnato un risultato finale e ti viene chiesto di spiegare come è successo. Un esempio evidente di questi è una discarica. Puoi caricare il dump di arresto anomalo e osservare lo stato del sistema e il tuo compito è spiegare come è arrivato in quello stato. Il dump di crash (o core) può mostrare un'eccezione, un deadlock, un errore interno o uno stato "indesiderabile" come definito dall'utente (ad esempio, lentezza). Per queste situazioni, seguo generalmente i passaggi in questo senso:
Osservazione ristretta : studiare le informazioni che circondano direttamente il problema specifico, se applicabile. Le cose ovvie qui sono lo stack di chiamate, le variabili locali se riesci a vederle, le righe di codice che circondano il problema. Questo tipo di studio specifico sulla posizione non è sempre applicabile. Ad esempio, lo studio di un sistema "lento" potrebbe non avere una posizione di partenza ovvia come questa, ma un incidente o una situazione di errore interno avranno probabilmente un punto di interesse immediato e ovvio. Un passaggio specifico qui potrebbe essere quello di utilizzare strumenti come windbg (esegui! Analizza -v su un dump di crash caricato e guarda cosa ti dice).
Ampia osservazione : studiare altre parti del sistema. Esaminare lo stato di tutti i thread nel sistema, esaminare eventuali informazioni globali (numero di utenti / operazioni / articoli, transazioni / processi / widget attivi, ecc.), Informazioni di sistema (SO), ecc. Se l'utente ha fornito dettagli esterni , pensa a quelli associati a ciò che hai osservato. Ad esempio, se ti hanno detto che il problema si verifica ogni martedì pomeriggio, chiediti cosa potrebbe significare.
supporre: Questa è la parte veramente divertente (e non sono faceto sul fatto che sia divertente). Spesso richiede una grande quantità di pensiero logico al contrario. Può essere molto divertente pensare a come il sistema è arrivato allo stato attuale. Sospetto che questa sia la parte che molte persone considerano un'arte. E suppongo che potrebbe essere se il programmatore inizia a lanciare casualmente cose per vedere cosa si attacca. Ma con l'esperienza, questo può essere un processo abbastanza ben definito. Se pensi molto logicamente a questo punto, è spesso possibile definire possibili insiemi di percorsi che hanno portato a un determinato stato. So che siamo nello stato S5. Perché ciò accada, è necessario che si verifichino S4a o S4b e forse S3 prima di S4a, ecc. Più spesso, possono esserci più elementi che potrebbero portare a un determinato stato. A volte può essere utile scrivere su un blocco per appunti un semplice diagramma di flusso o di stato o una serie di passaggi relativi al tempo. I processi attuali qui varieranno notevolmente a seconda della situazione, ma in questo momento il pensiero serio (e il riesame delle fasi precedenti) spesso forniranno una o più risposte plausibili. Si noti inoltre che una parte estremamente importante di questo passaggio è l'eliminazione di cose impossibili. La rimozione dell'impossibile può aiutare a tagliare lo spazio della soluzione (ricorda cosa ha detto Sherlock Holmes su ciò che resta dopo aver eliminato l'impossibile). Si noti inoltre che una parte estremamente importante di questo passaggio è l'eliminazione di cose impossibili. La rimozione dell'impossibile può aiutare a tagliare lo spazio della soluzione (ricorda cosa ha detto Sherlock Holmes su ciò che resta dopo aver eliminato l'impossibile). Si noti inoltre che una parte estremamente importante di questo passaggio è l'eliminazione di cose impossibili. La rimozione dell'impossibile può aiutare a tagliare lo spazio della soluzione (ricorda cosa ha detto Sherlock Holmes su ciò che resta dopo aver eliminato l'impossibile).
Esperimento : in questa fase, prova a riprodurre il problema in base alle ipotesi derivate nel passaggio precedente. Se hai preso il pensiero serio nel passaggio precedente, questo dovrebbe essere molto semplice. A volte "imbroglio" e modifico la base di codice per aiutare un determinato test. Ad esempio, recentemente stavo indagando su un incidente che ho concluso proveniva da una condizione di gara. Per verificarlo, ho semplicemente messo un Sleep (500) tra un paio di righe di codice per consentire a un altro thread di fare le sue cose cattive al momento "giusto". Non so se questo è permesso nella scienza "reale", ma è perfettamente ragionevole nel codice che possiedi.
Se riesci a riprodurlo, è probabile che tu abbia quasi finito (tutto ciò che resta è il semplice passo per risolverlo ... ma è per un altro giorno). Assicurati di controllare il nuovo test nel sistema di test di regressione. E dovrei sottolineare che intendevo che quella precedente affermazione sul fatto che fosse semplice essere ironici. La ricerca di una soluzione e la sua attuazione possono richiedere un ampio lavoro. Ritengo che la correzione di un bug non faccia parte del processo di debug ma sia piuttosto uno sviluppo. E se la correzione è del tutto implicata, dovrebbe richiedere una certa quantità di progettazione e revisione.
Prova a ridurre il test case. Quando è abbastanza piccolo, di solito è più facile individuare il codice corrispondente che causa il problema.
È probabile che un nuovo check-in stia causando il problema e che la build giornaliera precedente andasse bene. In tal caso, il registro delle modifiche dal controllo del codice sorgente dovrebbe aiutarti a decidere chi catturare.
Inoltre, se ti interessa C / C ++, considera di eseguire valgrind o purificare per isolare i problemi relativi alla memoria.
La parte più difficile del debug è isolare il problema, in particolare quando il problema viene nascosto sotto diversi livelli. Al college ho studiato la registrazione musicale, e stranamente c'era una lezione di Studio Electronics che si applica direttamente qui. Userò il debug di un ambiente di studio come illustrazione del processo di debug sistematico.
Il codice di debug non è davvero così diverso. Il debug è molto più semplice quando il codice genera un'eccezione. È possibile tracciare all'indietro dalla traccia dello stack di quell'eccezione e impostare i punti di interruzione nelle posizioni chiave. Di solito subito dopo aver impostato una variabile o sulla linea che chiama il metodo che genera l'eccezione. È possibile che uno o più valori non siano corretti. Se non è giusto (un null quando non dovrebbe esserci, o il valore è fuori range), allora è un processo per scoprire perché non è giusto. I punti di interruzione in un IDE sono equivalenti ai punti di prova elettronici (progettati per la sonda di un contatore per controllare il circuito).
Ora, una volta che avrò attraversato quella parte difficile della scoperta di dove sia il mio vero problema, scriverò alcuni test unitari per verificarlo in futuro.
Per un approccio più pratico:
Se il bug è correlato a un'eccezione non gestita, guarda la traccia dello stack. Il riferimento nullo, l'indice fuori dai limiti ecc. E le tue eccezioni definite sono le più comuni, puoi assegnare questo bug a uno sviluppatore junior, è probabilmente facile e una buona esperienza di apprendimento.
Se ciò non accade su ogni macchina, è probabilmente una forma di problema di gara / threading. Questi sono super divertenti da rintracciare, mettere il tuo programmatore senior annoiato su di esso. Un sacco di registrazione, buona conoscenza e buoni strumenti lo fanno.
Un'altra grande classe di bug è quando il team di test o il / i cliente / i non gradiscono un comportamento particolare. Ad esempio, a loro non piace che tu decida di visualizzare gli ID utente o che durante la ricerca non ottieni il completamento automatico. Si tratta di bug autentici, considera la possibilità di avere una migliore gestione del prodotto e gli sviluppatori con una visione più ampia. Uno sviluppatore dovrebbe impiegare un tempo relativamente breve per "risolvere" questo problema se costruisce il sistema pensando all'espansione.
L'80% di tutti gli altri bug viene risolto disponendo di buoni sistemi di registrazione e raccogliendo informazioni sufficienti per risolverli. Utilizza la traccia incorporata con più livelli di sistemi di registrazione complessi come Log4Net / Log4J
i bug delle prestazioni sono una categoria a parte, la regola golder qui è "misura prima, correggi dopo!", e rimarrai sorpreso nel vedere quanti sviluppatori indovinano dove si trova il problema e vai subito a risolverlo solo per vedere successivamente una riduzione del 3-4% nei tempi di risposta.
Ho due approcci di flusso:
Divide and Conquer
Paradigma.Questo approccio mi ha aiutato la maggior parte delle volte.