Hace casi veinte años, obtuve mucha información sobre esto del excelente libro de David Thielen "Sin errores: entrega de código libre de errores en C y C ++", que ahora está disponible como PDF gratuito .
Me enseñó dos grandes ideas ...
Los errores no vienen de la nada. Todos los programadores nos sentamos y los escribimos en nuestro código con nuestros propios dedos.
"Bug" connota que alguna agencia externa decidió infestar su programa con errores y que si vive una vida limpia y sacrifica pequeños animales peludos al pie de su computadora, desaparecerán ... Este concepto es importante porque colorea su enfoque para depurar su código. Si ve los errores como "errores", espera que no se encuentre ninguno. (Esperas que el buen hada haya venido, rociado con polvo de duendecillo y los insectos se hayan ido).
Los errores no deberían llamarse errores, deberían llamarse Fuck-Ups masivos [MFU] ... Las MFU existen porque los programas están escritos por personas y las personas cometen errores ... Usted escribirá MFU. Se sentará y, con total malicia de previsión, colocará MFU en su código. Piénselo: sabe que usted es quien está poniendo los errores allí. Entonces, si te sientas a codificar, insertarás algunos errores.
Como el destino ineludible de todos los programadores es escribir errores, necesito codificar defensivamente, incluidas las cosas que saltarán, gritarán y agitarán banderas rojas cuando detecten un error.
Después de haber sido escrito a principios de los 90, los detalles sobre esto en el libro de Thielen son bastante anticuados. Por ejemplo, en Linux y Mac OS X, ya no necesita escribir su propio contenedor para el nuevo operador de C ++; puedes usar valgrind para eso.
Pero hay algunas cosas que hago habitualmente para C / C ++ / ObjC:
- Cuando pueda razonablemente, active la opción "Advertencias son errores" del compilador y corríjalos todos. (Mantengo un proyecto heredado donde arreglarlos todos a la vez llevaría semanas, por lo que solo arreglo un archivo cada pocas semanas, y en unos pocos años, puedo activar esa opción).
- Use una herramienta de análisis de código estático, como PC-Lint de Gimpel o la muy ingeniosa ahora integrada en Xcode de Apple. La cobertura es aún mejor, pero el costo es para grandes corporaciones, no para simples mortales.
- Use herramientas de análisis dinámico, como valgrind, para verificar problemas de memoria, fugas, etc.
- Como dice Thielen (y aún vale la pena leer el capítulo): Afirma el mundo . Por supuesto, nadie más que un idiota llamará a su función con un puntero nulo, y eso significa que alguien, en algún lugar, es un idiota que hará exactamente eso. Incluso podrías ser tú en tres años cuando lo que estabas haciendo hoy se ha empañado. Entonces, solo agregue una afirmación al comienzo de la función para validar ese argumento de puntero: toma tres segundos escribir y desaparece en el ejecutable de lanzamiento.
- En C ++, RTTI es tu amigo. Nuevamente, nadie más que un idiota llamará a su función con un puntero al tipo de objeto equivocado, lo que significa que, inevitablemente, algún idiota lo hará, y el costo para defenderse es insignificante. En el código basado en C derivado de GObject, puede hacer lo mismo con las macros de conversión dinámica defensiva.
- Las pruebas automatizadas de unidad y regresión ahora son una parte clave de mi repertorio. En un proyecto, son una parte integral del sistema de compilación de lanzamiento, y la compilación no se completará a menos que todos pasen.
- Otra parte clave es el código de registro tanto en los ejecutables de depuración como de liberación que pueden habilitarse en tiempo de ejecución mediante una variable de entorno.
- Escriba pruebas defensivas para que los programadores que ejecutan ejecutables de depuración no puedan ignorarlas si fallan. Los mensajes de tiempo de ejecución a la consola se pueden ignorar. El programa que falla con una afirmación no puede ser ignorado.
- Al diseñar, proporcione API públicas e implementaciones privadas que el código externo no puede alcanzar. De esa manera, si tiene que refactorizar, nadie depende de alguna variable mágica de estado interior o algo así. En las clases de C ++, soy un gran fanático de lo protegido y lo privado para esto. También creo que las clases proxy son geniales, pero realmente no las uso yo mismo.
Por supuesto, lo que harás para un nuevo idioma o tecnología variará en los detalles. Pero una vez que entiendes en tu corazón las nociones de que los insectos son Fuck-Ups masivos que escribiste con tus propios dedos, y tu código está bajo el asalto constante de un ejército de idiotas, contigo a la cabeza como general, estoy seguro de que Descubriré técnicas defensivas adecuadas.