Ecco la mia filosofia di base (e altri pensieri casuali) sulle eccezioni.
Quando si chiama un metodo, si hanno certe aspettative su ciò che il metodo compirà. Formalmente, queste aspettative sono chiamate post-condizioni. Un metodo dovrebbe generare un'eccezione ogni volta che non riesce a soddisfare le sue postcondizioni.
Per utilizzare efficacemente questa strategia, è necessario disporre di una conoscenza limitata di Design by Contract e del significato delle pre e post-condizioni. Penso che sia una buona cosa sapere comunque.
Ecco alcuni esempi concreti. Il modello save
metodo di Rails:
model.save!
-- post-condition: The model object is saved.
Se il modello non viene salvato per qualche motivo, quindi un'eccezione deve essere sollevato perché il post-condizione non è soddisfatta.
model.save
-- post-condition: (the model is saved && result == true) ||
(the model is not saved && result == false)
Se save
in realtà non salva, poi il risultato restituito sarà false
, ma il post-condizione è ancora soddisfatta, quindi non fa eccezione.
Trovo interessante il fatto che il metodo save!
abbia una post-condizione molto più semplice.
Per quanto riguarda il salvataggio delle eccezioni, ritengo che un'applicazione debba disporre di punti strategici in cui vengono salvate le eccezioni. C'è poca necessità di salvataggio/rilancio per la maggior parte. L'unica volta in cui vorresti salvare e rilanciare è quando hai un lavoro a metà strada e vuoi annullare qualcosa per evitare uno stato parzialmente completo. I punti strategici di salvataggio dovrebbero essere scelti con cura in modo che il programma possa continuare con altri lavori, anche se l'operazione corrente non ha funzionato. I programmi di elaborazione delle transazioni dovrebbero semplicemente passare alla transazione successiva. Un'app Rails dovrebbe essere ripristinata ed essere pronta a gestire la prossima richiesta http.
La maggior parte dei gestori di eccezioni deve essere generica. Poiché le eccezioni indicano un errore di qualche tipo, il gestore deve solo prendere una decisione su cosa fare in caso di errore. Le operazioni di recupero dettagliate per eccezioni molto specifiche sono generalmente scoraggiate a meno che il gestore non sia molto vicino (call graph wise) al punto dell'eccezione.
Le eccezioni non devono essere utilizzate per il controllo di flusso, utilizzare throw/catch
per quello. Questo riserva eccezioni per le vere condizioni di fallimento.
(Una parentesi, perché io uso eccezioni per indicare fallimenti, ho quasi sempre utilizzare la parola chiave fail
piuttosto che la parola chiave raise
in Ruby. Fail
e raise
sono sinonimi in modo non v'è alcuna differenza se non che fail
communcates più chiaramente che il metodo L'unica volta che uso lo raise
è quando sto rilevando un'eccezione e la rilancio, perché qui sono non in errore, ma in modo esplicito e mirato a sollevare un'eccezione. Questo è un problema stilistico che seguo, ma io dubbio molte altre persone lo fanno).
Ecco qui, una memoria piuttosto sconclusionata sui miei pensieri sulle eccezioni.
Penso che questa domanda possa essere considerata off-topic, in quanto non è un problema specifico, quindi secondo me è più adatta ad esempio a [Programmers] (http://programmers.stackexchange.com/ –
@ m.cekiera quando si riferiscono ad altri siti, è spesso utile indicare che [il cross-posting è disapprovato] (http://meta.stackexchange.com/tags/cross-posting/info) – gnat
@ m.cekiera : In realtà, il problema è sorto da un problema specifico (sto scrivendo una libreria e voglio sollevare un'eccezione, quando un argomento passato a un metodo è fuori portata), ma ho pensato che fornire questa informazione non aiuta a rispondere alla domanda. Grazie comunque per il commento. – user1934428