Manejo de excepciones: Consejos

En lenguajes de programación orientados a objetos (O-O) existe un mecanismo que permite que las aplicaciones manejen situaciones no esperadas de una forma apropiada; esto significa que la aplicación puede intentar recuperar el estado que tenía antes de darse dicha excepción en el mejor de los casos; en el peor, si la recuperación no es posible, abortar la operación o liberar recursos y cerrar la aplicación de forma ordenada. El manejo de excepciones constituye, pues, una potente herramienta para lograr robustez y estabilidad en nuestros programas.

A pesar de las ventajas de esta herramienta, no es cuestión de poner bloques try-catch-finally por doquier y ante cualquier situación; se trata de un asunto de diseño detallado decidir qué nivel de la aplicación es capaz de gestionar una excepción adecuadamente, y qué decisión tomar una vez que se ha dado una excepción: si es posible recuperarse o por el contrario hay que abortar.

En las siguientes líneas centraremos el discurso en el caso particular de .NET. Además, supondremos que el lector tiene conocimientos básicos sobre las excepciones: sintaxis y uso de las mismas a un nivel básico. A pesar de que el texto está centrado en .NET, lo que aquí se trata es válido para cualquier lenguaje de programación O-O, pues veremos aspectos de diseño detallado.

Jeffrey Richter, en el libro que abajo menciono, incluye un completo capítulo sobre Excepciones y su tratamiento, incluyendo una serie de interesantes consejos que, de tenerlos en cuenta, nos permitirán un uso inteligente y apropiado de las excepciones, sacando el máximo partido de las mismas.

En primer lugar, una excepción no sirve solamente para manejar errores y/o situaciones inesperadas. Una excepción debe ser lanzada cuando se detecta una situación en la cual un método no puede realizar su función adecuadamente. Es decir, es una buena idea utilizar excepciones como sustitutas de aquello de retornar códigos de error, mucho menos mantenibles y entendibles por quien lee el código. Si la operación terminó es que fue bien; si no, se lanza una excepción con un mensaje adecuado que el receptor debe saber tratar.

Además, en el caso de .NET, es conveniente evitar en la medida de lo posible System.Exception; en su lugar es mejor utilizar algo más específico, porque ello nos permite utilizar bloques catch específicos para tratar cada tipo de excepción de forma más concreta y controlada. Si la jerarquía de excepciones de System.Exception no se adecúa a tus intereses, crea la tuya propia, haciendo que hereden directamente de System.Exception. Diseña cuidadosamente dicha jerarquía pensando en quién va a usar tu código. Además, si vas a definir tus propias excepciones, es una buena idea hacerlas serializables para poderlas guardar en un log, base de datos, etc.

Valida los argumentos de tus métodos; utiliza el manejo de excepciones para implementar programación bajo contrato: si no se cumplen las precondiciones del método, lanza una excepción. De este modo es más probable que el método termine correctamente, una vez satisfechas las precondiciones. Puedes utilizar una ArgumentException o cualquier tipo hijo de éste, o crear tu propia excepción como se indicó más arriba.

Recuerda utilizar bloques finally para liberar recursos allí donde fuere necesario: cerrar buffers de lectura o escritura, conexiones a bases de datos, etc. El bloque finally es un mecanismo muy elegante para dejar el entorno estable, ocurra lo que ocurra en la ejecución del método. Una nota importante aquí es que evites introducir código que pueda lanzar una excepción dentro de un bloque finally, porque si salta una excepción en dicho bloque se enmascarará una posible excepción que nos llevó al bloque finally con la nueva y perderemos la información relativa a aquella excepción.

No captures todo siempre: un método debe capturar aquellas excepciones para las cuales esté preparado, no “tragarse” todo. Las excepciones deben tratarse en el nivel adecuado. Es decir: evita a toda costa utilizar bloques catch vacíos. Si el nivel actual no está preparado para manejar la excepción, relánzala con throw.

A tenor de lo indicado antes, intenta ser específico al capturar excepciones, distingue entre los tipos de excepciones que te puedan llegar y trátalos en consecuencia de forma específica, en distintos bloques catch.

Espero que hayáis encontrado útiles estos consejos. Os recomiendo el libro del que he extraido estas notas; tiene algunos capítulos realmente interesantes, como el mencionado de las excepciones y el del recolector de basura, del que es posible que dedique algunas líneas aquí próximamente. Además trata aspectos del CLR de .NET en profundidad, explicando cómo funcionan las cosas desde el núcleo del framework.

Hasta la próxima.


CLR via C#
Jeffrey Richter

 

4 pensamientos en “Manejo de excepciones: Consejos

  1. Respecto a esta parte

    “No captures todo siempre: un método debe capturar aquellas excepciones para las cuales esté preparado, no “tragarse” todo. Las excepciones deben tratarse en el nivel adecuado. Es decir: evita a toda costa utilizar bloques catch vacíos. Si el nivel actual no está preparado para manejar la excepción, relánzala con throw.”

    En algún libro sobre buenas prácticas (lástima que no recuerde cual es) leí que si un catch simplemente iba a hacer un throw era mejor no poner, ya que el propio framework sube la excepción por la pila de llamadas hasta que encuentre un manejador para la excepción. Vamos que hay que evitar este tipo de códigos

    try
    {
    // tu código
    }
    catch
    {
    throw;
    }

  2. ¿Y por qué es malo que el framework suba la excepción por la pila de llamadas hasta que encuentre un manejador para la excepción? Creo que esa es la idea. No se pierde la traza en la pila de llamadas ya que se hace un throw y no un throw new Exception, lo cual sería erróneo.

    • En mi opinión, todo código “de más” sólo puede dar problemas. Simplemente, si nos acostumbramos a poner código “de más”, y teniendo en cuenta que el noventa por ciento del código “se genera” copiando y pegando, es fácil que se comentan errores, cuando no se debería haber escrito nada (estoy pensando en try/catch vacios y que por tanto se acaban comiendo el error),
      Yo intento ser lo más realista posible, el desarrollador medio va muy estresado o simplemente tiene momentos de llamemosle “vacio mental”, por eso mi filosofía es que cuanto menos deba picar/pensar un desarrollador, menos fallos comenterá.

      • Dios mío, no me puedo creer lo que estoy leyendo:
        – El 90% del código que se genera es copiando y pegando -> Espero que esto sea falso; al menos yo no lo he visto nunca.
        – cuanto menos deba picar/pensar un desarrollador, menos fallos comenterá. -> Creí que el trabajo de desarrollador era una tarea de ingenio y que para realizar tareas repetitivas están las máquinas y para darle al coco las personas, oséase, los desarrolladores.

        Te recomiendo estos dos libros:
        The Clean Coder, de Robert Martin.
        Clean Code, de Robert Martin.

        No, este tío no me paga por publicitar sus libros, pero me cambió como profesional definitivamente. Si piensas como dices arriba o tu entorno profesional te hace pensar así, deberías plantearte seriamente en cambiar de trabajo.🙂

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s