Avvertimento! Il programmatore C ++ arriva qui con idee forse diverse su come gestire le eccezioni cercando di rispondere a una domanda che riguarda sicuramente un'altra lingua!
Data questa idea:
Ad esempio, immagina di avere una risorsa di recupero, che esegue la richiesta HTTP e restituisce i dati recuperati. E invece di errori come ServiceTemporaryUnavailable o RateLimitExceeded vorremmo solo sollevare un RetryableError che suggerisce al consumatore che dovrebbe semplicemente riprovare la richiesta e non preoccuparsi di errori specifici.
... una cosa che suggerirei è che potresti confondere le preoccupazioni relative alla segnalazione di un errore con azioni da intraprendere per rispondere ad esso in un modo che potrebbe degradare la generalità del tuo codice o richiedere molti "punti di traduzione" per le eccezioni .
Ad esempio, se modello una transazione che comporta il caricamento di un file, potrebbe non riuscire per una serie di motivi. Forse il caricamento del file comporta il caricamento di un plug-in che non esiste sul computer dell'utente. Forse il file è semplicemente corrotto e si è verificato un errore durante l'analisi.
Indipendentemente da ciò che accade, supponiamo che il corso dell'azione sia segnalare ciò che è accaduto all'utente e chiedergli cosa vuole fare al riguardo ("riprovare, caricare un altro file, annullare").
Thrower vs. Catcher
Tale linea di condotta si applica indipendentemente dal tipo di errore riscontrato in questo caso. Non è incorporato nell'idea generale di un errore di analisi, non è incorporato nell'idea generale di non riuscire a caricare un plug-in. È incorporato nell'idea di incontrare tali errori durante il preciso contesto di caricamento di un file (la combinazione di caricamento di un file e errore). Quindi, in genere, lo vedo, parlando rozzamente, come la catcher's
responsabilità di determinare il corso dell'azione in risposta a un'eccezione generata (es: sollecitare l'utente con le opzioni), non il thrower's
.
Detto in altro modo, i siti in cui le throw
eccezioni in genere mancano di questo tipo di informazioni contestuali, soprattutto se le funzioni che generano sono generalmente applicabili. Anche in un contesto totalmente degeneralizzato quando hanno queste informazioni, finisci per accaparrarti in termini di comportamento di recupero inserendole nel throw
sito. I siti che catch
sono quelli che generalmente hanno la maggior quantità di informazioni disponibili per determinare una linea di condotta e ti danno un posto centrale per modificare se tale linea di azione dovesse mai cambiare per quella determinata transazione.
Quando inizi a provare a generare eccezioni non riportando più ciò che è sbagliato ma cercando di determinare cosa fare, ciò potrebbe degradare la generalità e la flessibilità del tuo codice. Un errore di analisi non dovrebbe sempre portare a questo tipo di prompt, ma varia in base al contesto in cui viene generata tale eccezione (la transazione in cui è stata generata).
The Blind Thrower
In generale, gran parte del design della gestione delle eccezioni spesso ruota attorno all'idea di un lanciatore cieco. Non sa come verrà catturata l'eccezione o dove. Lo stesso vale per forme ancora più vecchie di recupero degli errori usando la propagazione manuale degli errori. I siti che riscontrano errori non includono un corso d'azione dell'utente, ma incorporano solo le informazioni minime per segnalare il tipo di errore riscontrato.
Responsabilità invertite e generalizzazione del ricevitore
Pensando più attentamente a questo, stavo cercando di immaginare il tipo di base di codice in cui questo potrebbe diventare una tentazione. La mia immaginazione (forse sbagliata) è che la tua squadra sta ancora giocando il ruolo di "consumatore" qui e implementando anche la maggior parte del codice chiamante. Forse hai molte transazioni disparate (molti try
blocchi) che possono incorrere tutti negli stessi insiemi di errori e tutti dovrebbero, dal punto di vista del design, portare a un corso uniforme di azione di recupero.
Tenendo conto dei saggi consigli della Lightness Races in Orbit's
buona risposta (che penso provenga davvero da una mentalità avanzata orientata alla biblioteca), potresti essere ancora tentato di gettare eccezioni "cosa fare", solo più vicino al sito di recupero delle transazioni.
Potrebbe essere possibile trovare qui un sito intermedio e comune di gestione delle transazioni che centralizzi effettivamente le preoccupazioni "cosa fare" ma nel contesto della cattura.
Ciò si applicherebbe solo se è possibile progettare un qualche tipo di funzione generale utilizzata da tutte queste transazioni esterne (es: una funzione che immette un'altra funzione da chiamare o una classe base di transazione astratta con comportamento scavalcabile che modella questo sito di transazione intermedio che esegue la sofisticata cattura ).
Tuttavia, si potrebbe essere responsabili della centralizzazione del corso d'azione dell'utente in risposta a una varietà di possibili errori, e comunque nel contesto della cattura piuttosto che del lancio. Esempio semplice (pseudocodice Python-ish, e non sono minimamente uno sviluppatore Python esperto quindi potrebbe esserci un modo più idiomatico di farlo):
def general_catcher(task):
try:
task()
except SomeError1:
# do some uniformly-designed recovery stuff here
except SomeError2:
# do some other uniformly-designed recovery stuff here
...
[Speriamo con un nome migliore di general_catcher
]. In questo esempio, è possibile passare a una funzione contenente l'attività da eseguire ma beneficiare comunque del comportamento di cattura generalizzato / unificato per tutti i tipi di eccezioni a cui si è interessati e continuare a estendere o modificare la parte "cosa fare" ti piace da questa posizione centrale e comunque in un catch
contesto in cui questo è in genere incoraggiato. Soprattutto, possiamo impedire ai siti di lancio di preoccuparsi di "cosa fare" (preservando la nozione di "lanciatore alla cieca").
Se non trovi nessuno di questi suggerimenti qui utili e c'è una forte tentazione di gettare comunque eccezioni "cosa fare", sii principalmente consapevole del fatto che questo è almeno molto anti-idiomatico, oltre a scoraggiare potenzialmente una mentalità generalizzata.