Gestione degli errori: in caso di errori o errori del programma, ignorarli in silenzio

20

Sto scrivendo un semplice programma per trasmettere MIDI su una rete. So che il programma incontrerà problemi di trasmissione e / o altre situazioni eccezionali che non sarò in grado di prevedere.

Per la gestione delle eccezioni, vedo due approcci. Devo scrivere il programma in modo che:

  • fallisce con il botto quando qualcosa va storto o
  • dovrebbe semplicemente ignorare l'errore e continuare, a spese dell'integrità dei dati?

Quale approccio ci si aspetterebbe ragionevolmente da un utente?
C'è un modo migliore di gestire le eccezioni?

Inoltre, se la mia decisione sulla gestione delle eccezioni dovesse essere influenzata dal fatto che io abbia a che fare con una connessione di rete (ad esempio qualcosa in cui posso ragionevolmente aspettarmi di riscontrare problemi)?

    
posta Arlen Beiler 14.03.2013 - 13:13
fonte

9 risposte

34

Mai e poi mai dovresti ignorare un errore che il tuo programma incontra. Al minimo, devi registrarlo su un file o altro mecanismo per la notifica. potrebbe essere situazioni occasionali in cui vorrete ignorare un errore ma documentarlo! Non scrivere un blocco catch vuoto senza commenti che spieghino il motivo per cui è vuoto.

Se il programma dovrebbe fallire o meno dipende molto dal contesto. Se riesci a gestire l'errore con garbo, provaci. Se si tratta di un errore imprevisto, il programma si bloccherà. È praticamente la base della gestione delle eccezioni.

    
risposta data 14.03.2013 - 13:17
fonte
17

Non dovresti mai ignorare silenziosamente gli errori, perché il tuo programma è costruito su una serie di azioni che dipendono implicitamente da tutto ciò che è andato prima che loro andassero a posto. Se qualcosa va storto nel passaggio 3 e si tenta di continuare con il passaggio 4, il passaggio 4 inizierà a partire da presupposti non validi, il che rende più probabile che finirà per generare anche un errore. (E se lo ignori anche tu, allora il punto 5 genera un errore, e da lì cominciano le cose a valanga.)

Il fatto è che, man mano che gli errori si accumulano, alla fine ti imbatterai in un errore così grande che non puoi ignorarlo, perché consisterà in qualcosa che viene dato all'utente e che qualcosa sarà completamente sbagliato . Quindi gli utenti si lamentano del fatto che il tuo programma non funzioni correttamente e devi risolverlo. E se la parte "dare qualcosa all'utente" è al punto 28, e non hai idea che l'errore originale che sta causando tutto questo pasticcio era nel passaggio 3 perché hai ignorato l'errore nel passaggio 3, avrai un diamine una volta il debug del problema!

D'altra parte, se l'errore nel passaggio 3 fa esplodere tutto nella faccia dell'utente e genera un errore che dice SOMETHING WENT BADLY WRONG IN STEP 3! (o il suo equivalente tecnico, una traccia dello stack,) il risultato è lo stesso-- l'utente si lamenta del fatto che il programma non funzioni correttamente - ma questa volta sai esattamente dove iniziare a cercare quando lo correggi .

EDIT: in risposta ai commenti, se qualcosa va storto che hai anticipato e sai come gestire, è diverso. Ad esempio, in caso di ricezione di un messaggio non valido, non si tratta di un errore del programma; questo è "l'input fornito dall'utente che ha fallito la convalida". La risposta appropriata è quella di dire all'utente che ti sta dando input non validi, che è quello che sembra che tu stia facendo. Non è necessario arrestarsi in modo anomalo e generare una traccia dello stack in un caso del genere.

    
risposta data 14.03.2013 - 13:23
fonte
16

Ci sono altre opzioni tra "esplodere" e "ignorare".

Se l'errore è prevedibile ed evitabile, cambia il disegno o rifatta il codice per evitarlo.

Se l'errore è prevedibile ma non evitabile, ma sai cosa fare quando succede, poi prendi l'errore e gestisci la situazione. Ma fai attenzione a non usare eccezioni come controllo del flusso. E potresti voler registrare un avviso a questo punto, e magari avvertire l'utente se c'è qualche azione che potrebbero prendere per evitare questa situazione in futuro.

Se l'errore è prevedibile, inevitabile, e quando accade non c'è nulla che tu possa fare per garantire l'integrità dei dati, quindi devi registrare l'errore e tornare a uno stato sicuro (che, come altri hanno detto, può significare crash).

Se l'errore non è qualcosa che hai previsto, allora non puoi davvero essere sicuro di poter tornare a uno stato sicuro, quindi potrebbe essere preferibile eseguire solo il log e il crash.

Come regola generale, non notare alcuna eccezione a cui non puoi fare nulla, a meno che tu non stia solo pianificando di registrarlo e ripeterlo. E nei rari casi in cui un try-catch-ignore è inevitabile, almeno aggiungi un commento nel tuo catch catch per spiegare perché.

Vedi l'eccellente articolo di gestione delle eccezioni di Eric Lippert per ulteriori suggerimenti su categorizzazione e gestione delle eccezioni.

    
risposta data 14.03.2013 - 18:55
fonte
6

Queste sono le mie opinioni sulla domanda:

Un buon principio di partenza è fallire velocemente. In particolare, non si dovrebbe mai scrivere codice di gestione degli errori per qualsiasi errore per il quale non si conosce la causa esatta.

Dopo aver applicato questo principio è possibile aggiungere il codice di recupero per condizioni di errore specifiche che si verificano. È inoltre possibile introdurre diversi "stati sicuri" per tornare a. Annullare un programma è quasi sicuro, ma a volte potresti voler tornare ad un altro stato conosciuto. Un esempio è come un moderno sistema operativo gestisce un programma incriminato. Spegne solo il programma, non l'intero sistema operativo.

Fallendo velocemente e coprendo lentamente condizioni di errore sempre più specifiche, non si compromette mai l'integrità dei dati e ci si sposta costantemente verso un programma più stabile.

Errori di deglutizione, ovvero il tentativo di pianificare errori per i quali non si conosce la causa esatta e che quindi non hanno una specifica strategia di recupero, porta solo a un numero crescente di errori, saltando e aggirando il codice nel programma. Dal momento che non ci si può fidare che i dati precedenti siano stati elaborati correttamente, inizierai a vedere i controlli sparsi per dati errati o mancanti. La tua complessità ciclomatica sarà a spirale e ti ritroverai con una grande palla di fango.

Indipendentemente dal fatto che tu sia a conoscenza dei casi di insuccesso è meno importante. Ma se per esempio si tratta di una connessione di rete per la quale si conosce una certa quantità di stati di errore, rimandare l'aggiunta della gestione degli errori fino a quando non si aggiunge anche il codice di ripristino. Questo è in linea con i principi sopra delineati.

    
risposta data 14.03.2013 - 17:52
fonte
6

Non dovresti mai silenziosamente ignorare gli errori. E soprattutto non a scapito dell'integrità dei dati .

Il programma sta cercando di fare qualcosa. Se fallisce, devi affrontare il fatto e fare qualcosa su di esso. Quello che sarà qualcosa dipende da molte cose.

Alla fine l'utente ha richiesto al programma di fare qualcosa e il programma dovrebbe dire loro che non ha avuto successo. Ci sono molti modi in cui può farlo. Potrebbe interrompersi immediatamente, potrebbe persino ripristinare i passaggi già completati o, dall'altra parte, continuare e completare tutti i passaggi possibili e dire all'utente che questi passaggi hanno avuto esito positivo e gli altri non sono riusciti.

Il modo in cui si sceglie dipende da quanto i passaggi sono correlati e se è probabile che l'errore si ripresenti per tutti i passaggi futuri, che a loro volta potrebbero dipendere dall'errore esatto. Se è richiesta una strong integrità dei dati, è necessario eseguire il rollback fino all'ultimo stato coerente. Se stai solo copiando un sacco di file, puoi saltarne alcuni e dire semplicemente all'utente che questi file non possono essere copiati. Non devi saltare silenziosamente i file e dire niente all'utente.

Modifica degli annunci, l'unica differenza è che dovresti considerare di riprovare un certo numero di volte prima di mollare e dire all'utente che non ha funzionato, dal momento che è probabile che la rete abbia errori transitori che non si ripresenteranno se proverai di nuovo .

    
risposta data 14.03.2013 - 13:49
fonte
4

Esiste una classe di casi in cui ignorare gli errori è la cosa giusta da fare: quando non c'è nulla che potrebbe essere fatto sulla situazione e quando i risultati poveri e possibilmente errati sono migliori dei risultati.

Il caso di decodifica del flusso HDMI per scopi di visualizzazione è un caso del genere. Se il flusso è brutto è male, urlarlo non lo risolverà magicamente. Fai ciò che puoi per visualizzarlo e permetti allo spettatore di decidere se è tollerabile o meno.

    
risposta data 15.03.2013 - 00:50
fonte
1

La mia strategia è quella di distinguere tra errori di codifica (bug) ed errori di runtime e, per quanto possibile, rendere difficili gli errori di codifica.

I Bug devono essere corretti il prima possibile, quindi un approccio Design by Contract è appropriato. In C ++, mi piace controllare tutte le mie precondizioni (input) con asserzioni nella parte superiore della funzione al fine di rilevare il bug nel più breve tempo possibile e facilitare l'aggiunta di un debugger e correggere il bug. Se lo sviluppatore o il tester sceglie invece di provare a continuare a eseguire il programma, qualsiasi perdita di integrità dei dati diventa il loro problema.

E trovare modi per prevenire il bug, in primo luogo. Essere severi con cost-correct e scegliere i tipi di dati appropriati per i dati che terranno sono due modi per rendere difficile la creazione di bug. Fail-Fast è anche buono al di fuori del codice critico di sicurezza che ha bisogno di un modo per recuperare.

Per errori di runtime che potrebbero verificarsi con codice privo di bug, come errori di comunicazione di rete o seriali o file mancanti o corrotti:

  1. Registra l'errore.
  2. (Facoltativo) Tentativo di riprovare o ripristinare in altro modo dall'operazione.
  3. Se l'operazione continua a fallire o è irrecuperabile, segnala l'errore visibilmente all'utente. Quindi come sopra, l'utente può decidere cosa fare. Ricorda il Principio di almeno stupore , perché una perdita di integrità dei dati è sorprendente per l'utente a meno che tu non li abbia avvertiti prima tempo.
risposta data 09.11.2018 - 21:09
fonte
1

Non credo che un programma debba ignorare o causare il caos ogni volta che si verifica un problema.

Che cosa faccio del software interno che scrivo per la mia azienda ...

Dipende dall'errore, diciamo se è una funzione critica che sta inserendo dati in MySQL, ha bisogno di far sapere all'utente che ha fallito. Il gestore degli errori dovrebbe cercare di raccogliere tutte le informazioni e fornire all'utente un'idea di come correggere l'errore da sé in modo che possano salvare i dati. Mi piace anche fornire un modo silenzioso di inviarci le informazioni su dove cercano di salvare, quindi se il peggio peggiora, possiamo inserirlo manualmente dopo che il bug è stato corretto.

Se non è una funzione critica, qualcosa che può errore e non influisce sul risultato finale di ciò che stanno cercando di ottenere, potrei non mostrare loro un messaggio di errore, ma inviarlo un'email che lo inserisce automaticamente nel nostro software di tracciamento bug o un gruppo di distribuzione e-mail che avvisa tutti i programmatori dell'azienda in modo che siamo a conoscenza dell'errore, anche se l'utente non lo è. Questo ci permette di fissare il back-end mentre sul front-end nessuno sa cosa sta succedendo.

Una delle cose più grandi che cerco di evitare è avere il programma in crash dopo l'errore - non essere in grado di recuperare. Cerco sempre di dare all'utente la possibilità di continuare senza chiudere l'applicazione.

Credo che nessuno sappia del bug, non sarà mai riparato. Sono anche fermamente convinto della gestione degli errori che consente all'applicazione di continuare a funzionare una volta scoperto un errore.

Se l'errore è correlato alla rete - perché le funzioni non eseguono un semplice test di comunicazione di rete prima di eseguire la funzione per evitare l'errore in primo luogo? Quindi, basta avvisare l'utente che una connessione non è disponibile, verificare Internet ecc. Ecc. E riprovare?

    
risposta data 15.03.2013 - 02:45
fonte
0

Fallire è l'opzione giusta quando si ha motivo di pensare che lo stato generale del programma sia instabile e che qualcosa di brutto possa accadere se lo si lascia eseguire ora. In qualche modo "ignorandolo" (cioè, come altri hanno sottolineato, registrandolo da qualche parte o visualizzando un messaggio di errore all'utente, quindi procedendo) va bene quando si sa che, certo, l'operazione corrente non può essere eseguita, ma il programma può continua a correre.

    
risposta data 14.03.2013 - 14:05
fonte

Leggi altre domande sui tag