Debug di errori multipli

1

A volte mi sono imbattuto in errori che sono davvero difficili da debugare. Quindi la mia meta domanda è la seguente:

  1. Hai più blocchi di codice, diciamo A -> B -> C -> D
  2. Il tuo codice non si arresta in modo anomalo ma il risultato non è quello che ti aspettavi
  3. Ovviamente non sai da dove arriva l'errore, quindi hai provato a cambiare tutti i blocchi uno per uno per trovare il bug. Prima A a a ma si blocca il codice in modo da annullare le modifiche
  4. Poi provi lo stesso con B , C e D
  5. Ogni volta che cambi i blocchi, il tuo codice si rompe
  6. Quando le stelle sono allineate, hai cambiato due blocchi allo stesso tempo (ad esempio B e C ) e funziona ...

Quindi la mia domanda è: come possiamo evitare quelle situazioni?

Con i miei 5 anni di esperienza di programmazione, ho riscontrato solo il caso in cui devo cambiare due parti diverse del codice. (Immagina solo se devi aggiustare più di 2 blocchi di codice per vedere apparire il vero risultato.)

Non ho mai visto qualcuno parlare di questo argomento, ma forse non ho le parole giuste, quindi qualsiasi suggerimento per aiutarmi a raccogliere più informazioni su questo argomento è benvenuto.

    
posta Ice-Blaze 17.03.2017 - 23:00
fonte

3 risposte

5

Il tuo problema sembra essere causato dalla mancanza di comprensione del tuo codice. Il miglior consiglio che posso darti è imparare a leggere il codice (il tuo e scritto da altri), in modo che tu possa vedere cosa c'è di buono e di brutto.

Consigli pratici:

  1. Scrivi un codice comprensibile. Capire cosa è e non comprensibile di solito viene quando si impara a leggere il codice, da qui il mio consiglio sopra.
    1. Scomporre il codice in parti più piccole che sono più facili da capire. Usa nomi descrittivi per tutto.
    2. Usa il sistema dei tipi a tuo vantaggio. Ad esempio, se hai a che fare con numeri di telefono, crea una classe PhoneNumber invece di passare attorno alle stringhe.
    3. Evita la mutazione ; evitare lo stato globale o altrimenti implicito, quando possibile.
  2. Usa il debugger invece di cambiando materiale e vedendo cosa succede . Questo metodo che utilizzi è chiamato debug shotgun ed è noto per la bassa efficienza. Il debug passo dopo passo ti aiuterà a capire meglio le parti di livello più basso del tuo codice, dove la maggior parte dei bug si nasconde.
  3. Scrivi i test ogni volta che puoi per parti non banali della tua logica.
risposta data 17.03.2017 - 23:53
fonte
2

La mia risposta dovrebbe essere considerata complementare alle altre risposte. Ci sono altre cose che puoi fare per ridurre il tempo impiegato nel debugging. I programmatori efficienti dedicano poco tempo al debug, principalmente perché la maggior parte dei bug che si verificano vengono catturati rapidamente, dove sono facili da correggere, non nella catena di chiamate, e non da un cliente o un collega.

Punte:

  • Come dice scriptin, evita di mutare i dati: se la tua lingua ha parole chiave per impedire a una variabile o un campo di mutare (assegnandogli un nuovo valore), usa quelle parole il più possibile. Lo stato predefinito per tutti i campi deve essere immutabile, modificato per essere modificato solo quando necessario.
  • Quando è necessario modificare i dati, mantenere l'intervallo di mutazione (intervallo di valori possibili) il più piccolo possibile. Identificare gli invarianti (descritti sotto) aiuterà. Lo scopo di questo è di ridurre lo spazio degli stati del programma, che semplifica le prove, il test e il debug.
  • Riduci al minimo il numero di posti quando un campo specifico mutabile viene mutato.
  • Riduci al minimo il numero di punti nel tempo in cui i campi vengono modificati. Gli approcci di programmazione funzionale ti guideranno naturalmente in questa direzione.
  • Semplifica il più possibile il codice raccogliendo codice comune in metodi, funzioni o classi base.
  • Mantenere la lunghezza del codice più corta possibile ed evitare un'eccessiva ingegnerizzazione, evitando tecniche di progettazione di tipo cargo-cult. I motivi di progettazione superflui e "principi", applicati indiscriminatamente, sono i principali colpevoli.
  • Utilizza prove informali a ogni livello di astrazione, o almeno per le sezioni più critiche ai livelli più bassi.

Per usare le prove informali devi identificare tre cose, più volte:

  • Invarianti: per classi e sistemi nel loro insieme, identifica le cose che dovrebbero sempre essere vere. Ad esempio, forse un campo non dovrebbe mai deviare da determinati valori, o mai essere nullo.
  • Prerequisiti: per ciascun metodo, identificare ciò che deve essere vero prima dell'esecuzione del metodo.
  • Post-condizioni: per ogni metodo, identificare ciò che deve essere vero dopo l'esecuzione del metodo.

Al livello più alto, gli invarianti per il sistema (o sottosistema) nel suo insieme devono essere dimostrati in modo informale. Questo viene fatto esaminando ogni chiamata dall'alto verso il basso, usando le post-condizioni conosciute per dimostrare che gli invarianti hanno tenuto. Gli invarianti non devono essere veri all'interno del codice del metodo. Gli invarianti possono essere temporaneamente sospesi all'interno dei metodi, purché siano veri quando il metodo esce.

In alternativa, puoi iniziare dal fondo della catena di chiamate e determinare se le pre-condizioni saranno vere per ogni chiamata in aumento.

Idealmente fai qualche prova informale delle catene di chiamata prima di scrivere il codice.

Scrivi il codice per asserire (crash o generare eccezioni se non è vero) le pre-condizioni all'inizio di ogni metodo e le post-condizioni alla fine di ogni metodo. Se una di queste cose è troppo costosa da controllare in fase di esecuzione, fallo solo nelle build di debug.

Il risultato finale è che il tuo codice si bloccherà immediatamente non appena inizi a scriverlo. Questi sono errori o errori di specifica. L'arresto anomalo potrebbe richiedere una modifica agli invarianti, alle condizioni preliminari o alle condizioni successive. Ma tieni questi fatti il più "stretti" possibile; limitare il più possibile gli intervalli di stati del programma.

Troverai bug non appena avvii l'esecuzione del codice. Saranno comunque necessari test per esercitare completamente il codice.

Idealmente avremmo tutti compilatori di prova di controllo formali automatici, ma quel giorno sembra essere ancora distante in futuro.

Se questo sembra troppo lavoro, fallo solo per le sezioni di codice di basso livello e più critiche.

    
risposta data 18.03.2017 - 01:03
fonte
2

Le risposte esistenti sono davvero buone. Aggiungerei altri 2 punti:

  1. Lascia che il compilatore esegua il debug per te. Imposta il livello di avviso al livello più alto possibile e, se possibile, imposta gli avvisi come errori. Il tuo codice dovrebbe essere in grado di essere compilato senza avvisi di sorta. Ciò ridurrà il numero di piccoli errori logici e errori di battitura che si verificano nella compilazione.
  2. Utilizza un analizzatore statico per informarti su errori logici più difficili da trovare. Può dirti cose del genere che ti stai dimenticando di liberare memoria, o che non hai inizializzato una variabile quando si verifica una determinata condizione.

Inoltre, ci sono molti strumenti di debug oltre il debugger. La maggior parte dei sistemi dispone di strumenti in grado di tracciare allocazioni di memoria per aiutarti a trovare perdite o problemi di utilizzo dopo l'uscita. Strumenti come valgrind, disinfettante di indirizzi, ecc. Impara a usarli!

    
risposta data 20.03.2017 - 22:39
fonte

Leggi altre domande sui tag