martes, 23 de diciembre de 2014

Bibliotecas externas en versión debug

Siempre pensé que era mejor utilizar versiones "release" de las bibliotecas de terceros en mis proyectos, para todas las compilaciones, aún en mis versiones para debug. Es decir, que si mi programa usa una biblioteca B, al depurarlo me interesa solo depurar mi parte. Agregar la información de depuración de B sería agregar ruido. Hace poco comprobé que esto no siempre es recomendable. Es algo que ahora me parece muy obvio, pero la verdad es que antes no le había dado importancia. Nunca había usado intensivamente una versión debug de una biblioteca externa, y por eso no había notado las muchas ventajas que esto tiene.

Vamos con un ejemplo: en PSeInt y en ZinjaI utilizo la biblioteca wxWidgets (wx desde ahora). Cuando se manifiesta un error, en principio asumo que es mio (que no es un error de wx), e intento depurar mi propio código para ver donde metí la pata. Al hacerlo, no quiero meterme adentro de wx, ya que estoy asumiendo que el error está afuera, de mi lado (lo cual suele ser cierto). Entonces, en principio, no necesito información de depuración en wx, solo la de mis propios objetos. Usar una versión debug de wx implicaría hacer más lenta la ejecución (sería una versión no optimizada), más lenta la depuración (habría más información de depuración que cargar y analizar para gdb), más engorrosa (al ir paso a paso me metería dentro de wx a cada rato), etc.

Unas pocas veces pensé en re-compilar wx con su información de depuración. Estas veces pueden agruparse en dos tipos de situaciones. Una se da cuando mi programa revienta dentro de la biblioteca, aún por un error que viene de afuera (de mi lado): ver qué es lo que explota dentro de wx (suponiendo que entienda qué está haciendo wx) puede darme alguna pista de cómo se llegó hasta ese punto y qué es lo que hice mal antes. La otra situación se da cuando de verdad creo que el error está en wx, o cuando quiero entender cómo funciona por dentro algo que no está bien detallado en su documentación. Me he topado algunas pocas veces con estas situaciones y siempre me las arreglé solo inspeccionando sus fuentes,o a lo sumo con un poquito de prueba y error para complementar. Pero hace poco tenía un problema que no podía identificar correctamente ni terminar de entender de dónde venía, así que finalmente junté paciencia y me puse a recompilar wx en modo debug, para analizarlo desde el depurador.

Me llevé una grata sorpresa al ver que en modo debug wx realiza una gran cantidad de verificaciones adicionales, y que tiene además un mecanismo propio muy útil para notificar cuando estas verificaciones fallan. Digamos que está llena de asserts (programación defensiva), que se aseguran de que las llamadas a métodos y funciones sean coherentes. Por ejemplo, no es lógico pedirle a un string que representa la palabra "Hola" la subcadena que va de la letra 10 a la 15, ya que no hay tantas letras en esa palabra. En release, estos problemas pueden caer en lo que se conoce como "comportamiento indefinido", y pasar en muchos casos inadvertidos. En debug, wx verifica estas cosas y avisa, con una ventana especial, que hasta muestra un trazado inverso, y ofrece detener el programa, o continuar como si nada. No es responsabilidad de wx verificar esto, es en principio problema nuestro si la usamos mal, si no leemos la documentación, o si no respectamos el "contrato" que plantea cada interfaz de clase o función. Pero aún así wx, de yapa, en modo debug nos da una mano, verificando lo esencial, y avisando con bastante detalle sobre cada error en tiempo de ejecución.


Y de pronto, después de usar por años wx, veo que mi código tenía cientos de errores como esos que no se habían manifestado antes, muchos bastante tontos y simples de solucionar (y un puñado que todavía no pude resolver). Pero en cualquier caso puedo concluir que es altamente recomendable utilizar las versiones debug de bibliotecas como esta. No siempre es el caso, ya que insisto en que si la referencia dice "no llamar a esta función con 0", no es responsabilidad de la biblioteca verificar si recibe o no un 0, y entonces la mayoría no lo hace. Y si no lo hace, no gano nada con la versión debug. Pero es bueno saber cuales sí, porque nos pueden ahorrar mucho tiempo de depuración y varios dolores de cabeza. Obviamente, al final del día, cuando el proyecto está listo y libre de errores, la versión final sí se compila con bibliotecas "release", y así ya no pierden valioso tiempo de ejecución con estas validaciones supuestamente innecesarias.

2 comentarios:

  1. Muy bueno, Pablo. ¿Se sintió la diferencia en tiempo de depuración al final?

    ResponderEliminar
  2. Thanks for sharing, nice post! Post really provice useful information!

    Giaonhan247 chuyên dịch vụ ship hàng nhật uy tín, giá rẻ cũng như chia sẻ kinh nghiệm cách order taobao về VN giá rẻ.

    ResponderEliminar