Non credo che le catture locali siano un anti-pattern, infatti se ricordo bene è effettivamente applicato in Java!
Ciò che per me è fondamentale quando si implementa la gestione degli errori è la strategia generale. Potresti desiderare un filtro che raccolga tutte le eccezioni al limite del servizio, potresti voler intercettarlo manualmente: entrambi vanno bene fintanto che esiste una strategia generale, che rientrerà negli standard di codifica dei tuoi team.
Personalmente mi piace catturare errori in una funzione quando posso fare una delle seguenti azioni:
- Aggiungi informazioni contestuali (come lo stato degli oggetti o cosa stava succedendo)
- Gestisci l'eccezione in modo sicuro (come un metodo TryX)
- Il tuo sistema sta attraversando un limite di servizio e chiama in una libreria o API esterna
- Vuoi catturare e rilanciare un diverso tipo di eccezione (forse con l'originale come eccezione interna)
- L'eccezione è stata generata come parte di alcune funzionalità di background di basso valore
Se non è uno di questi casi, non aggiungo un try / catch locale. Se lo è, a seconda dello scenario, posso gestire l'eccezione (ad esempio un metodo TryX che restituisce un falso) o ripensare in modo che l'eccezione venga gestita dalla strategia globale.
Ad esempio:
public bool TryConnectToDatabase()
{
try
{
this.ConnectToDatabase(_databaseType); // this method will throw if it fails to connect
return true;
}
catch(Exception ex)
{
this.Logger.Error(ex, "There was an error connecting to the database, the databaseType was {0}", _databaseType);
return false;
}
}
O un esempio di rethrow:
public IDbConnection ConnectToDatabase()
{
try
{
// connect to the database and return the connection, will throw if the connection cannot be made
}
catch(Exception ex)
{
this.Logger.Error(ex, "There was an error connecting to the database, the databaseType was {0}", _databaseType);
throw;
}
}
Quindi rilevi l'errore in cima allo stack e presenta all'utente un messaggio di facile utilizzo.
Indipendentemente dall'approccio che prendi, vale sempre la pena di creare test unitari per questi scenari, in modo da assicurarti che la funzionalità non cambi e interrompa il flusso del progetto in un secondo momento.
Non hai menzionato la lingua in cui lavori ma sei uno sviluppatore .NET e lo hai visto troppe volte per non menzionarlo.
NON SCRIVERE:
catch(Exception ex)
{
throw ex;
}
Usa:
catch(Exception ex)
{
throw;
}
Il primo reimposta la traccia dello stack e rende assolutamente inutile il tuo livello più alto!
TLDR
L'acquisizione locale non è un anti-pattern, può spesso far parte di un design e può aiutare ad aggiungere ulteriore contesto all'errore.