Recomendar un patrón / enfoque de diseño para exponer / tolerar / recuperarse de errores del sistema, manejo de excepciones (egs en Java, C ++, Perl, PHP)

13

¿Puede recomendar un patrón / enfoque de diseño para exponer / tolerar / recuperarse de errores del sistema, manejo de excepciones (Java, C ++, Perl, PHP)?

Algunos errores deben ser reportados.

Algunos errores pueden manejarse internamente (mediante un reintento o son intrascendentes (pueden ignorarse).

¿Cómo estructura el código para atraparlos?

Pero todos los errores deben registrarse.

¿Qué mejores prácticas hay?

¿Y para simularlos para poder probar completamente los componentes afectados por ellos?

Pregunta general no específica del lenguaje de programación aplicable a varios lenguajes de programación modernos, pero sería bienvenida con ejemplos de patrones, enfoques y filosofías en Java, C ++, PHP y Perl.

(También se preguntó en stackoverflow: /programming/7432596/recommend-a-design-pattern-approach-to-exposing-tolerating-recovering-from-system pero pensé que debería preguntarse a los programadores también porque Creo que las preguntas y respuestas de los programadores cubren problemas más amplios de software / programación, mientras que stackoverflow trata más sobre la implementación técnica en mi humilde opinión).

therobyouknow
fuente
2
Para mí, su pregunta parece demasiado general y abierta para ser respondida de manera efectiva. Intente restringirlo a algunos casos más específicos y también a tipos / entornos de aplicaciones específicos (por ejemplo, aplicación GUI / servidor / ...).
Péter Török
Ver también stackoverflow.com/questions/937285/…
Péter Török
@ Péter Török, mikera ofrece una buena respuesta, probablemente acepte la suya.
therobyouknow

Respuestas:

16

Fail fast es un gran enfoque de diseño, y tal vez se pueda contar como un patrón: http://en.wikipedia.org/wiki/Fail-fast

También he encontrado que varios principios son útiles:

  • Considere las excepciones como parte de la interfaz para cada función / módulos , es decir, documente y, si corresponde, si su idioma lo admite, utilice las excepciones marcadas.
  • Nunca evite una falla : si falla, no intente continuar con algún intento de "asumir" cómo proceder. Por ejemplo, el manejo especial para casos nulos es a menudo un olor a código para mí: si su método necesita un valor no nulo, debería arrojar una excepción de inmediato si encuentra un nulo (NullPointerException o idealmente una IllegalArgumentException más descriptiva).
  • Escriba pruebas unitarias para casos excepcionales y normales ; a veces, tales pruebas pueden ser difíciles de configurar, pero vale la pena cuando desea asegurarse de que su sistema sea robusto ante fallas
  • Registre en el punto donde se detectó y manejó el error (suponiendo que el error fuera de suficiente gravedad para ser registrado). La razón de esto es que implica que entendió la causa y tuvo un enfoque para manejar el error, por lo que puede hacer que el mensaje de registro sea significativo .....
  • Use excepciones solo para condiciones / fallas verdaderamente inesperadas. Si su función "falla" de una manera realmente esperada (por ejemplo, sondear para ver si hay más entradas disponibles y no encontrar ninguna), entonces debería devolver una respuesta normal ("no hay entradas disponibles"), no lanzar una excepción
  • Falla con gracia (¡crédito a Steven Lowe!) : Limpie antes de terminar, si es posible, por lo general deshaciendo los cambios, retrotrayendo transacciones o liberando recursos en una declaración "finalmente" o equivalente. Lo ideal es que la limpieza se realice al mismo nivel en que se comprometieron los recursos en aras de la claridad y la coherencia lógica.
  • Si tiene que fallar, hágalo en voz alta , una excepción que ninguna parte de su código pudo manejar (es decir, filtrada al nivel superior sin ser atrapado + manejado) debería causar una falla inmediata, fuerte y visible que dirija su atención hacia él. Normalmente detengo el programa o la tarea y escribo un informe de excepción completo en System.out.
mikera
fuente
1
también fallar con gracia - limpiar antes de terminar si es posible
Steven A. Lowe
+1 @mikera para obtener puntos claros sobre qué considerar. Respuesta probablemente aceptada, dejaré abierto un poco más para que otros contribuyan.
therobyouknow
+1 @Steve A. Lowe: para un diseño centrado en el usuario. por ejemplo, como guardar archivos, no dejar archivos temporales por ahí Vea mi pregunta sobre "higiene de datos" como un tema relacionado en mi lista de preguntas.
therobyouknow
5

Después de haber trabajado con excepciones en Java y .NET Y después de leer muchos artículos sobre cómo / cuándo / por qué capturar excepciones, finalmente se me ocurrieron los siguientes pasos que paso por mi cabeza cada vez que veo una posible excepción, o un excepción debo atrapar (Java) ... incluso si nunca sucede (suspiro ...). Y parece estar funcionando, al menos para mí:

  1. ¿Hay algo útil que pueda hacer con esa excepción (excepto el registro)? Si la respuesta es sí, escriba el código de solución y si la solución puede generar excepciones, vaya a 2:
  2. Envuelva la excepción alrededor de una excepción de tiempo de ejecución, tírela, vaya a 3.
  3. En la clase de nivel superior donde se ha iniciado una posible transacción de base de datos / proceso, capture la excepción, revierta la transacción, vuelva a lanzar la excepción.
  4. En la clase de nivel superior (que puede ser aquella donde se inició la transacción), registre la excepción utilizando un marco de registro como slf4j (junto con log4j, por ejemplo) o log4net . Si es posible, envíe directamente la excepción por correo electrónico a una lista de distribución compuesta por desarrolladores de la aplicación.
  5. Si hay una GUI, muestre un mensaje de error que indique de la manera más fácil de usar qué causó el problema; no muestra la excepción / stacktrace, al usuario no le importa y no necesita saber que fue una NullPointerException.

También debo agregar el paso 0 , donde estoy lanzando a propósito lo que llamo una excepción "comercial" (una nueva excepción que creo al extender la clase "Excepción") cuando algún tratamiento complejo no puede ejecutarse debido a errores de datos, PERO eso se sabe que suceden ya que se han identificado como casos de excepción durante el análisis.

Excepto por la parte de registro, estoy totalmente de acuerdo con los puntos escritos por "mikera"; Solo agregaré que la excepción debe registrarse solo una vez .

Además, los pasos que enumeré pueden ser diferentes si lo que está escribiendo es un API / Framework . Allí, lanzar excepciones bien diseñadas es obligatorio para ayudar a los desarrolladores a comprender sus errores.

En cuanto a probar las excepciones, con el uso de objetos simulados debería poder probar casi todo, ya sea de forma excepcional o no, siempre que sus clases respeten la práctica recomendada de "una clase para hacer una cosa". También me aseguro de marcar los métodos más importantes pero ocultos como "protegidos" en lugar de "privados" para poder probarlos sin demasiados problemas. Aparte de eso, probar excepciones es simple, solo provoca la excepción y "espera" que ocurra una excepción al atraparla. Si no obtiene una excepción, entonces tiene un error de caso de prueba de unidad.

Jalayn
fuente
+1 @Jalayn para log4j menciona como un enfoque, esto es lo que uso, por lo que lo refuerza saber que alguien más también lo es.
therobyouknow
0

Construye tus objetos de la manera correcta, no te preocupes por factores externos. Si elige aprovechar las excepciones, haga que sus objetos arrojen excepciones si fallan en algo.

Una vez que todos sus objetos funcionan correctamente, debería ser bastante fácil encontrar una jerarquía de responsabilidad de manejo de errores limpia en su diseño.

Ñame Marcovic
fuente