Come insegnare la gestione delle eccezioni per i nuovi programmatori? [chiuso]


21

Come si fa a insegnare la gestione delle eccezioni ai programmatori. Tutte le altre cose vengono insegnate facilmente - Strutture dati, ASP.NET, WinForms, WPF, WCF - lo chiami, tutto può essere insegnato facilmente.

Con la gestione delle eccezioni, insegnare loro try-catch-finalmente è solo la natura sintattica della gestione delle eccezioni.

Ciò che dovrebbe essere insegnato comunque è: quale parte del codice inserisci nel blocco try ? Cosa fai nel blocco catch ?

Vorrei illustrarlo con un esempio.

Stai lavorando a un progetto Windows Form (una piccola utility) e l'hai progettato come di seguito con 3 progetti diversi.

  1. UILayer
  2. BusinessLayer
  3. DataLayer

Se un'eccezione (diciamo del caricamento di un XDocument genera un'eccezione) viene sollevata in DataLayer (l'UILayer chiama BusinessLayer che a sua volta chiama DataLayer), fai semplicemente quanto segue

//In DataLayer
try {
    XDocument xd_XmlDocument = XDocument.Load("systems.xml");
} 
catch(Exception ex)
{
    throw ex;
}

quale viene lanciato di nuovo in BusinessLayer e che viene catturato in UILayer dove lo scrivo nel file di registro?

È così che ti occupi della gestione delle eccezioni?


15
Se stavate andando a fare questo, non si vuole catch (Exception ex) {tiro ex; } - prendi invece {lancio; }
Steven Evers,

4
Non dimentichiamoci finalmente dei blocchi?
Chris,

1
È necessario specificare la lingua nei tag. Stai entrando più nel dettaglio di quanto non sia comune alla maggior parte delle implementazioni delle eccezioni e ignori le cose al di fuori dei blocchi. In C ++, ad esempio, la parte più importante della gestione delle eccezioni è sapere come scrivere programmi sicuri per le eccezioni.
David Thornley,


Spero che tu sappia che è una cattiva idea catturare qualsiasi "eccezione". Dovresti avere blocchi di cattura nidificati per rilevare eccezioni specifiche e gestirle di conseguenza (non solo generare l'eccezione).
meno

Risposte:


29

Per spiegare la gestione delle eccezioni, spiegare il concetto alla base: Il codice in cui si verifica spesso un errore non sa come gestirlo correttamente. Il codice che sa come gestirlo correttamente potrebbe essere la funzione che lo ha chiamato, oppure potrebbe essere più in alto nello stack di chiamate.

Quando si scrive una routine che chiama una routine che potrebbe generare un'eccezione, se si sa come gestire correttamente l'errore, inserire la chiamata in un blocco try e inserire il codice di gestione degli errori nel blocco catch. In caso contrario, lascialo da solo e lascia che qualcosa sopra di te nello stack delle chiamate gestisca l'errore.

Dire "catch ex, throw ex" non è un buon modo per gestire le eccezioni, dal momento che in realtà non gestisce nulla. Inoltre, a seconda di come funziona il modello di eccezione nella tua lingua, ciò può effettivamente essere dannoso se cancella le informazioni di stack stack che potresti aver usato per eseguire il debug del problema. Lascia che l'eccezione si propaghi nello stack di chiamate fino a quando non raggiunge una routine che sa come gestirla.


4
+1 per "... dal momento che in realtà non gestire qualsiasi cosa", i nuovi utenti di gestire in modo spesso pensano eccezione di movimentazione mezzi di cattura e non si rendono conto se non si fa qualcosa per risolvere il problema, è non è la gestione delle eccezioni, solo gonfiare il codice.
Jimmy Hoffa,

13

Come la maggior parte delle cose, le eccezioni e la gestione delle eccezioni sembreranno probabilmente una soluzione alla ricerca di un problema per i nuovi programmatori fino a quando non mostrerai perché la soluzione apparentemente più semplice (codici di ritorno in stile C ed errno) funziona così male. Vorrei iniziare motivando il problema e inserendolo nel contesto. Mostra come è possibile eseguire la gestione degli errori utilizzando i codici di ritorno o le variabili globali / statiche. Quindi dare esempi del perché non funziona bene. Quindi e solo allora, introdurre eccezioni e spiegare che sono una forma di segnalazione fuori banda e che l'intero punto è che il comportamento predefinito se si ignora un'eccezione è passare il gruppo di chiamate in alto a qualcuno che può occupatene.

Bottom line: Mostrare come è stata fatta la gestione degli errori in C farà capire agli studenti a cosa servono davvero le eccezioni e perché catturare le eccezioni che non si possono realmente gestire sta fondamentalmente simulando il modo in cui sono state fatte le cose nel Medioevo.


2
+1 per la pratica dell'insegnamento di guidarli nei codici di ritorno e nei numeri di errore in stile C tradizionale e mostrare loro che funziona male e, quindi, insegnare loro come funzionerà è una cosa geniale!
Kanini,

3
@Kanini: In generale, penso che la maggior parte dei costrutti relativamente nuovi / di alto livello sembrano soluzioni alla ricerca di problemi e sono facili da usare sbagliati se non capisci quale problema avrebbero dovuto risolvere e perché sono stati inventati.
dsimcha,

Sono d'accordo che mostrare come sarebbe fatto senza eccezioni è buono, ma poi arriva l'onere di spiegare quando usare le eccezioni e quando usare altre tecniche (perché non tutte le situazioni sono eccezionali)
Matthieu M.

@Matthieu: giusto. Ma se capisci quali problemi storici le eccezioni devono risolvere, piuttosto che conoscerli nel vuoto, diventa più ovvio che è sciocco usarli per situazioni non eccezionali.
dsimcha,

giusto, ecco perché hai ottenuto il mio +1. Ho solo pensato che la tua risposta potesse essere interpretata come "non usare mai un altro meccanismo" :)
Matthieu M.

5

Vorrei iniziare con le Linee guida per la progettazione delle eccezioni, che sono brevi e include DO, DO NOT e EVITARE. Fornisce anche i motivi per cui.

Nel tuo esempio, la sezione revelvent sarebbe Wrapping Exceptions

E si aspetterebbe che sia scritto in questo modo. Si noti che rileva un'eccezione specifica e tenta di aggiungere informazioni in modo da propagare un messaggio più significativo. Si noti inoltre che l'eccezione interna è ancora mantenuta ai fini della registrazione

//In DataLayer

try
{
XDocument xd_XmlDocument = XDocument.Load("systems.xml");
}
catch(FileNotFoundException ex)
{
        throw new TransactionFileMissingException(
                     "Cannot Access System Information",ex);
}

AGGIORNAMENTO Kanini chiede che sia giusto avere questo blocco di eccezioni nel livello dati o se il controllo del file deve essere disponibile per il livello aziendale.

Bene, prima vorrei sottolineare che la logica di Wrapping Exceptions è questa

Prendi in considerazione la possibilità di racchiudere eccezioni specifiche generate da un livello inferiore in un'eccezione più appropriata, se l'eccezione del livello inferiore non ha senso nel contesto dell'operazione di livello superiore.

Quindi, se ritieni che avere un livello superiore debba conoscere il file, il tuo livello dati dovrebbe apparire così

//In DataLayer

XDocument xd_XmlDocument = XDocument.Load("systems.xml");

No Try No Catch.

Personalmente ritengo che, a meno che il tuo livello dati non sia in grado di fare qualcosa di utile come utilizzare un files.xml predefinito che è una risorsa di assemblaggio, non fare nulla o racchiudere l'eccezione è una buona scommessa poiché la tua registrazione ti dirà quale metodo e quale file è stato il problema. ( throw exin questo caso o anche il preferito lo throwfa ma non aggiunge alcun valore). Ciò significa che, una volta identificato, sarai in grado di risolvere rapidamente il problema.

Inoltre questo particolare esempio presenta anche il seguente problema in XDocument.Load può generare quattro esecuzioni

  • ArgumentNullException
  • SecurityException
  • FileNotFoundException
  • UriFormatException

Non possiamo garantire con sicurezza che il seguente codice non genererà FileNotFoundException, semplicemente perché potrebbe essere lì quando eseguiamo il controllo dell'esistenza e spariamo quando lo cariciamo. Avere questo a disposizione per il livello aziendale non sarebbe d'aiuto.

 if (File.Exists("systems.xml")) 
     XDocument.Load("systems.xml");

SecurityException è anche peggio perché tra le altre ragioni per cui viene lanciata se un altro processo prende un blocco di file esclusivo non otterrai l'errore fino a quando non provi ad aprirlo per la lettura perché non esiste un metodo File.CanIOpenThis (). E se esistesse un metodo del genere, hai ancora lo stesso problema di File.Exists


Correzione: grazie! Ma è anche giusto avere questo blocco di eccezioni nel livello dati? Dovresti controllare se il file è disponibile o no in Business Layer? Altrimenti, sono d'accordo con il tuo metodo di scrittura del codice.
Kanini,

Correzione: nella mia lingua madre, Kanini significa un computer mentre Kani significa un frutto ;-)
Kanini,

Posso dire che non sei troppo turbato dal mio errore, ma mi dispiace molto e l'ho corretto.
Conrad Frix,

1
Correzione: sconvolto? Affatto. In gran parte divertito. Mio fratello non ha smesso di ridere da quando glielo ho fatto notare principalmente perché, in ogni caso, non assomiglio ad un frutto, tranne forse per la forma strana ...
Kanini,

4

Facciamo un gioco di ruolo. (questo non è uno scherzo)

Dovresti fare un seminario in cui reciti la catena della chiamata. Ogni persona è un oggetto. Avrai bisogno di alcuni principianti e alcune persone che capiscono il "gioco" aiuta.

Usa un problema davvero semplice come il file IO. su GUI> modello-> file_io

La persona che è il lettore di file deve dirlo al prossimo ...

Per prima cosa fallo con i codici di ritorno. (usi i post-it?)

se le interazioni sono solo "ciò che dice il codice" abbastanza presto, puoi far capire alle persone che le eccezioni sono eccezionali.

per i codici di ritorno, passa una nota di post-it.

per eccezioni, lancia le mani in aria e dì qual è il problema.

poi inducili a fare "cattura x, lancia x" e vedo molto peggio la diagnosi è ciò che la GUI ottiene "il modello aveva un'eccezione".

Penso che questo funzionerà per formare le persone che hai perché le persone comprendono abbastanza bene le interazioni con altre persone.


+1 per l'idea del gioco di ruolo. Non ci abbiamo mai pensato prima. Chi avrebbe mai pensato che l'insegnamento della programmazione potesse essere fatto attraverso il gioco di ruolo?
Kanini,

1

Immagino di capire le eccezioni che devi prima comprendere, ad esempio, la relazione figlio / genitore delle classi. Se capisci che un bambino può ereditare la funzionalità da un genitore, potrebbe essere in grado di capire a livello elementare che se un bambino ha un problema che non può gestire, passerà questo problema (eccezione) al suo genitore e lascia che il genitore si occupi con esso.

Questo diventa una relazione incatenata fino a quando non si finisce con un posto in cui qualcosa sa come gestire l'eccezione.

E per quanto riguarda finalmente questa è la parte banale ... quando si verifica un problema qualcosa deve gestirlo in modo che il programma non esca fatalmente, dopo che viene gestita quell'eccezione il blocco finally è lì che verrà sempre eseguito indipendentemente dal tentativo di cattura .

Un buon esempio di ciò potrebbe essere con la rete:

  • facciamo connessione
  • la connessione è ok, quindi la usiamo
  • al termine chiudiamo e liberiamo risorse

o in casi eccezionali:

  • stabilire una connessione
  • si verifica un'eccezione che qualcosa gestisce
  • a quel punto liberiamo la connessione e le risorse associate

1

Dai un'applicazione al neofita che ha un'ottima gestione delle eccezioni al suo interno. Lancia qualche eccezione da qualche parte e lascia che eseguano il debug con l'aiuto di Logs. Tracciando la propagazione dell'eccezione dovrebbero essere in grado di eseguirne il debug. Esegui questo esercizio 3 o 4 volte. Ora rimuovi tutta la gestione delle eccezioni dal codice e lascia che provino a tenere traccia della stessa eccezione.

Credo che l'apprezzamento per il codice di gestione delle eccezioni sarà immediatamente apprezzato.


Suona come un piano. Hai qualche codice di esempio disponibile in Internet (per esempio, sourceforge.net) che consiglieresti?
Kanini,

0

IMO, dovresti pensare che le istruzioni di gestione delle eccezioni e di controllo del flusso siano sostanzialmente le stesse. Li usi per controllare il flusso dei tuoi programmi in base alla condizione in cui si trovano attualmente. La differenza è che la gestione delle eccezioni reagirà solo quando si verifica un errore (o un'eccezione).


@denny: Mentre sono d'accordo con "la gestione delle eccezioni reagirà solo quando si verifica un errore (o un'eccezione)", non sono del tutto sicuro dell'affermazione che "le istruzioni di gestione delle eccezioni e di controllo del flusso sono sostanzialmente le stesse". Non sono rispettosamente d'accordo. Il blocco di cattura fa certamente quello che dovrebbe fare in quella condizione. Il blocco try tuttavia non riguarda affatto il flusso o il controllo. Il blocco finally, di nuovo, non riguarda affatto il flusso o il controllo. Forse ho frainteso la tua risposta, ma puoi chiarire a beneficio di me e degli altri?
Kanini,

0

Probabilmente non aiuterebbe un nuovo programmatore, ma ho scoperto che ho capito molto meglio il concetto di eccezioni una volta che ho iniziato a usare le monadi nella programmazione funzionale. Una monade ti costringe a considerare ogni "canale" attraverso il quale i dati possono viaggiare all'interno o all'esterno di un programma, poiché tutto ciò che fornisce fornisce un'astrazione conveniente per "nascondere" parte di quel flusso di dati.

L'idea che una funzione possa avere diversi tipi di output e un'eccezione è come un tipo di ritorno con priorità più alta dalla funzione è piuttosto chiara.

Intendiamoci, capisco che non è il modo in cui funzionano le eccezioni nella maggior parte del linguaggio (dettagli di implementazione), ma in senso astratto, è quello che sta succedendo.


0

Fai finta che una scimmia stia usando la tastiera

Ero solito dire ai miei ragazzi quando scrivono codice per fingere che una scimmia siederà al keyborad e utilizzi questa applicazione.

Questo ha insegnato loro come anticipare ogni genere di cose:

  • Dati mancanti
  • File mancanti
  • Caratteri alfa quando ti aspetti i numeri
  • Divisione per zero

Penso che fosse la parola ritratto di avere una scimmia che batteva le chiavi e faceva tutto quello che voleva invece di seguirla bene. Ha funzionato per me.


Scimmie? Suppongo che i tuoi utenti non lo
abbiano

@Kanini - Buono. Quello era ai miei giorni del Corpo dei Marines. Volevo solo che i miei ragazzi pensassero fuori dagli schemi quando si trattava di intercettare errori. Ho appena detto errore trapping ... intendevo la gestione delle eccezioni.
Michael Riley - AKA Gunny
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.