Granularità delle eccezioni


9

Ho incontrato un dibattito tra alcuni amici e I. Preferiscono eccezioni generali come ClientErrorExceptione ServerErrorExceptioncon i dettagli come campi dell'eccezione, mentre preferisco rendere le cose più specifiche. Ad esempio, potrei avere una manciata di eccezioni come:

  • BadRequestException
  • AuthenticationFailureException
  • ProductNotFoundException

Ognuno di questi costruito sulla base del codice di errore restituito dall'API.

A seguito dei vantaggi delle eccezioni questo sembra idiomatico a Java. Tuttavia, l'opinione dei miei amici non è esattamente insolita.

Esiste un modo preferito in termini di leggibilità del codice e usabilità dell'API o si riduce davvero alle preferenze?


La pagina che hai collegato è probabilmente la migliore risposta definitiva che possiamo ottenere. Stai chiedendo un parere, davvero. Posso rispondere con la mia esperienza e opinione, ma questa non è una risposta obiettiva.
marstato,

@marstato è giusto. Immagino di cercare una giustificazione nella mia posizione. Preferirei attenermi a ciò che la gente si aspetta dalle biblioteche che scrivo, piuttosto che seguire una guida se ciò significa che rende le mie cose più facili da usare, sai?

Sono assolutamente d'accordo. Ho anche le mie classi di eccezione granulari. Inoltre, è possibile definire abstracte generalizzare le classi di eccezione con i metodi getter e quindi estendere quelle granulari a quelle generali. Es AuthenticationFaliureException extends ClientErrorException. In questo modo, ogni utente può scegliere come gestire le eccezioni. Più lavoro però, ovviamente. Tuttavia, quando si scrive un'applicazione (anziché una libreria), è una situazione diversa IMHO. In tal caso, non renderei le eccezioni più granulari di quanto tu ne abbia bisogno, per motivi di semplicità.
marstato,

@marstato è così che lo implemento ora. Sono contento che tu sia d'accordo. Lascerò la domanda aperta tutta la notte, ma per favore consolidala in un post in modo che io possa almeno controllarti in verde

Risposte:


15

La differenza principale tra avere molte diverse classi di eccezioni e averne solo alcune, con informazioni più dettagliate nel testo dell'errore (ad esempio), è che molte diverse classi di eccezioni consentono al codice chiamante di reagire in modo diverso a diversi tipi di errori, pur avendo solo poche classi semplificano la gestione di tutti i tipi di eccezioni in modo uniforme.

Questo è in genere un compromesso. Può essere mitigato in una certa misura usando l'ereditarietà (una classe di eccezione di base generale per quei chiamanti che vogliono catturare e registrare tutto in modo generico e derivare eccezioni da quella classe di base per quei chiamanti che hanno bisogno di reazioni diverse), ma anche questo può produrre un molta complessità inutile se non stai attento e mantieni il principio YAGNI. Quindi la domanda guida dovrebbe essere qui:

  • Ti aspetti davvero che il chiamante del tuo codice reagisca in modo diverso, con diverso flusso di controllo, a questi diversi tipi di errori?

Non esiste una soluzione unica per questa soluzione, nessuna "best practice" di Braindead che puoi applicare ovunque. La risposta a questa domanda dipende fortemente dal tipo di software o componente che stai progettando:

  • qualche applicazione, in cui tu o il team hai l'intero codice di base sotto il tuo controllo?

  • o qualche componente riutilizzabile per terze parti, dove non conosci tutti i potenziali chiamanti?

  • un'applicazione server di lunga durata, in cui diversi tipi di errori non dovrebbero interrompere immediatamente l'intero sistema e potrebbero richiedere diversi tipi di mitigazione degli errori?

  • un processo applicativo di breve durata in cui è sufficiente in caso di errore visualizzare un messaggio di errore per l'utente e quindi riavviare il processo?

Quindi, più conosci i potenziali chiamanti del tuo componente, meglio puoi decidere il livello di dettaglio corretto per le tue eccezioni.


3
"Ti aspetti davvero che il chiamante del tuo codice reagisca in modo diverso, con un diverso flusso di controllo, a questi diversi tipi di errori?" questa è un'ottima domanda da porre Grazie, lo ricorderò.

Questa è una buona risposta, penso, vorrei solo sottolineare ulteriormente la necessità di consentire all'applicazione client di guidare il progetto di lancio delle eccezioni. Anche le generalizzazioni che potresti ritenere sensate da incorporare nella gerarchia delle eccezioni potrebbero non corrispondere ai modi in cui l'applicazione client (se non la stai scrivendo) potrebbe scegliere di generalizzare un gestore. Se hai più di un'applicazione client con esigenze diverse, ovviamente dipenderà da te bilanciarle.
magicduncan,

1

La risposta dipende dal livello di segnalazione degli errori di cui stiamo parlando.

In generale, sono d'accordo con i tuoi amici, non dovresti renderli più granulari del necessario per comunicare la causa del problema.

Se esiste un'eccezione comune e ben nota per il riferimento null (NullReferenceException), non è necessario creare MyObjectIsNullException. Ciò aggiungerebbe solo uno strato di confusione per l'interprete umano, un'altra cosa da imparare che non chiarisce nulla.

Solo quando la tua eccezione è quella speciale che non esiste una predefinita che copre la causa principale, puoi crearne una tua.

Tuttavia, non devi fermarti qui. L'errore comune può verificarsi in uno dei componenti e potresti voler comunicare che si è verificato un problema nel componente . Quindi non solo cosa è andato storto, ma anche dove. Quindi sarebbe opportuno racchiudere la prima eccezione in MyComponentException. Questo ti darà il meglio di entrambi i mondi.

Innanzitutto sarà chiaro che il tuo componente ha avuto problemi. Su una leva inferiore, la causa specifica sarebbe nell'eccezione interna.


È giusto. Quindi stai suggerendo di non inventare una nuova eccezione quando ne esiste già una buona?

@rec Sì, perché tutti conoscono già quelli predefiniti. Questo è ciò per cui sono lì.
Martin Maat,
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.