¿Por qué se considera que “log and throw” es un anti-patrón? [cerrado]

85

Esta pregunta fue provocada por una discusión sobre este artículo , donde no recibí ninguna buena respuesta.

¿Por qué debería ser una mala idea registrar su excepción y luego volver a lanzarla (conservando el seguimiento de la pila original, por supuesto) si no puede manejarlo de otra manera?

Manu
fuente
Intente buscar una respuesta en softwareengineering.stackexchange.com
chharvey

Respuestas:

121

Supongo que la respuesta se debe en gran parte a que, ¿por qué lo capta si no puede manejarlo? ¿Por qué no dejar que quien pueda manejarlo (o quien no tenga más remedio que manejarlo) lo registre, si sienten que vale la pena registrarlo?

Si lo detecta, lo registra y lo vuelve a lanzar, entonces no hay forma de que el código ascendente sepa que ya ha registrado la excepción, por lo que la misma excepción podría registrarse dos veces. O peor aún, si todo el código ascendente sigue este mismo patrón, la excepción podría registrarse un número arbitrario de veces, una por cada nivel del código que decida capturarlo, registrarlo y luego lanzarlo nuevamente.

También algunos podrían argumentar que dado que lanzar y capturar excepciones son operaciones relativamente costosas, toda esta captura y relanzamiento no está ayudando a su rendimiento en tiempo de ejecución. Tampoco ayuda a su código en términos de concisión o mantenibilidad.

aroth
fuente
para más detalles, vea los comentarios sobre la respuesta de Jeff
Manu
8
Una razón para registrar y volver a lanzar una exdeption debería ser reducir la razón y registrar un mensaje específico.
Mike Argyriou
11
Respuesta: podría haber información de depuración útil disponible en el punto actual de la pila que no estará disponible en otro punto del seguimiento de la pila
rtconner
A veces es útil atrapar y volver a lanzar si la nueva excepción es más útil con más información o más específica.
borjab
Para gastar en lo que comentó @rtconner: en código asíncrono podría ser que el receptor no tenga el contexto que está disponible para el lanzador.
Nir Alfasi
53

Log-and-throw es un buen patrón si la entidad que captura y vuelve a generar la excepción tiene motivos para creer que contiene información que no se registrará más arriba en la pila de llamadas, al menos no de la manera más deseada. Algunas razones por las que esto puede ocurrir:

  1. La excepción se puede detectar y volver a lanzar en un límite de la capa de aplicación y puede contener información privilegiada. Sería malo que una capa de base de datos permitiera una excepción que dijera, por ejemplo, "Intente agregar la clave duplicada 'fnord' al campo 'usuarios'" para llegar a la capa externa de la aplicación (que a su vez podría exponerla a un usuario), pero podría ser útil para las partes internas de la base de datos para lanzar una excepción de este tipo y la interfaz de la aplicación para detectarla, registrarla de forma segura y volver a generar una excepción algo menos descriptiva.
  2. La excepción puede ser una que la capa externa probablemente esperaría manejar sin registrar, pero la capa interna puede saber algo que la capa externa no sabe, lo que sugeriría que el registro puede ser útil. Como ejemplo burdo, una capa de aplicación intermedia podría estar programada para intentar conectarse a un servidor y, si eso no funciona, pruebe con otro. Inundar el registro de la aplicación con mensajes de 'conexión fallida' mientras un servidor está inactivo por mantenimiento puede no ser útil, especialmente porque, desde la perspectiva de la aplicación, todo funcionó bien. Puede ser útil reenviar información sobre la falla de conexión a un recurso de registro asociado con los servidores, que luego podría filtrar los registros para producir un informe de cuándo el servidor subió y bajó, en lugar de un registro de cada intento de conexión. .
Super gato
fuente
4
El # 1 es de hecho un caso de uso general sensato, sin embargo, el OP preguntó explícitamente sobre "volver a lanzarlo (preservando el rastro de pila original, por supuesto)", por lo que el # 1 no es la respuesta correcta.
Geoffrey Zheng
@GeoffreyZheng: Eso dependería de si registrar el seguimiento de la pila original de forma segura contaría como "preservar".
supercat
2
Con respecto al n. ° 1: exponer contenido de excepción (como mostrar e.getMessage()/ stacktrace en la interfaz de usuario, así como enviarlo como respuesta REST) ​​debe tratarse como una vulnerabilidad en sí misma, ya que la excepción en tiempo de ejecución puede contener cualquier tipo de información confidencial. Con respecto al n. ° 2: puede volver a lanzar la excepción agregando toda la información que desea que el cliente sepa (+ causa raíz), sin necesidad de registrar nada.
Nikita Bosik
@NikitaBosik: Ya sea que las excepciones se expongan o no en el lado del cliente, las aplicaciones que lo hacen son lo suficientemente comunes como para que el principio de 'seguridad en profundidad' sugiera que los mensajes de excepción deben eliminarse de la información confidencial. Además, si la capa externa no espera descartar un tipo particular de excepción sin registrarla ni reenviar información a una entidad externa que pueda estar interesada, tener una capa intermedia que agregue información que la capa externa va a ignorar no ayudará. cualquier cosa.
supercat
20

Supongo que la razón más simple es que normalmente tendrías un solo controlador de nivel superior haciendo esto por ti, por lo que no es necesario contaminar el código con este manejo de excepciones.

El argumento de las preocupaciones transversales es básicamente que es una pérdida de tiempo manejar errores que no le conciernen. Es mucho mejor dejar que el error aumente en la pila de llamadas hasta que se pueda encontrar un controlador adecuado.

En mi opinión, la única vez que debería detectar una excepción es cuando puede hacer algo útil con los resultados. Capturar simplemente para registrar no es útil, porque podría centralizar ese trabajo más arriba.

Jeff Foster
fuente
1
Estoy de acuerdo en que debería tener un único controlador de nivel superior que haga esto por usted. Pero en mi opinión, ese controlador de nivel superior DEBE ser "log and throw" -ing. Entonces, el argumento gira en torno a ¿EN QUÉ PUNTO "iniciar sesión y tirar", no si hacerlo o no hacerlo?
Manu
@Manu, supongo que el punto es que si es un solo controlador (centralizado), está bien. Si está duplicando código, no está bien. ¡No creo que haya nada más que eso!
Jeff Foster
5
@Manu - ¿A qué está lanzando el controlador de nivel superior en ese caso? Me parece que si hay algo disponible para lanzar, entonces no es realmente el controlador de nivel superior. Y definitivamente no desea volver a lanzar una excepción al entorno de ejecución en sí. Eso detendrá la mayoría de las aplicaciones.
aroth
1
@aroth: Ya veo, lo que está diciendo es "registrar y manejar" (si es el controlador de nivel superior) o "no iniciar sesión y lanzar (o manejar de otra manera)" si no lo es. Gracias por señalar eso.
Manu
9

El registro y lanzamiento de la OMI es una clara violación del principio de la menor sorpresa.

Si la excepción se maneja correctamente más arriba en la pila de llamadas, es posible que no valga la pena una entrada en el registro de errores. Y luego es confuso encontrar una entrada de registro de errores.

Bastian Voigt
fuente
¿Qué pasa con los registros sin errores?
Su Zhang
6
@SuZhang No entiendo bien tu pregunta. Si no hay ningún error, no hay nada que tirar. Por supuesto, puede y debe escribir registros sin errores.
Bastian Voigt