Esos mensajes son para otros desarrolladores.
Se espera que los desarrolladores lean esos mensajes para ayudarlos a depurar la aplicación. Esto puede tomar dos formas:
Depuración activa En realidad, está ejecutando un depurador mientras escribe código e intenta averiguar qué sucede. En este contexto, una excepción útil lo guiará al facilitarle la comprensión de lo que está sucediendo o, eventualmente, le sugerirá una solución alternativa (aunque esto es opcional).
Depuración pasiva. El código se ejecuta en producción y falla. La excepción se registra, pero solo obtiene el mensaje y el seguimiento de la pila. En este contexto, un mensaje de excepción útil lo ayudará a localizar rápidamente el error.
Dado que esos mensajes a menudo se registran, también significa que no debe incluir información confidencial allí (como claves privadas o contraseñas, incluso si pudiera ser útil para depurar la aplicación).
Por ejemplo, el IOSecurityExceptiontipo de excepción que se produce al escribir un archivo no es muy explícito sobre el problema: ¿es porque no tenemos permisos para acceder a un archivo? ¿O tal vez podamos leerlo, pero no escribir? ¿O tal vez el archivo no existe y no tenemos permisos para crear archivos allí? O tal vez está bloqueado (con suerte, el tipo de excepción será diferente en este caso, pero en la práctica, los tipos a veces pueden ser crípticos). ¿O tal vez Code Access Security nos impide realizar cualquier operación de E / S?
En lugar:
IOSecurityException: se encontró el archivo pero se denegó el permiso para leer su contenido.
Es mucho más explícito. Aquí, sabemos de inmediato que los permisos en el directorio están configurados correctamente (de lo contrario, no podremos saber que el archivo existe), pero los permisos a nivel de archivo son problemáticos.
Esto también significa que si no puede proporcionar ninguna información adicional que no esté en el tipo de excepción, puede mantener el mensaje vacío. DivisionByZeroExceptionEs un buen ejemplo donde el mensaje es redundante. Por otro lado, el hecho de que la mayoría de los idiomas le permiten lanzar una excepción sin especificar su mensaje se hace por una razón diferente: ya sea porque el mensaje predeterminado ya está disponible o porque se generará más tarde si es necesario (y la generación de este mensaje). el mensaje está encerrado dentro del tipo de excepción, lo que tiene mucho sentido, "OOPly" hablando).
Tenga en cuenta que por razones técnicas (a menudo de rendimiento), algunos mensajes terminan siendo mucho más crípticos de lo que deberían ser. .NET's NullReferenceException:
Referencia a objeto no establecida como instancia de un objeto.
es un excelente ejemplo de un mensaje que no es útil. Un mensaje útil sería:
La referencia de objeto productno se establece en una instancia de un objeto cuando se llama product.Price.
¡Esos mensajes no son para usuarios finales!
No se espera que los usuarios finales vean mensajes de excepción. Nunca. Aunque algunos desarrolladores terminan mostrando esos mensajes a los usuarios, esto conduce a una experiencia de usuario deficiente y a la frustración. Mensajes como:
Referencia a objeto no establecida como instancia de un objeto.
no significa absolutamente nada para un usuario final y debe evitarse a toda costa.
El peor de los casos es tener un try / catch global que arroje la excepción al usuario y salga de la aplicación. Una aplicación que se preocupa por sus usuarios:
Maneja excepciones en primer lugar. La mayoría se pueden manejar sin molestar al usuario. ¿La red está inactiva? ¿Por qué no esperar unos segundos y volver a intentarlo?
Impide que un usuario dirija la aplicación a un caso excepcional. Si le pide al usuario que ingrese dos números y divida el primero por el segundo, ¿por qué permitiría al usuario ingresar cero en el segundo caso para culparlo unos segundos después? ¿Qué hay de resaltar el cuadro de texto en rojo (con una información útil que dice que el número debe ser diferente a cero) y deshabilitar el botón de validación hasta que el campo permanezca rojo?
Invita a un usuario a realizar una acción en un formulario que no sea un error. ¿No hay suficientes permisos para acceder a un archivo? ¿Por qué no pedirle al usuario que otorgue permisos administrativos o elegir un archivo diferente?
Si nada más funciona, muestra un error útil y amigable que está escrito específicamente para reducir la frustración del usuario, ayudarlo a comprender qué salió mal y eventualmente resolver el problema, y también ayudarlo a prevenir el error en el futuro (cuando corresponda).
En su pregunta, sugirió tener dos mensajes en una excepción: uno técnico para desarrolladores y otro para usuarios finales. Si bien esta es una sugerencia válida en algunos casos menores, la mayoría de las excepciones se producen a un nivel en el que es imposible producir un mensaje significativo para los usuarios. Tome DivisionByZeroExceptione imagine que no podríamos evitar que ocurra la excepción y no podemos manejarla nosotros mismos. Cuando ocurre la división, ¿sabe el marco (ya que es el marco, y no el código comercial, lo que arroja la excepción) cuál será un mensaje útil para un usuario? Absolutamente no:
La división por cero ocurrió. [OKAY]
En cambio, uno puede dejar que arroje la excepción, y luego atraparlo en un nivel superior donde conocemos el contexto comercial y podríamos actuar en consecuencia para ayudar realmente al usuario final, mostrando así algo como:
El campo D13 no puede tener el valor idéntico al del campo E6, porque la resta de esos valores se usa como divisor. [OKAY]
o tal vez:
Los valores informados por el servicio ATP son inconsistentes con los datos locales. Esto puede deberse a que los datos locales no están sincronizados. ¿Desea sincronizar la información de envío y volver a intentarlo? [Si no]
Esos mensajes no son para analizar
Tampoco se espera que los mensajes de excepción sean analizados o utilizados mediante programación. Si cree que la persona que llama puede necesitar información adicional, inclúyala en la excepción junto con el mensaje. Esto es importante porque el mensaje está sujeto a cambios sin previo aviso. El tipo es parte de la interfaz, pero el mensaje no lo es: nunca confíe en él para el manejo de excepciones.
Imagine el mensaje de excepción:
La conexión al servidor de almacenamiento en caché expiró después de esperar 500 ms. Aumente el tiempo de espera o verifique la supervisión del rendimiento para identificar una caída en el rendimiento del servidor. El tiempo de espera promedio para el servidor de almacenamiento en caché fue de 6 ms. para el último mes, 4 ms. para la última semana y 377 ms. por la última hora
Desea extraer los valores "500", "6", "4" y "377". Piensa un poco en el enfoque que usarás para hacer el análisis, y solo entonces continúa leyendo.
Tienes la idea? Excelente.
Ahora, el desarrollador original descubrió un error tipográfico:
Connecting to the caching sever timed out after waiting [...]
debiera ser:
↓
Connecting to the caching server timed out after waiting [...]
Además, el desarrollador considera que mes / semana / una hora no son particularmente relevantes, por lo que también realiza un cambio adicional:
El tiempo de espera promedio para el servidor de almacenamiento en caché fue de 6 ms. para el último mes, 5 ms. durante las últimas 24 horas y 377 ms. por la última hora
¿Qué pasa con tu análisis?
En lugar de analizar, podría estar utilizando propiedades de excepción (que pueden contener lo que uno quiera, tan pronto como se puedan serializar los datos):
{
message: "Connecting to the caching [...]",
properties: {
"timeout": 500,
"statistics": [
{ "timespan": 1, "unit": "month", "average-timeout": 6 },
{ "timespan": 7, "unit": "day", "average-timeout": 4 },
{ "timespan": 1, "unit": "hour", "average-timeout": 377 },
]
}
}
¿Qué tan fácil es usar estos datos ahora?
A veces (como en .NET), el mensaje puede incluso traducirse al idioma del usuario (en mi humilde opinión, traducir esos mensajes es absolutamente incorrecto, ya que se espera que cualquier desarrollador pueda leer en inglés). Analizar tales mensajes es casi imposible.