Granularidad de Excepciones

9

He tenido un debate entre unos pocos amigos y yo. Prefieren excepciones generales como ClientErrorExceptiony ServerErrorExceptioncon detalles como campos de la excepción, mientras que prefiero hacer las cosas más específicas. Por ejemplo, podría tener un puñado de excepciones como:

  • BadRequestException
  • AuthenticationFailureException
  • ProductNotFoundException

Cada uno de estos se basa en el código de error devuelto por la API.

Siguiendo las ventajas de las excepciones, esto parece idiomático para Java. Sin embargo, la opinión de mis amigos no es exactamente infrecuente.

¿Existe una forma preferida en términos de legibilidad de código y usabilidad de API, o realmente se reduce a la preferencia?


fuente
La página que ha vinculado es probablemente la mejor respuesta definitiva que podemos obtener. Estás pidiendo una opinión, de verdad. Puedo responder con mi experiencia y opinión, pero esa no es una respuesta objetiva.
marstato
@marstato eso es justo. Supongo que estoy buscando justificación en mi posición. Prefiero seguir lo que la gente espera en las bibliotecas que escribo, en lugar de seguir una guía si eso significa que mis cosas son más fáciles de usar, ¿sabes?
Estoy absolutamente de acuerdo. También tengo mis clases de excepción granulares. Además, puede definir abstracty generalizar las clases de excepción con los métodos getter y luego hacer que las granulares amplíen las generales. Por ej AuthenticationFaliureException extends ClientErrorException. De esta manera, cada usuario puede elegir cómo quiere lidiar con las excepciones. Sin embargo, funciona más, obviamente. Sin embargo, al escribir una aplicación (en lugar de una biblioteca), es una situación diferente en mi humilde opinión. En ese caso, no haría que las excepciones sean más granulares de lo que las necesita, por simplicidad.
marstato
@marstato así es como lo implemento ahora. Me alegra que estés de acuerdo. Dejaré la pregunta abierta durante la noche, pero consolide eso en una publicación para que al menos pueda verificarlo en verde

Respuestas:

15

La principal diferencia entre tener muchas clases de excepción diferentes y tener solo unas pocas, con información más detallada en el texto de error (por ejemplo), es que muchas clases de excepción diferentes permiten que el código de llamada reaccione de manera diferente a diferentes tipos de errores, mientras que tiene Solo unas pocas clases facilitan el manejo de todo tipo de excepciones de manera uniforme.

Esto suele ser una compensación. Puede mitigarse hasta cierto punto mediante el uso de la herencia (una clase de excepción de base general para las personas que llaman que desean capturar y registrar todo genéricamente, y las excepciones derivadas de esa clase de base para las personas que llaman que necesitan diferentes reacciones), pero incluso eso puede producir un mucha complejidad innecesaria si no tienes cuidado y te apegas al principio YAGNI. Entonces la pregunta guía debería estar aquí:

  • ¿Realmente espera que la persona que llama su código reaccione de manera diferente, con un flujo de control diferente, a ese tipo diferente de errores?

No hay una solución única para todo esto, no hay una "práctica recomendada" que pueda aplicar todos y cada uno. La respuesta a esta pregunta depende en gran medida del tipo de software o componente que esté diseñando:

  • alguna aplicación, donde usted o el equipo tiene toda la base de código bajo su control?

  • o algún componente reutilizable para terceros, donde no conoces a todas las personas que llaman potenciales?

  • Es una aplicación de servidor de larga ejecución, donde diferentes tipos de errores no deberían romper todo el sistema de inmediato y pueden requerir diferentes tipos de mitigación de errores.

  • un proceso de aplicación de corta duración en el que es suficiente en caso de error mostrar un mensaje de error al usuario y luego reiniciar el proceso?

Por lo tanto, cuanto más sepa acerca de las posibles llamadas de su componente, mejor podrá decidir sobre el nivel de detalle correcto para sus excepciones.

Doc Brown
fuente
3
"¿Realmente espera que la persona que llama su código reaccione de manera diferente, con un flujo de control diferente, a esos diferentes tipos de errores?" Esta es una gran pregunta para hacer. Gracias, voy a recordar esto.
Creo que esta es una buena respuesta, solo enfatizaría aún más la necesidad de dejar que la aplicación cliente impulse el diseño de lanzamiento de excepciones. Incluso las generalizaciones que podría considerar sensatas para incorporar a la jerarquía de excepciones podrían no coincidir con las formas en que su aplicación cliente (si no es usted quien la escribe) podría optar por generalizar un controlador. Si tiene más de una aplicación cliente con diferentes necesidades, entonces, por supuesto, dependerá de usted equilibrarlas.
magicduncan
1

La respuesta depende de qué nivel de informe de errores estamos hablando.

En general, estoy de acuerdo con tus amigos, no debes hacerlos más granulares de lo necesario para transmitir la causa del problema.

Si hay una excepción común y bien conocida para hacer referencia a nulo (NullReferenceException), no debe crear su propia MyObjectIsNullException. Eso solo agregaría una capa de confusión para el intérprete humano, una cosa adicional que aprender que no aclara nada.

Solo cuando su excepción sea tan especial que no haya una predefinida que cubra la causa raíz, debe crear la suya propia.

Sin embargo, no tiene que detenerse allí. El error común puede ocurrir en uno de sus componentes y es posible que desee comunicar que hubo un problema en su componente . Así que no solo lo que salió mal sino también dónde. Entonces sería apropiado envolver la primera excepción en una excepción MyComponentException. Eso te dará lo mejor de ambos mundos.

Primero quedará claro que su componente tuvo problemas. En una palanca inferior, la causa específica estaría en la excepción interna.

Martin Maat
fuente
Eso es justo. ¿Entonces sugiere que no invente una nueva excepción cuando ya existe una buena?
@rec Sí, porque todos ya conocen los predefinidos. Para eso están allí.
Martin Maat