ConstructiCat Logo
CodeBust.
Browse section ▾

Ocultamiento de errores.

No informar de los detalles de un error

En la programación informática, el ocultamiento de errores (o tragado de errores) es la práctica de capturar un error o excepción y luego continuar sin registrar, procesar ni informar del error a otras partes del software. Manejar los errores de esta manera se considera una mala práctica y un antipatrón en la programación informática. En los lenguajes con soporte para el manejo de excepciones, esta práctica se denomina tragado de excepciones.

Los errores y las excepciones tienen varios propósitos:

  • Ayudar a los encargados del mantenimiento del software a localizar y comprender los problemas que ocurren cuando un usuario ejecuta el software, cuando se combinan con un sistema de registro
  • Proporcionar información útil al usuario del software, cuando se combinan con mensajes de error significativos, códigos de error o tipos de error mostrados en una interfaz de usuario, como mensajes de consola o como datos devueltos por una API (según el tipo de software y el tipo de usuario)
  • Indicar que la operación normal no puede continuar, de modo que el software pueda recurrir a formas alternativas de realizar la tarea requerida o abortar la operación.

Cuando los errores se tragan, no es posible cumplir estos propósitos. Se pierde la información sobre el error, lo que hace muy difícil localizar los problemas. Según cómo esté implementado el software, esto puede provocar efectos secundarios no deseados que se propagan en cascada hacia otros errores, desestabilizando el sistema. Sin información sobre la causa raíz del problema, es muy difícil averiguar qué está fallando o cómo solucionarlo.

Ejemplos

Lenguajes con manejo de excepciones

En este ejemplo en C#, aunque el código dentro del bloque try lanza una excepción, esta es capturada por la cláusula catch general. La excepción ha sido tragada y se considera manejada, y el programa continúa.

try {
  throw new Exception();
} catch {
  // no hacer nada
}

En este ejemplo en PowerShell, la cláusula trap captura la excepción que se lanza y la traga al continuar la ejecución. El mensaje "I should not be here" se muestra como si no hubiera ocurrido ninguna excepción.

&{ 
  trap { continue }
  throw
  write-output "I should not be here"
}

El tragado de excepciones también puede ocurrir si la excepción se maneja y se vuelve a lanzar como una excepción diferente, descartando la excepción original y todo su contexto.

En este ejemplo en C#, todas las excepciones se capturan sin importar su tipo, y se lanza una nueva excepción genérica que conserva únicamente el mensaje de la excepción original. Se pierde la traza de pila original, junto con el tipo de la excepción original, cualquier excepción de la que la original fuera un envoltorio y cualquier otra información capturada en el objeto de excepción.

try {
    // hacer algo
} catch (Exception ex) {
    // quizá realizar algún manejo local de la excepción
    throw new Exception(ex.Message);
}

Una forma mejor de volver a lanzar excepciones sin perder información es lanzar la excepción original desde la cláusula catch:

try {
    // hacer algo
} catch (Exception ex) {
    // realizar algún manejo local de la excepción
    throw;
}

Como alternativa, se puede crear una nueva excepción que envuelva la excepción original, de modo que cualquier otro manejador tenga acceso a ambas:

try {
    // hacer algo
} catch(Exception ex) {
    // quizá realizar algún manejo local de la excepción
    throw new CustomException(ex);
}

Otros lenguajes

En Go, los errores se propagan devolviendo un objeto Error junto con el valor de retorno normal de la función. Puede ignorarse, como en este ejemplo.

f, _ := "I should not be here", errors.New("")
fmt.Print(f)

En el caso de las llamadas al sistema de C, los errores se indican cuando el valor de retorno de la llamada es NULL, y la información del error se almacena en una variable global errno. Este código se asegura de que el file sea válido antes de acceder a él, pero si fopen falló, el error se traga.

FILE *file = fopen("", "r");
if (file) {
  // hacer algo con el archivo
}

Causas

La causa subyacente más común del tragado de errores es la falta de buenas herramientas y procesos de registro mientras el desarrollador construye el software. Ante un error que no puede manejarse con facilidad, si el desarrollador dispone de buenas herramientas de registro, registrar un error inesperado no le cuesta tiempo ni esfuerzo. Registrar el error debería ser sencillo (una sola llamada a un método), rápido (sin impacto en el rendimiento de la aplicación), seguro (no genera ningún error ni excepción) y debería garantizar que se guarde toda la información, registrando el tipo de error y cualquier dato relevante asociado a él, la traza de pila del error (para que el desarrollador pueda identificar exactamente dónde ocurrió el error y qué instrucciones lo precedieron) y la marca de tiempo del error.

Manejadores de excepciones temporales

En los lenguajes con excepciones comprobadas, todas las excepciones que se lanzan en un método deben figurar en la firma de ese método. Al crear prototipos e implementar software, el código cambia con frecuencia, lo que significa que el tipo de excepciones que podrían lanzarse en un método también cambia a menudo. Tener que ajustar la firma del método cada vez que algo cambia ralentiza el desarrollo y puede resultar frustrante, por lo que tragar las excepciones como medida temporal mientras se realizan grandes cambios de código resulta tentador. Este código de manejo temporal de excepciones podría acabar en la base de código publicada.

Incluso en lenguajes sin excepciones comprobadas, puede ocurrir que se añadan manejadores de excepciones temporales durante grandes cambios de código para acelerar la creación de prototipos, lo que puede dar lugar al tragado de errores.

Evitar caídas

En situaciones en las que el software no debe caer por ningún motivo, el tragado de errores es una práctica en la que un programador puede caer con facilidad. Por ejemplo, se espera que un complemento que se ejecuta dentro de otra aplicación maneje todos los errores y excepciones de tal manera que no provoque la caída de la aplicación en la que está incrustado. La captura indiscriminada de errores y excepciones es un patrón en el que es fácil caer cuando se intenta evitar caídas a toda costa y, cuando eso se combina con herramientas de registro deficientes, puede producirse el tragado de errores.

Ocultar la complejidad a los usuarios

Al mostrar errores a los usuarios, es importante convertir los errores técnicos crípticos en mensajes que expliquen qué ocurrió y qué acciones puede emprender el usuario, si las hay, para solucionar el problema. Al realizar esta traducción de errores técnicos a mensajes de usuario significativos, los errores específicos suelen agruparse en errores más genéricos, y este proceso puede hacer que los mensajes de usuario se vuelvan tan inútiles que el usuario no sepa qué salió mal ni cómo solucionarlo. En lo que respecta al usuario, el error fue tragado.