Actualmente estoy haciendo una revisión del código y una de las cosas que noto es la cantidad de excepciones en las que el mensaje de excepción parece reiterar dónde ocurrió la excepción. p.ej
throw new Exception("BulletListControl: CreateChildControls failed.");
Los tres elementos en este mensaje los puedo resolver del resto de la excepción. Sé la clase y el método del seguimiento de la pila y sé que falló (porque tengo una excepción).
Me hizo pensar en qué mensaje pongo en los mensajes de excepción. Primero creo una clase de excepción, si aún no existe, por la razón general (por ejemplo PropertyNotFoundException
, el por qué ), y luego, cuando la lanzo, el mensaje indica qué salió mal (por ejemplo, "No se puede encontrar la propiedad 'IDontExist' en el Nodo 1234 "- el qué ). El donde está en el StackTrace
. El cuándo puede terminar en el registro (si corresponde). El cómo es para que el desarrollador resuelva (y arregle)
¿Tienes algún otro consejo para lanzar excepciones? Específicamente con respecto a la creación de nuevos tipos y el mensaje de excepción.
fuente
Respuestas:
Dirigiré mi respuesta más a lo que viene después de una excepción: para qué sirve y cómo debe comportarse el software, ¿qué deben hacer sus usuarios con la excepción? Una gran técnica que encontré al principio de mi carrera fue siempre informar problemas y errores en 3 partes: contexto, problema y solución. El uso de esta diciplina cambia enormemente el manejo de errores y hace que el software sea mucho mejor para que lo utilicen los operadores.
Aquí hay algunos ejemplos.
En este caso, el operador sabe exactamente qué hacer y a qué archivo debe verse afectado. También saben que los cambios de agrupación de conexiones no tomaron y deberían repetirse.
Escribo sistemas del lado del servidor y mis operadores son generalmente expertos en tecnología de primera línea. Escribiría los mensajes de manera diferente para el software de escritorio que tiene una audiencia diferente pero incluye la misma información.
Varias cosas maravillosas suceden si uno usa esta técnica. El desarrollador de software a menudo está mejor ubicado para saber cómo resolver los problemas en su propio código, por lo que codificar las soluciones de esta manera a medida que escribe el código es de gran beneficio para los usuarios finales que están en desventaja al encontrar soluciones, ya que a menudo les falta información sobre qué estaba haciendo exactamente el software. Cualquiera que haya leído un mensaje de error de Oracle sabrá a qué me refiero.
La segunda cosa maravillosa que viene a la mente es cuando te encuentras tratando de describir una solución en tu excepción y estás escribiendo "Marque X y si A entonces B más C". Esta es una señal muy clara y obvia de que su excepción se está verificando en el lugar incorrecto. Usted, el programador, tiene la capacidad de comparar cosas en el código, por lo que las declaraciones "si" deben ejecutarse en el código, ¿por qué involucrar al usuario en algo que pueda automatizarse? Lo más probable es que es de más profundo en el código y alguien ha hecho lo vago y arrojado IOException de cualquier número de métodos y atrapado posibles errores de todos ellos en un bloque de código de llamada que no se puede describir adecuadamente lo que salió mal, lo que la específicacontexto es y cómo solucionarlo. Esto lo alienta a escribir errores de grano más fino, atraparlos y manejarlos en el lugar correcto en su código para que pueda articular adecuadamente los pasos que debe seguir el operador.
En una compañía teníamos operadores de primer nivel que conocían muy bien el software y mantenían su propio "libro de ejecución" que aumentaba nuestros informes de errores y las soluciones sugeridas. Para reconocer esto, el software comenzó a incluir enlaces wiki al libro de carreras en excepciones, de modo que una explicación básica estaba disponible, así como enlaces a discusiones y observaciones más avanzadas por parte de los operadores a lo largo del tiempo.
Si ha tenido la diciplina para probar esta técnica, se vuelve mucho más obvio qué debe nombrar sus excepciones en el código al crear el suyo. NonRecoverableConfigurationReadFailedException se convierte en una abreviatura de lo que está a punto de describir más completamente al operador. Me gusta ser detallado y creo que será más fácil de interpretar para el próximo desarrollador que toque mi código.
fuente
FileNotFound
oConnectException
sabrá qué hacer))En esta pregunta más reciente, señalé que las excepciones no deberían contener ningún mensaje. En mi opinión, el hecho de que lo hagan es un gran error. Lo que propongo es que
Una excepción debe contener dentro de sus propias variables miembro tantos detalles como sea posible sobre exactamente lo que sucedió; por ejemplo, un
IndexOutOfRangeException
debe contener el valor de índice que se consideró no válido, así como los valores superior e inferior que eran válidos en el momento en que se lanzó la excepción. De esta manera, usando la reflexión, puede tener un mensaje construido automáticamente que se lee así:IndexOutOfRangeException: index = -1; min=0; max=5
y esto, junto con el seguimiento de la pila, debe ser toda la información objetiva que necesita para solucionar el problema. Formatearlo en un mensaje bonito como "índice -1 no estaba entre 0 y 5" no agrega ningún valor.En su ejemplo particular, la
NodePropertyNotFoundException
clase contendría el nombre de la propiedad que no se encontró y una referencia al nodo que no contenía la propiedad. Esto es importante: debe no contener el nombre del nodo; Debe contener una referencia al nodo real. En su caso particular, esto puede no ser necesario, pero es una cuestión de principios y una forma preferida de pensar: la preocupación principal al construir una excepción es que debe ser utilizable por código que pueda atraparla. La usabilidad por parte de los humanos es una preocupación importante, pero solo secundaria.Esto se encarga de la situación muy frustrante que pudo haber presenciado en algún momento de su carrera, en la que puede haber detectado una excepción que contiene información vital sobre lo que sucedió dentro del texto del mensaje, pero no dentro de sus variables miembro, por lo que tuvo que hacer un análisis de cadena del texto para averiguar qué sucedió, esperando que el texto del mensaje permanezca igual en futuras versiones de la capa subyacente, y rezando para que el texto del mensaje no esté en algún idioma extranjero cuando su programa esté correr en otros países.
Por supuesto, dado que el nombre de clase de la excepción es el mensaje de la excepción (y las variables miembro de la excepción son los detalles específicos), esto significa que necesita muchas excepciones para transmitir todos los mensajes diferentes, y eso está bien.
Ahora, a veces, mientras escribimos código, nos encontramos con una situación errónea para la que solo queremos codificar rápidamente una
throw
declaración y continuar escribiendo nuestro código en lugar de tener que interrumpir lo que estamos haciendo para crear una nueva clase de excepción para que podamos tíralo ahí mismo. Para estos casos, tengo unaGenericException
clase que, de hecho, acepta un mensaje de cadena como parámetro de tiempo de construcción, pero el constructor de esta clase de excepción está adornado con un gran granFIXME XXX TODO
comentario púrpura brillante que indica que cada instancia de esta clase debe ser reemplazado con una instanciación de alguna clase de excepción más especializada antes de que se libere el sistema de software, preferiblemente antes de que se comprometa el código.fuente
node
objeto está protegido por una cláusula use-disposable (en C #) o try-with-resources (en Java): el objeto almacenado con la excepción sería desechado / cerrado, lo que lo hace ilegal acceder a él para obtener información útil en el lugar donde se maneja la excepción. Supongo que en estos casos algún tipo de resumen del objeto debe almacenarse dentro de la excepción, en lugar del objeto en sí. No puedo pensar en una forma infalible de manejar esto genéricamente para todos los casos.Como regla general, una excepción debería ayudar a los desarrolladores a identificar la causa al proporcionar información útil (valores esperados, valor real, posibles causas / solución, etc.).
Se deben crear nuevos tipos de excepción cuando ninguno de los tipos integrados tiene sentido . Un tipo específico permite a otros desarrolladores detectar una excepción específica y manejarla. Si el desarrollador supiera cómo manejar su excepción pero el tipo es
Exception
, no podrá manejarlo correctamente.fuente
En .NET nunca
throw new Exception("...")
(como ha mostrado el autor de la pregunta). La excepción es el tipo de excepción raíz y no se supone que se lance directamente. En su lugar, lanza uno de los tipos de excepción .NET derivados o crea tu propia excepción personalizada que se derive de Exception (u otro tipo de excepción).¿Por qué no lanzar Exception? ¡Porque lanzar Excepción no hace nada para describir su excepción y obliga a su código de llamada a escribir código como el
catch(Exception ex) { ... }
cual generalmente no es algo bueno! :-).fuente
Las cosas que desea buscar para "agregar" a la excepción son aquellos elementos de datos que no son inherentes a la excepción o al seguimiento de la pila. Si esos son parte del "mensaje" o deben adjuntarse cuando se registra es una pregunta interesante.
Como ya ha notado, la excepción probablemente le dice qué, el stacktrace probablemente le dice dónde, pero el "por qué" puede estar más involucrado (debería ser, uno esperaría) que simplemente mirar una o dos líneas y decir " doh! Por supuesto ". Esto es aún más cierto cuando se registran errores en el código de producción: con demasiada frecuencia he sido mordido por datos incorrectos que se han introducido en un sistema en vivo que no existe en nuestros sistemas de prueba. Algo tan simple como saber cuál es la ID del registro en la base de datos que está causando (o contribuyendo) al error puede ahorrar una cantidad significativa de tiempo.
Entonces ... Enumerado o, para .NET, agregado a la recopilación de datos de excepciones registradas (cf @Plip!):
Algunas cosas, por supuesto, no sabrá que necesita hasta que no las tenga en su informe / registro de errores inicial. Algunas cosas no se dan cuenta de que puede obtener hasta que descubra que las necesita.
fuente
¿Cuáles son excepciones para ?
(1) ¿Decirle al usuario que algo salió mal?
Esto debería ser un último recurso, porque su código debe interceder y mostrarles algo "más agradable" que una excepción.
El mensaje de "error" debe indicar clara y sucintamente qué salió mal y qué puede hacer el usuario para recuperarse de la condición de error.
por ejemplo, "No presione este botón nuevamente"
(2) ¿Informarle a un desarrollador cuándo salió mal?
Este es el tipo de cosas que inicia sesión en un archivo para su posterior análisis.
El seguimiento de la pila le dirá al desarrollador dónde se rompió el código; el mensaje debe, nuevamente, indicar qué salió mal.
(3) ¿Decirle a un controlador de excepciones (es decir, código) que algo salió mal?
El Tipo de Excepción decidirá qué controlador de excepciones podrá verlo y las propiedades definidas en el objeto Excepción permitirán que el controlador lo maneje.
El mensaje de la excepción es totalmente irrelevante .
fuente
No cree nuevos tipos si puede evitarlo. Pueden causar confusión adicional, complejidad y generar más código para mantener. Pueden hacer que su código tenga que extenderse. El diseño de una jerarquía de excepción requiere mucho tiempo y pruebas. No es un pensamiento posterior. A menudo es mejor usar la jerarquía de excepciones de lenguaje integrada.
El contenido del mensaje de excepción depende del receptor del mensaje, por lo que debe ponerse en el lugar de esa persona.
Un ingeniero de soporte deberá poder identificar la fuente del error lo más rápido posible. Incluya una cadena descriptiva corta más cualquier dato que pueda ayudar a solucionar el problema. Incluya siempre el seguimiento de la pila, si puede, esta será la única fuente verdadera de información.
La presentación de errores a los usuarios generales de su sistema depende del tipo de error: si el usuario puede solucionar el problema, proporcionando una entrada diferente, por ejemplo, entonces se requiere un mensaje descriptivo conciso. Si el usuario no puede solucionar el problema, lo mejor es indicar que se ha producido un error y registrar / enviar un error al servicio de asistencia (utilizando las pautas anteriores).
Además, no arroje un gran "¡ERROR DE MEDIO!" icono. Es un error, no es el fin del mundo.
En resumen: piense en los actores y use casos para su sistema. Ponte en el lugar de esos usuarios. Se útil Se bueno. Piense en esto por adelantado en el diseño de su sistema. Desde la perspectiva de sus usuarios, estos casos excepcionales y la forma en que el sistema los maneja son tan importantes como los casos normales en su sistema.
fuente