Encontré un código como este en uno de nuestros proyectos:
SomeClass QueryServer(string args)
{
try
{
return SomeClass.Parse(_server.Query(args));
}
catch (Exception)
{
return null;
}
}
Según tengo entendido, suprimir errores como este es una mala práctica, ya que destruye información útil de la excepción del servidor original y hace que el código continúe cuando realmente debería terminar.
¿Cuándo es apropiado suprimir completamente todos los errores como este?
programming-practices
language-agnostic
error-handling
usuario626528
fuente
fuente
Respuestas:
Imagine código con miles de archivos usando un montón de bibliotecas. Imagine que todos ellos están codificados de esta manera.
Imagine, por ejemplo, que una actualización de su servidor hace que un archivo de configuración desaparezca; y ahora todo lo que tiene es un seguimiento de pila es una excepción de puntero nulo cuando intenta usar esa clase: ¿cómo resolvería eso? Podría tomar horas, donde al menos solo registrar el seguimiento de la pila sin procesar del archivo no encontrado [ruta del archivo] puede permitirle resolver momentáneamente.
O peor aún: una falla en una de las bibliotecas que usa después de una actualización que hace que su código se bloquee más adelante. ¿Cómo puedes rastrear esto hasta la biblioteca?
Incluso sin un manejo robusto de errores simplemente haciendo
o
puede ahorrarle horas de tiempo.
Pero hay algunos casos en los que es posible que desee ignorar la excepción y devolver un valor nulo como este (o no hacer nada). Especialmente si se integra con algún código heredado mal diseñado y esta excepción se espera como un caso normal.
De hecho, al hacer esto, debería preguntarse si realmente está ignorando la excepción o "manejando adecuadamente" sus necesidades. Si devolver nulo es "manejar adecuadamente" su excepción en ese caso dado, hágalo. Y agregue un comentario por qué esto es lo correcto.
Las mejores prácticas son cosas a seguir en la mayoría de los casos, tal vez 80%, tal vez 99%, pero siempre encontrará un caso límite en el que no se aplican. En ese caso, deje un comentario de por qué no está siguiendo la práctica para los demás (o incluso para usted) que leerán su código meses después.
fuente
Hay casos en los que este patrón es útil, pero generalmente se usan cuando la excepción generada nunca debería haber sido (es decir, cuando se usan excepciones para el comportamiento normal).
Por ejemplo, imagine que tiene una clase que abre un archivo, lo almacena en el objeto que se devuelve. Si el archivo no existe, puede considerar que no se trata de un caso de error, devuelve nulo y deja que el usuario cree un nuevo archivo. El método de abrir archivo puede lanzar una excepción aquí para indicar que no hay ningún archivo presente, por lo que la captura silenciosa puede ser una situación válida.
Sin embargo, no es frecuente que desee hacer esto, y si el código está lleno de ese patrón, querrá tratarlo ahora. Por lo menos, esperaría que una captura tan silenciosa escriba una línea de registro diciendo que esto es lo que sucedió (tiene seguimiento, correcto) y un comentario para explicar este comportamiento.
fuente
null
si eso es lo mejor que el idioma elegido puede ofrecer.Esto es 100% dependiente del contexto. Si la persona que llama de dicha función tiene el requisito de mostrar o registrar errores en algún lugar, entonces obviamente no tiene sentido. Si la persona que llama ignoró todos los errores o mensajes de excepción tampoco, no tendría mucho sentido devolver la excepción o su mensaje. Cuando el requisito es hacer que el código solo termine sin mostrar ningún motivo, entonces una llamada
probablemente sería suficiente Debe considerar si esto hará que sea difícil encontrar la causa del error por parte del usuario; si ese es el caso, esta es la forma incorrecta de manejar el error. Sin embargo, si el código de llamada se ve así
entonces debería tener una discusión con el desarrollador durante la revisión del código. Si alguien implementa tal forma de manejo sin errores solo porque es demasiado vago para averiguar sobre los requisitos correctos, entonces este código no debe entrar en producción, y se debe enseñar al autor del código las posibles consecuencias de tal pereza .
fuente
En los años que pasé programando y desarrollando sistemas, solo hay dos situaciones en las que encontré útil el patrón en cuestión (en ambos casos la supresión contenía también el registro de la excepción lanzada, no considero que la captura y el
null
retorno sean una buena práctica )Las dos situaciones son las siguientes:
1. Cuando la excepción no se consideró un estado excepcional
Esto es cuando realiza una operación en algunos datos, que pueden arrojarse, sabe que pueden arrojarse, pero aún así desea que su aplicación siga ejecutándose, porque no necesita los datos procesados. Si los recibe, es bueno, si no los recibe, también es bueno.
Se pueden tener en cuenta algunos atributos opcionales de una clase.
2. Cuando proporciona una nueva implementación (¿mejor, más rápida?) De una biblioteca utilizando una interfaz ya utilizada en una aplicación
Imagina que tienes una aplicación que usa algún tipo de biblioteca antigua, que no arrojó excepciones pero regresó
null
por error. Por lo tanto, creó un adaptador para esta biblioteca, prácticamente copió la API original de la biblioteca y está utilizando esta nueva interfaz (aún no lanzada) en su aplicación y manejando losnull
cheques usted mismo.Viene una nueva versión de la biblioteca, o tal vez una biblioteca completamente diferente que ofrece la misma funcionalidad, que, en lugar de devolver
null
s, arroja excepciones y desea usarla.No desea filtrar las excepciones a su aplicación principal, por lo que debe suprimirlas y registrarlas en el adaptador que cree para ajustar esta nueva dependencia.
El primer caso no es un problema, es el comportamiento deseado del código. Sin embargo, en la segunda situación, si en todas partes el
null
valor de retorno del adaptador de biblioteca realmente significa un error, refactorizar la API para lanzar una excepción y atraparlo en lugar de verificarlonull
puede ser (y el código generalmente es una buena idea).Yo personalmente uso la supresión de excepciones solo para el primer caso. Solo lo he usado para el segundo caso, cuando no teníamos el presupuesto para hacer que el resto de la aplicación funcionara con las excepciones en lugar de
null
s.fuente
Si bien parece lógico decir que los programas solo deberían detectar excepciones que saben cómo manejar, y no pueden saber cómo manejar excepciones que no fueron anticipadas por el programador, tal afirmación ignora el hecho de que muchas operaciones pueden fallar en un número casi ilimitado de formas que no tienen efectos secundarios, y que en muchos casos el manejo adecuado para la gran mayoría de tales fallas será idéntico; los detalles exactos de la falla serán irrelevantes y, en consecuencia, no debería importar si el programador los anticipó.
Si, por ejemplo, el propósito de una función es leer un archivo de documento en un objeto adecuado y crear una nueva ventana de documento para mostrar ese objeto o informar al usuario que el archivo no se puede leer, un intento de cargar un el archivo de documento no válido no debe bloquear la aplicación; en su lugar, debe mostrar un mensaje que indique el problema pero dejar que el resto de la aplicación continúe ejecutándose normalmente a menos que por alguna razón el intento de cargar el documento haya dañado el estado de otra cosa en el sistema .
Básicamente, el manejo adecuado de una excepción a menudo dependerá menos del tipo de excepción que de la ubicación donde se lanzó; Si un recurso está protegido por un bloqueo de lectura y escritura, y se lanza una excepción dentro de un método que ha adquirido el bloqueo para la lectura, el comportamiento adecuado generalmente debería ser liberar el bloqueo ya que el método no puede haber hecho nada al recurso . Si se produce una excepción mientras se adquiere el bloqueo para escritura, el bloqueo a menudo debe invalidarse, ya que el recurso protegido puede estar en un estado no válido; Si la primitiva de bloqueo no tiene un estado "invalidado", se debe agregar una bandera para rastrear dicha invalidación. Liberar el bloqueo sin invalidarlo es malo porque otro código puede ver el objeto protegido en un estado no válido. Sin embargo, dejar la cerradura colgando no es ta solución adecuada tampoco. La solución correcta es invalidar el bloqueo para que cualquier intento de adquisición pendiente o futuro falle inmediatamente.
Si resulta que un recurso invalidado se abandona antes de que se intente usarlo, no hay razón para que detenga la aplicación. Si un recurso invalidado es crítico para la operación continua de una aplicación, la aplicación deberá ser desactivada, pero invalidar el recurso probablemente hará que eso suceda. El código que recibió la excepción original a menudo no tendrá forma de saber qué situación se aplica, pero si invalida el recurso puede asegurarse de que la acción correcta terminará siendo tomada en cualquier caso.
fuente
Tragar este tipo de error no es particularmente útil para nadie. Sí, la llamada original no puede preocuparse por la excepción, sino alguien más fuerza .
Entonces que hacen? Agregarán código para manejar la excepción para ver qué sabor de excepción están recuperando. Excelente. Pero si se deja el controlador de excepciones, la persona que llama original ya no se anula y algo se rompe en otro lugar.
Incluso si sabe que algún código ascendente podría generar un error y, por lo tanto, volverse nulo, sería muy inerte de su parte no intentar al menos evitar la excepción en el código de llamada IMHO.
fuente
He visto ejemplos en los que las bibliotecas de terceros tenían métodos potencialmente útiles, excepto que arrojan excepciones en algunos casos que deberían funcionar para mí. ¿Que puedo hacer?
Por ejemplo, el método de la biblioteca
devuelve el primer foo, pero si no hay ninguno, arroja una excepción. Pero lo que necesito es un método para devolver el primer foo o un nulo. Entonces escribo este:
No aseado Pero a veces la solución pragmática.
fuente