Diego's profileZonaDiegumPhotosBlogListsMore Tools Help

Blog


    September 18

    Haciendo lugar a la Excepción

     Las  plataformas modernas de desarrollo de software consideran el concepto de Excepción (Exception) como una pieza fundamental (hay que tener en cuenta que lenguajes más antiguos como C, Cobol o Pascal no las contemplaban). Comandos como try - catch hoy son moneda corriente tanto en Java como en la plataforma .NET
    No obstante, quizás es mi impresión, nunca quedó del todo claro cual es la forma correcta de manejar las excepciones, y eso ha conllevado a malestares tanto al desarrollar el software como al mantenerlo. Y, en ocasiones, también al usarlo. Voy a resumir acá cuatro antipatterns. La lista es más extensa
    • "Excepcionalización" exagerada
      Supe del caso de un proyecto donde se tomó la decisión de aprovechar el concepto de excepción para abordar cualquier situación anómala. Todas las situaciones anómalas. Así, los módulos de ingreso de datos validaban la información recibida y si algún campo obligatorio estaba en blanco o un código no respetaba una dada máscara, eso arrojaba excepción. Simplemente porque la política era lanzar excepción ante toda condición anómala
      Por supuesto esto encareció el costo de codificación, ya que toda esa plomería de lanzado y captura de excepciones quedó como responsabilidad de los desarrolladores. Pero no fue todo. El código se volvió ilegible, ya que la gestión de estas excepciones estaba varias líneas de código más lejos. Ocasionalmente varios módulos en la pila de llamadas (callstack) más lejos
      Entonces podemos decir que se han provocado dos consecuencias no deseadas: demasiado código (too much code) e ilegibilidad
      Un enfoque más adecuado en este caso debería haber manejado las validaciones in situ, y ante datos mal cargados devolver el control señalando los errores en una forma sencilla y directa. Sin complicarse la vida
    • Intervención innecesaria
      Es normal tener bloques de código que incluyan llamadas a módulos que puedan arrojar excepción. Lo antinatural, acepto que no todos piensan como yo, es tener que prepararse siempre para reaccionar ante cada posible excepción. Recuerdo mi paso por el banco multinacional donde era imperativo encerrar entre try - catch todo aquel bloque de código de esta naturaleza, y estaba prohibido no hacer nada dentro del catch. Resultado: la dirección del proyecto terminó pidiendo a ciertos miembros del equipo de desarrollo que construyeran un robot que revisaba permanentemente el código del resto del equipo, buscando la presencia de catchs vacíos. Con el tiempo la dirección del proyecto terminó convenciéndose de que no siempre hay algo para decir ante la presencia de una excepción, pero sólo flexibilizaron su postura (y consiguientemente el robot) permitiendo que en esos casos se documentara con un comentario dentro del catch explicando por qué no se iba a intervenir. Hecha la ley hecha la trampa: a partir de ese día todos los desarrolladores comenzaron a poner comentarios del tipo /* dskjhdsakf fhdskahda dafhkjh */ y el arturito ése nunca más encontró excepciones mal manejadas
      Lo cierto es que en cada segmento de código habrá invocaciones a módulos que arrojaran excepciones que podremos manejar, donde podremos intervenir en consecuencia, y excepciones ante las cuales no tendrá sentido nuestra intervención. Ejemplo de esto último? El módulo de acceso a datos vuelve con SQLException quizás porque el string de conexión tiene expirada la contraseña. La llamada se hizo en la capa de negocio de la aplicación. Tiene sentido capturar allí esa excepción? Acaso tiene sentido establecer una nueva contraseña allí?
      Lo mejor es dejar que la excepción pase de largo hacia capas superiores. O bien, sí, acepto. Enmascararla en un tipo de excepción de más alto nivel pero sin perder la excepción original (la root cause que es la que tiene el stack trace genuino). Ver siguiente.
    • Inacción negligente
      Es el opuesto al caso previo. Es cuando, por el contrario, dejamos pasar siempre las excepciones que se produzcan y nunca intervenimos ni siquiera para enmascarar ciertos errores y así no estampar en la jeta del usuario el error del caso anterior donde la contraseña de la base de datos había expirado
      No intervenir nunca, como política, conduce a código de ejecución impredecible, pobremente documentado y esto atenta contra su fiabilidad por parte de los desarrolladores y su usabilidad por parte de los usuarios
      Cuál debiera ser la correcta intervención para no caer en el antipatrón anterior? Como contaba antes, enmascarar adecuadamente el error de bajo nivel en uno del nivel del módulo en que nos encontramos. Especial atención aquí, como decía previamente, de anidar la excepción original ya que la excepción nueva será para presentar en el nivel contextual en que nos encontramos, pero la original servirá, en última instancia, por saber que fue lo que lo provocó. En otras palabras, la excepción actual será la que se presentará al usuario de la aplicación. La original será la que se logueará para que el equipo de sistemas conozca lo que ocurrió realmente y pueda prevenirlo a futuro. Creo que todos alguna vez nos hemos topado con un sitio web donde al pulsar un botón de acción hemos recibido un bello mensaje en letras rojas, estilo [ODBC Exception, SQL code = ...]. Mejor hubiera sido loguear ese error y presentar al usuario Momentáneamente no fue posible realizar su reserva
    • Tratamiento inoportuno
      Un cliente alguna vez me reclamo de la poca fiabilidad de .NET respecto del manejo de excepciones. Me decía que ellos como política, ante cierto rango de excepciones tenían un handler que invocaban en el catch, que a su vez generaba un registro con la excepcion a fin de tomar estadísticas mensuales de los fallos que el código producía. Su recriminación hacia .NET era que mientras el handler estaba generando el registro en la base, el usuario web quedaba esperando como un tonto una respuesta que encima iba a ser anómala
      La realidad es que la lógica de un catch se ejecuta by design en el mismo hilo que la lógica que provocó la excepción. Por consiguiente si estamos urgidos por anunciar al usuario que no se pudo, pero a la vez queremos generar el registro para estadísticas, lo aconsejable aquí es aplicar mecanismos de fire and forget en el handler de excepciones. Ejemplo? Postear un mensaje en una cola cuyo consumidor -necesariamente en otro hilo- completará la acción de registrarlo en la base de datos. Entonces el handler sólo postea a la cola y devuelve el control al catch que lo invocó que a su vez terminará y devolverá el control al cliente. La lógica de persistencia queda entonces desacoplada y se ejecutará en forma asíncrona

    Invito a contar vuestras experiencias, antipatterns y sus consiguientes best practices en el manejo de las excepciones

    Comments (2)

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    Diego Dagumwrote:
    Y creame que ni siquiera es patrimonio de Sudamérica hacer mamarrachos con el manejo de excepciones. El ejemplo que yo contaba del robot q vigilaba que los developers capturen las excepciones todas fue en Madrid. Y acá en el fundo de don Sam también he visto cosillas por el estilo
     
    Doble frustración como sudaca que soy me he llevado: no sólo somos truchos para manejar excepciones. Ni siquiera somos truchos originales   :-P
     
    Abrazo, estimado 
    Sept. 2

    Diego,

     

    Después de leer tu post, solo he podido llegar a una sola conclusión. El criterio muchas veces decidirá cuándo y por qué capturar o no una excepción, y qué hacer con ella. Lamentablemente el criterio no es un bien público.

     

    Dentro de mi experiencia, cuando desarrollé en IC, usábamos mayormente try/finally y rara vez try/catch. Nunca nos interesó capturar una excepción en medio del código con la cual no pudiésemos hacer nada. La excepción subiría hasta la capa de presentación o capa superior en caso de ser un servicio Windows, y loguebamos un error, asíncronamente por supuesto (fire and forget).

     

    En mis viajes por Sudamérica, he visto cada cosa, y lo más triste es que cuando preguntas por qué lo hacen así, no tienen idea. Seguramente picaron código en algún sitio web y creyeron que con eso estaban listos. Un ejemplo típico es:

     

    try

    {

        código

    }

    catch (exception ex)

    {

        throw ex;

    }

     

    Con este código horroroso, además de perder la excepción original, agregas un par de stacks al frame, obligas a realizar muchas más instrucciones de las necesarias.

     

    Criterio, eso es lo que más escasea.

     

    Saludos,

     

    Patrick

    Sept. 2

    Trackbacks (1)

    The trackback URL for this entry is:
    http://diegumzone.spaces.live.com/blog/cns!1AD5096D63670065!150.trak
    Weblogs that reference this entry