Volver a lanzar una excepción solo porque decidió iniciar sesión utilizando un bloque catch (lo que significa que la excepción no ha cambiado en absoluto) es una mala idea.
Una de las razones por las que usamos excepciones, mensajes de excepciones y su manejo es para que sepamos qué salió mal y las excepciones escritas inteligentemente pueden acelerar la búsqueda del error por un gran margen.
También recuerde, manejar excepciones cuesta mucho más recursos que, digamos, tener un if
, por lo que no debería manejarlos todos a menudo solo porque lo desee. Tiene impacto en el rendimiento de su aplicación.
Sin embargo, es un buen enfoque utilizar la excepción como un medio para marcar la capa de aplicación en la que apareció el error.
Considere el siguiente semi-pseudocódigo:
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
}
}
Supongamos que alguien ha llamado GetNumberAndReturnCode
y recibido el 500
código, señalando un error. Llamaría al soporte, quien abriría el archivo de registro y vería esto:
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
Luego, el desarrollador sabe de inmediato qué capa del software provocó la interrupción del proceso y tiene una manera fácil de identificar el problema. En este caso es crítico, porque el tiempo de espera de Redis nunca debería suceder.
Quizás otro usuario llame al mismo método, también reciba el 500
código, pero log mostrará lo siguiente:
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.
En cuyo caso, el soporte podría simplemente responder al usuario que la solicitud no era válida porque está solicitando un valor para una ID inexistente.
Resumen
Si está manejando excepciones, asegúrese de manejarlas de la manera correcta. También asegúrese de que sus excepciones incluyan los datos / mensajes correctos en primer lugar, siguiendo sus capas de arquitectura, para que los mensajes lo ayuden a identificar un problema que pueda ocurrir.