Rinviare un'eccezione solo perché hai deciso di registrarla utilizzando un blocco catch (il che significa che l'eccezione non è cambiata affatto) è una cattiva idea.
Uno dei motivi per cui utilizziamo le eccezioni, i messaggi di eccezioni e la sua gestione è che sappiamo cosa è andato storto e le eccezioni scritte in modo intelligente possono accelerare la ricerca del bug con un grande margine.
Ricorda anche che gestire le eccezioni costa molto più risorse di quante ne diciamo avere if
, quindi non dovresti gestirle tutte spesso solo perché ne hai voglia. Ha un impatto sulle prestazioni della tua applicazione.
È tuttavia un buon approccio utilizzare l'eccezione come mezzo per contrassegnare il livello dell'applicazione in cui è apparso l'errore.
Considera il seguente semi-pseudo codice:
interface ICache<T, U>
{
T GetValueByKey(U key); // may throw an CacheException
}
class FileCache<T, U> : ICache<T, U>
{
T GetValueByKey(U key)
{
throw new CacheException("Could not retrieve object from FileCache::getvalueByKey. The File could not be opened. Key: " + key);
}
}
class RedisCache<T, U> : ICache<T, U>
{
T GetValueByKey(U key)
{
throw new CacheException("Could not retrieve object from RedisCache::getvalueByKey. Failed connecting to Redis server. Redis server timed out. Key: " + key);
}
}
class CacheableInt
{
ICache<int, int> cache;
ILogger logger;
public CacheableInt(ICache<int, int> cache, ILogger logger)
{
this.cache = cache;
this.logger = logger;
}
public int GetNumber(int key) // may throw service exception
{
int result;
try {
result = this.cache.GetValueByKey(key);
} catch (Exception e) {
this.logger.Error(e);
throw new ServiceException("CacheableInt::GetNumber failed, because the cache layer could not respond to request. Key: " + key);
}
return result;
}
}
class CacheableIntService
{
CacheableInt cacheableInt;
ILogger logger;
CacheableInt(CacheableInt cacheableInt, ILogger logger)
{
this.cacheableInt = cacheableInt;
this.logger = logger;
}
int GetNumberAndReturnCode(int key)
{
int number;
try {
number = this.cacheableInt.GetNumber(key);
} catch (Exception e) {
this.logger.Error(e);
return 500; // error code
}
return 200; // ok code
}
}
Supponiamo che qualcuno abbia chiamato GetNumberAndReturnCode
e ricevuto il 500
codice, segnalando un errore. Chiamerebbe il supporto, che aprirà il file di registro e vedrebbe questo:
ERROR: 12:23:27 - Could not retrieve object from RedisCache::getvalueByKey. Failed connecting to Redis server. Redis server timed out. Key: 28
ERROR: 12:23:27 - CacheableInt::GetNumber failed, because the cache layer could not respond to request. Key: 28
Lo sviluppatore quindi conosce immediatamente quale livello del software ha causato l'interruzione del processo e ha un modo semplice per identificare il problema. In questo caso è fondamentale, perché il timeout di Redis non dovrebbe mai accadere.
Forse un altro utente chiamerebbe lo stesso metodo, ricevendo anche il 500
codice, ma il registro mostrerebbe quanto segue:
INFO: 11:11:11- Could not retrieve object from RedisCache::getvalueByKey. Value does not exist for the key 28.
INFO: 11:11:11- CacheableInt::GetNumber failed, because the cache layer could not find any data for the key 28.
Nel qual caso il supporto potrebbe semplicemente rispondere all'utente che la richiesta non era valida perché sta richiedendo un valore per un ID inesistente.
Sommario
Se gestisci le eccezioni, assicurati di gestirle nel modo corretto. Assicurati anche che le tue eccezioni includano i dati / messaggi corretti, in primo luogo, seguendo i livelli dell'architettura, in modo che i messaggi ti aiuteranno a identificare un problema che può verificarsi.