Excepciones de "error de programación": ¿suena bien mi enfoque?


9

Actualmente estoy tratando de mejorar mi uso de excepciones, y encontré la distinción importante entre las excepciones que significan errores de programación (por ejemplo, alguien pasó nulo como argumento, o llamó a un método en un objeto después de que se eliminó) y aquellos que significan una falla en el operación que no es culpa del llamante (por ejemplo, una excepción de E / S).

¿Cómo deben tratarse estos dos tipos de excepciones de manera diferente? ¿Cree que las excepciones de error deben documentarse explícitamente o es suficiente para documentar las condiciones previas relevantes? ¿Y puede omitir la documentación de una condición previa o una excepción de error si fuera obvio (por ejemplo, ObjectDisposedExceptional llamar a un método en un objeto desechado)


Por lo general, distingo otra categoría de excepciones: excepciones comerciales. Estos se refieren a las condiciones de error que el usuario está interesado en los detalles. Normalmente hago esas excepciones marcadas.
beluchin

Respuestas:


2

Creo que estás en el camino correcto. Ni tirar, atrapar ni documentar todas las excepciones potencialmente arrojables tiene mucho sentido. Hay momentos en que la rigurosidad del producto requiere un mayor grado de excepción de empleo y documentación (por ejemplo, ciertos aspectos críticos de seguridad de un sistema).

La estrategia de estar más a la defensiva, utilizando conceptos de contrato para identificar condiciones previas (y condiciones posteriores) en personas que llaman especialmente en sentido descendente (por ejemplo, cualquier cosa que se parezca a un miembro público o protegido) a menudo será más efectiva y más flexible. Esto se aplica no solo a la implementación, sino a la documentación. Si los desarrolladores saben lo que se espera, es más probable que sigan las reglas y es menos probable que se confundan o usen mal el código que ha escrito.

Algunas de las cosas comunes que deberían documentarse incluyen el caso de parámetros nulos. A menudo, hay una consecuencia de su uso que lleva el resultado a algo que normalmente no se esperaría, pero que se permite y usa por una variedad de razones, a veces por flexibilidad. Como consumidor de un miembro que tiene parámetros que permiten valores nulos u otros valores especiales no racionales (como tiempo negativo o cantidades negativas), espero verlos identificados y explicados.

Para parámetros no nulos, como consumidor de un miembro público o protegido, quiero saber que nulo no está permitido. Quiero saber cuál es el rango válido de valores en el contexto dado. Quiero saber las consecuencias de usar valores que están fuera del rango normal, pero que son válidos en un contexto de llamada diferente (por ejemplo, el valor del tipo generalmente es válido para cualquier operación, pero no aquí, como un parámetro booleano que no No esperes falso como un valor válido.

En cuanto a la plataforma, o interfaces bien conocidas, no creo que tenga que llegar a extremos al documentarla. Sin embargo, debido a que tiene la oportunidad como desarrollador de variar la implementación de cualquier guía de plataforma, tomar nota de cómo sigue esa guía puede ser valioso.

Las implementaciones específicas de IDisposable, a menudo de esta interfaz ofrecen un método alternativo que se prefiere sobre el proceso de eliminación explícito. En estos casos, resalte el método preferido y tenga en cuenta que no se prefiere la eliminación explícita.


Entiendo la necesidad de documentar qué valores están permitidos, pero si ve una función performReadCommand(ICommand cmd, int replySizeBytes), ¿esperaría que nulo sería aceptable para cmd o un valor negativo para replySizeBytes? La documentación de la OMI solo sería necesaria si esos valores realmente estuvieran permitidos, y probablemente debería abordar si 0 es válido para replySizeBytes.
Medo42

Ambos podrían ser "válidos" dependiendo de la implementación. Usted o yo somos, e incluso todos aquí no esperarían que los valores nulos o negativos sean apropiados para esa firma, pero podrían serlo. Considere un entorno donde el lector es un proceso persistente y de bloqueo, y cuando el cmd es nulo podría significar no cambiar el comando utilizado por el lector, y continuar con la siguiente lectura usando el comando anterior. Idealmente, en ese caso, se definiría y utilizaría una firma de método más apropiada que omitiera el cmd como parámetro, pero podría no serlo.
JustinC

2

Aquí están mis propios pensamientos. Tenga en cuenta que no estoy muy seguro de que esta sea la mejor manera de hacerlo, por eso creé esta pregunta en primer lugar.

Por lo que entiendo, tiene poco sentido que una persona que llama de inmediato maneje realmente las excepciones de error de programación, en su lugar debería asegurarse de que se cumplan las condiciones previas. Solo los manejadores de excepciones "externas" en los límites de la tarea deben atraparlos, para que puedan mantener el sistema en funcionamiento si una tarea falla.

Con el fin de garantizar que el código del cliente pueda capturar limpiamente las excepciones de "falla" sin atrapar las excepciones de error por error, creo mis propias clases de excepción para todas las excepciones de falla ahora, y las documento en los métodos que las arrojan. Les haría excepciones marcadas en Java.

Hasta hace poco, intenté documentar todas las excepciones que un método podría generar, pero eso a veces crea una lista involuntaria que debe documentarse en cada método de la cadena de llamadas hasta que pueda demostrar que el error no ocurrirá. En cambio, ahora documento las condiciones previas en las descripciones de resumen / parámetro y ni siquiera menciono lo que sucede si no se cumplen. La idea es que las personas no deberían tratar de detectar estas excepciones explícitamente de todos modos, por lo que no es necesario documentar sus tipos.

Para documentar las condiciones previas, declarar lo obvio simplemente crea un desorden innecesario: si pasar nulo a un método no tiene sentido obvio, la persona que llama tiene que esperar una excepción si pasa nulo de todos modos, incluso si eso no está documentado. Lo mismo es cierto para el caso de ObjectDisposedException: esta interfaz es tan utilizada que alguien que llame a Dispose estaría al tanto de la responsabilidad de asegurarse de que nadie continúe usando el objeto.


1

Una regla general razonable:

  1. Captura cualquier excepción que puedas arreglar.
  2. Capture, comente y vuelva a lanzar cualquier excepción que no pueda solucionar pero que pueda decir algo útil.
  3. No detecte ninguna excepción que no pueda procesar o diagnosticar mejor que el procesamiento predeterminado.

Es posible que desee tener un controlador de excepción no fatal de nivel superior para atrapar cualquier cosa que no se pueda manejar a continuación para tratar de evitar que su aplicación se caiga, pero eso dependerá en gran medida de su aplicación en particular. Por ejemplo, las aplicaciones de iOS prefieren atrapar tanto como sea posible; una aplicación de línea de comandos puede estar perfectamente bien si no atrapa casi ninguna excepción.


0

Incluso Java no "documenta" todas las excepciones. A pesar del requisito de que cada thrown excepción se mencione en una throwscláusula, cualquier línea de código puede arrojar una RuntimeExceptionsin necesidad de declararla en la firma del método.


Sin embargo, esto va en contra de los consejos populares: específicamente, Effective Java, 2nd ed, Item 62 es "Documentar todas las excepciones lanzadas por cada método". De hecho, Bloch reconoce que las excepciones no verificadas son generalmente para errores de programación, pero que también deben documentarse cuidadosamente, ya que esa es "la mejor manera" de documentar las condiciones previas de un método. Sin embargo, no estoy seguro de si estoy de acuerdo. Si documento las ejecuciones, las hago parte del contrato de interfaz y es posible que tenga que agregar código para que sigan siendo las mismas si cambia mi implementación.
Medo42

1
Para cada experto, hay un contra-experto. Bruce Eckel, autor del famoso Pensamiento en Java , estuvo una vez en el campo de excepciones comprobadas y ha cambiado de bando. Hay una buena discusión entre Eckels y Anders Hejlsberg , el creador de C #, que no tiene excepciones comprobadas.
Ross Patterson

0

La forma estándar de hacerlo es con el enfoque de Java. Los errores de programación deben ser excepciones no verificadas y no deben detectarse para garantizar una falla rápida. Los errores del contrato son excepciones comprobadas y el cliente debe manejarlos adecuadamente.


2
¿Considera (por ejemplo) un NULL calculado (o un valor de error de) como un error de programación o un error de contrato ? Voy con su distinción, pero el límite no es tan claro :)
Andrew

Si el valor nulo se calcula a partir de un argumento que se ha pasado (como un argumento nulo o algo no válido), es un error de contrato. Si el valor nulo se calcula debido a un código incorrecto, es un error de programación. Si se supone que se debe calcular el valor nulo, no es un error. Realmente no veo ninguna ambigüedad en este ejemplo.
J.Ashworth
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.