Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

?id=9601c6dd-062b-48cb-81ef-631a92ae3693

GAMBADAS: Los tres principales pecados al gestionar errores y excepciones

ElGrito

La gestión de excepciones es una de las cosas más comunes y sencillas que realiza cualquier desarrollador. Se trata de prever y gestionar los posibles problemas que puedan surgir durante la ejecución de nuestro programa, de modo que sea más robusto al saber "reaccionar" de la manera adecuada.

Incluso cuando se producen excepciones que no habíamos tenido en cuenta hay que tener un "Plan B" para gestionarlas y evitar que la aplicación rompa. Pero ni siquiera en este caso es admisible el primero de los errores típicos que vamos a comentar a continuación.

1.- Excepciones Pokemon y demasiada información

Este es uno de los errores más comunes que cometen muchos desarrolladores, independientemente del lenguaje o la plataforma que estén usando. Se trata de revelar demasiada información cuando se produce un error o excepción.

El caso típico más básico de este problema se da en código como este:

try 
{ // Código de una función o método } catch (Exception ex)
{ Console.WriteLine(ex.Message); }

En este fragmento en C# (sería casi idéntico en cualquier otro lenguaje como Java, JavaScript, etc...) lo que se hace es capturar de manera genérica cualquier excepción que se produzca y mostrarla por pantalla. En este caso es a través de la consola, pero podría ser a través de un mensaje en una aplicación de escritorio o en la respuesta de un servidor Web. El concepto es el mismo. Con esto lo que se pretende es cubrir todos los casos y que, pase lo que pase, la aplicación "no rompa".

A esta operación se le llama a veces, jocosamente, "Excepción Pokemon" ya que como dice el eslogan del famoso juego: "¡Atrápalos a todos!" ;-)

Hacer esto presenta diversos problemas. Por ejemplo que no estamos teniendo en cuenta las posibles excepciones particulares que se pueden producir y que debiésemos gestionar de mejor manera (que es el objetivo primordial en este aspecto que debiésemos tener en una aplicación: prever las excepciones). Pero también que si mostramos cualquier mensaje de excepción por pantalla corremos el riesgo de revelar información de valor que puede ser utilizada de forma maliciosa.

El caso más habitual de esto se produce con código de bases de datos, especialmente en aplicaciones web, donde esta información puede quedar al alcance de cualquiera. Por ejemplo, esta es la típica "pantalla amarilla de la muerte" (YSOD: Yellow Screen Of Death) que sacan las aplicaciones de ASP.NET Web Forms cuando hay un error no controlado (sería lo mismo que mostrarlo por pantalla como en el fragmento anterior):

YSOD-BaseDatos-Movistar

Pulsa para aumentar

En este caso vemos que un error de esta naturaleza, mostrado así directamente sin filtro al usuario, además de dar muy mala imagen ofrece un montón de información peligrosa en manos de un posible atacante. En este fragmento (de una aplicación real) vemos mucha información sobre la estructura de la base de datos que usa la aplicación (nombres de campos y de tablas, tipos de datos utilizados...) e incluso la ruta física en el servidor que se está utilizando para almacenar los archivos de la aplicación (abajo del todo). Un peligro y oro puro para un atacante.

Ojo, este no es solamente el comportamiento por defecto de ASP.NET: pasa exactamente igual en casi todas las plataformas de servidor.

Consejo: trata de gestionar todas las excepciones de manera individual y no de forma genérica, y en cualquier caso si tienes un capturador "Pokemon" jamás muestres por pantalla o de manera accesible al usuario los detalles del error. Si se trata de un gestor genérico del entorno (como en el caso de plataformas Web) cambia su comportamiento por defecto para que solo muestre los detalles de error localmente, pero jamás a los usuarios.

Más detalles en la Common Weakness Enumeration.

2.- Las excepciones fantasma y ninguna información

Este caso es justo el opuesto al anterior, pero es también extremadamente común.

Una tentación enorme que existe es la de hacer caso omiso de las excepciones no planeadas que se produzcan. Es decir, si se produce una excepción con la que no contábamos, simplemente la capturamos para que no rompa la aplicación y no hacemos nada más. El código sería algo como esto:

try 
{ // Código de una función o método } catch (Exception ex)
{ }

Es decir, casi lo mismo que antes pero sin hacer absolutamente nada en el catch. Se podrían capturar otras excepciones especializadas previas, pero si tienes una al final "por si acaso" que además no hace nada, es un tremendo error y una fuente de futuras frustraciones. ¿Por qué?

Pues porque cuando se produzca una error que no tenías contemplado en tu código ni siquiera te enterarás. Algo fallará pero no quedará rastro de ellos. Por eso te resultará casi imposible averiguar qué está pasando, y mucho menos aún depurar la aplicación.

Consejo: este sería el caso opuesto al anterior. Si hay algo peor que dar demasiada información es hacer que el error nunca deje rastro. Deberás loguear a algún lugar privado (base de datos, archivo...) los detalles del mismo para poder estudiarlo, aunque no llegue a trascender jamás a usuario final.

3.- Los gemelos golpean dos veces

Otro clásico de los errores a la hora de gestionar excepciones es relanzar de cualquier manera la excepción que se acaba de producir. Se trata de código similar a este:

try
{
   //Código de nuestra función o método
}
catch (Exception ex)
{
   //Hacemos algo para paliar el problema y lanzamos de nuevo la excepción
   throw ex;
}

Hay ocasiones en las que es interesante relanzar una excepción. Por ejemplo, si queremos que quede capturada por un manejador superior en la jerarquía de gestión estructurada de excepciones para que, por ejemplo, la deje registrada. O bien si hemos capturado una excepción en un componente de terceros (en otra DLL o control) y queremos gestionarla y registrarla (más "arriba") pero que no se enteren los usuarios... Casos por el estilo.

De todos modos si vamos a relanzarla debemos tener en cuenta dos cosas importantes:

  1. Suele ser buena idea envolverla en otra excepción (como InnerException) dando detalles adicionales en lugar de lanzarla de nuevo directamente. De este modo podemos dar información adicional de contexto a la excepción original, facilitando la depuración.
  2. Existe una diferencia enorme entre lanzar una excepción como se ve en el fragmento anterior (o sea throw ex;) entre Java y C#. En el caso de Java no hay problema con hacerlo así, ya que se conserva toda la información de la excepción original; pero en C# si la lanzamos de esa manera es como si se generase una excepción nueva y no se conserva la información de la pila de llamadas, por lo que perdemos toda la información de contexto de dónde se produjo más abajo en la pila de llamadas, y nos va a dificultar la depuración. Es muy importante y un error común. La manera correcta de hacerlo es llamar simplemente a throw, sin pasarle parámetro alguno, lo cual relanzará la última excepción tal cual y conservará toda la información de ésta. ¡Ojo!

Consejo: si relanzas una excepción en tu programa debes tener la seguridad de que servirá para algo y que no estás cometiendo alguno de los otros errores que hemos mencionado. Si la lanzas es buena idea envolverla en otra excepción si puedes darle mayor información a la función superior que se encargará de gestionarla. Si simplemente devuelves la misma excepción, en la plataforma .NET/C# deberás lanzarla simplemente con throw, sin pasarle la excepción original como parámetro para evitar que se pierda información sobre la pila de llamadas.

En resumen

En tus aplicaciones, sean del tipo que sean, deberías prestar atención a la manera en la que gestionas los errores y excepciones. Aquí hemos resaltado solamente los más comunes y sencillos, pero deberías tratar siempre de pensar en qué errores y situaciones excepcionales se pueden producir en tu código y luego:

  1. Evitar capturar todos los errores porque sí. Es aconsejable ir capturando individualmente cada tipo y solamente dejar para un gestor general los que no hayas tenido en cuenta.
  2. Este gestor general de excepciones no debería jamás de los jamases dar detalles sobre la excepción a los usuarios finales, solo guardar la información en algún sitio accesible únicamente por los encargados del soporte y la depuración.
  3. Nunca dejes que los usuarios vean las pantallas de error por defecto que tienen las diversas plataformas y lenguajes. Muestran demasiada información y además dan mala imagen. Haz una personalizada y controlada por ti.
  4. Cuidado cómo relanzas las excepciones y con qué objetivo.
  5. Lleva un registro detallado y privado de todas las excepciones no controladas que se produzcan en tu aplicación. Y revísalo a menudo para adelantarte a los problemas de los usuarios. Es posible que algunos de ellos ni siquiera hayan salido a la superficie y los podrás arreglar antes de que se hagan evidentes.

¡Espero que te resulte útil!

Fecha de publicación:
José Manuel Alarcón Fundador de campusMVP, es ingeniero industrial y especialista en consultoría de empresa. Ha escrito diversos libros, habiendo publicado hasta la fecha cientos de artículos sobre informática e ingeniería en publicaciones especializadas. Microsoft lo ha reconocido como MVP (Most Valuable Professional) en desarrollo web desde el año 2004 hasta la actualidad. Puedes seguirlo en Twitter en @jm_alarcon o leer sus blog técnico o personal. Ver todos los posts de José Manuel Alarcón
Archivado en: DevFacts | General

Boletín campusMVP.es

Solo cosas útiles. Una vez al mes.

🚀 Únete a miles de desarrolladores

DATE DE ALTA

x No me interesa | x Ya soy suscriptor

La mejor formación online para desarrolladores como tú

Comentarios (1) -

David Marco
David Marco

Buen artículo. Para quien esté interesado en alguna técnica más, un artículo que escribí hace algún tiempo: www.davidmarco.es/.../tratamiento-de-excepciones-en-java

Responder

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.