Progettazione di gestione delle eccezioni Java

1

Sto cercando di progettare una semplice strategia di gestione delle eccezioni per il middleware dei servizi web utilizzando alcune idee da qui: link .

Tuttavia penso valga la pena di avere due classi di eccezione che ereditano da RuntimeException invece di una sola.

L'idea è di usare una classe per rappresentare i guasti generali (NPE, ecc.) che non possono essere gestiti, e la mia strategia è di catturarli e registrarli in una singola barriera di errore in modo che gli sviluppatori / devOps possano risolverli . Queste eccezioni dovrebbero essere spostate e restituite per nascondere alcuni dettagli di implementazione agli utenti dell'API?

L'altra classe rappresenterà le eccezioni che dovrebbero essere restituite agli utenti dell'API poiché sono in attesa di esse e sanno come gestirle (ad esempio condizioni eccezionali specifiche che fanno parte di un'API di servizi Web).

Qualche svantaggio nell'usare queste due classi di eccezioni o è meglio usare solo una classe per tutto?

Grazie.

    
posta dabd 20.11.2014 - 15:49
fonte

4 risposte

6

Non penso che sia una buona idea. Questo introduce l'accoppiamento in un modo molto non ovvio.

Considera una classe o un servizio. Ha compiti chiaramente definiti, i suoi metodi sono ben documentati, possono essere scambiati per qualcos'altro che ha la stessa interfaccia / contratto.

Supponiamo che incontri un'eccezione. Il servizio quindi può decidere se è recuperabile o meno. Questo, di per sé, va bene - se il servizio determina che un errore è recuperabile, dovrebbe ripristinarlo. Fine della storia.

La tua versione è abbastanza diversa. Nella tua domanda stai dicendo "Il servizio decide se la situazione è recuperabile dal chiamante ". Questo non va bene. Come lo sa il tuo servizio? Perché si preoccupa per chi lo chiama? È solo richiamabile da un'altra classe molto specifica?

Si parla di NPE come "errore generale". Potrebbe non essere. Potrebbe trattarsi di una configurazione errata o di dati errati inviati da un utente malintenzionato, non degli errori del programmatore (alcuni potrebbero obiettare che è un errore del programmatore non tenere conto di questa possibilità, ma non è questo il punto qui). Un'eccezione IO è un "errore generale"? Potrebbe significare che è necessario utilizzare una connessione di backup (ripristino semplice), oppure qualcuno ha strappato la scheda di rete da un sistema live (non così semplice da recuperare). Nessuna delle tue classi, salva l'ultimo gestore di eccezioni del thread, può decidere se l'app può recuperare da qualcosa o meno.

Se modifichi il codice del chiamante per gestire un tipo di eccezione che precedentemente era "irrecuperabile", come sai che è necessario modificare la parte che genera questa eccezione?

L'altro punto su cui non sono d'accordo è:

...inheriting from RuntimeException...

...should be passed back to the users of the API since they are expecting them...

Non penso che questo sia un buon uso di eccezioni non controllate.

Se si suppone che gli utenti dell'API si aspettino tali eccezioni, perché non farle controllare e farle rispettare? Quindi le eccezioni non verificate si propagheranno fino in fondo e potrebbero essere registrate in un modo specifico - ciò significherà esattamente ciò che si desidera - Nessuno del codice chiamante si aspettava o poteva gestire questa eccezione . Mentre le eccezioni "previste" dovranno essere gestite, anche se il codice chiamante insiste sul fatto che tutto ciò che fa è registrarlo (o addirittura inghiottirlo silenziosamente).

Questo ha il vantaggio in più che le modifiche API sono documentate! Puoi aggiungere più "eccezioni previste" se sono in esecuzione - e nessuno le noterà fino a quando non è già in diretta! Anche se una volta selezionato, non sarai in grado di compilare se non ti occupi della situazione.

    
risposta data 20.11.2014 - 16:40
fonte
0

The idea is to use one class to represent general faults (NPE, etc.) that can't be handled in place, and my strategy is to catch and log them in a single fault barrier so developers/devOps can troubleshoot them. These exceptions should be wrapped and passed back hiding some implementation details to the users of the API?

Mi sembra che tu stia sbagliando. Non includere errori generali nel codice in altre eccezioni. Ciò renderà più difficile agli utenti della tua API capire cosa sta succedendo. Non creare le proprie barriere di errore o registrare eccezioni. L'intera applicazione Web dovrebbe avere una barriera di errore che registra tutte le eccezioni. Tutto ciò che puoi ottenere aggiungendo il tuo è registrare due volte le cose. Non aggiungere un altro per il tuo middleware.

    
risposta data 20.11.2014 - 16:38
fonte
0

The idea is to use one class to represent general faults

Non ci sono errori "generali". Ad esempio, NPE può essere lanciato manualmente, quindi non puoi nemmeno dire se è intenzionale o meno. Ci sono anche classi di eccezione usate male o qualcosa di cui non sai nulla. Come apparirebbe il "wrapping" nel codice? Immagino:

try {
    //...
} catch (ExceptionType1 e) {
    throw new MyException(e);
} catch (ExceptionType2 e) {
    throw new MyException(e);
} catch (...) {
    //...
} catch (ExceptionTypeN e) {
    throw new MyException(e);
}

Ne ho visto molto - è orribile da mantenere.

my strategy is to catch and log them in a single fault barrier

Solo la cattura e la registrazione non sono sempre nel modo giusto. Ecco le regole che cerco di usare:

  • Se l'eccezione può essere gestita, dovrebbe essere. Non è necessario comunicarlo a un utente, a meno che non possa essere gestito solo da un utente.
  • Se non può essere gestito, quindi:
    • Se è possibile fornire ulteriori informazioni sul contesto - avvolgerlo. L'eccezione wrapper deve accettare l'eccezione iniziale come causa ( getCause() ), quindi la traccia dello stack non è interrotta.
    • Se non sei in grado di fornire ulteriori informazioni, esegui di nuovo il test, perché potrebbe essere gestito da qualche parte sopra.

Cattura di livello superiore è una misura estrema nel caso in cui qualcosa di realmente inaspettato sia accaduto. Lo considero una rete di sicurezza che impedisce di mostrare brutte tracce dello stack agli utenti, che possono potenzialmente avere intenzioni malevole.

Le eccezioni dovrebbero essere registrate al più presto, fornendo un messaggio utile con informazioni sufficienti su un contesto per capire cosa è successo. Se viene rilevata e gestita un'eccezione, non è necessario registrare la traccia completa dello stack: sarebbe sufficiente un semplice avviso.

Considerare il messaggio di errore di registrazione e la traccia dello stack con diversi livelli di avviso: ad es. ERRORE per messaggio, DEBUG per traccia stack. In questo modo è possibile mantenere i registri puliti, trasformando il livello di registrazione DEBUG solo quando necessario per visualizzare i dettagli completi. Inoltre è possibile inserire i messaggi di registro con diversi livelli di registro in file di registro separati.

    
risposta data 20.11.2014 - 21:12
fonte
-1

Ne resterei fedele. Ogni volta che si dispone di un'eccezione che non è catastrofica, non è un'eccezione. Registrarlo per avvertire o il livello di errore, quindi andare avanti. Altrimenti, hai appena reinventato le eccezioni controllate.

    
risposta data 20.11.2014 - 15:56
fonte

Leggi altre domande sui tag