14 pasos para depurar tu software

pasos depuración software

La capacidad de encontrar y resolver errores de forma rápida y eficaz en aplicaciones nuevas o heredadas es como programador de software una de las habilidades más valiosas que puedes llegar a desarrollar. Dado que esta habilidad permite el rápido desarrollo y mantenimiento de sistemas de ingeniería informática de alta calidad, esta destreza resulta fundamental para muchas empresas tecnológicas, y es una de las habilidades más preciadas y buscadas en cualquier profesional que se dedica al desarrollo de aplicaciones de software.

No obstante, esta habilidad rara vez se evalúa en las entrevistas y en las pruebas que se hacen a los candidatos que optan a un puesto de trabajo como programador.

Nuestro equipo de desarrollo ha depurado y resuelto muchos problemas difíciles en muchos tipos de aplicaciones y sistemas, desde los consultores y los miembros del equipo de soporte que ayudan a nuestros clientes a depurar sus aplicaciones hasta nuestro equipo de desarrollo encargado del desarrollo de la plataforma completa de programación de aplicaciones empresariales Velneo y que se enfrentan al duro trabajo de depuración de errores para garantizar que todo funcione bien.

El procedimiento óptimo para encontrar y corregir errores es esencialmente el mismo para todos los casos. Sorprendentemente, muchos desarrolladores de software no tienen una noción clara y práctica del proceso. En este post vamos a repasar 14 pasos para depurar tu software. Esperamos que te sirva de ayuda.

Paso 1: asegúrate bien de saber lo que sí está funcionando

Cuando algo no funciona como se esperaba, es fácil dar por sentado que nada está funcionando bien. Tómate un tiempo para ver qué cosas sí están funcionando bien en torno al ámbito del problema. Esto te ayudará a delimitar el problema y crear una imagen clara en tu mente de su alcance.

Paso 2: localiza con precisión lo que no está funcionando

En el proceso indicado en el paso anterior para determinar lo que sí está funcionando, se identificará un conjunto de operaciones que no funcionan. Dedica tiempo a la elaboración de esta lista. Ten claro exactamente en qué cosas concretas el sistema no funciona como se esperaba.

A pesar de que puede parecer que estos primeros pasos no tienen sentido porque el problema es “obvio”, a menudo pasar a resolver el problema sin hacer un buen análisis de situación previo puede llevar a perder tiempo y esfuerzo, y, además, a dar una solución parcial o no óptima.

Paso 3: Simplifica el problema

El error de una aplicación de software que se descubre o sale a relucir en una situación compleja puede ser difícil de reproducir, especialmente cuando hay efectos no deterministas o estadísticos. Cualquier intento de simplificar el caso de prueba a la par que se conserva la reproducción del error siempre es un tiempo bien invertido.

Por ejemplo, si el error se produce al procesar un conjunto de datos muy grande, es posible que quieras intentar reproducir el problema con datasets cada vez más pequeños. Por supuesto, este ejemplo no sería posible si el problema está relacionado con conjuntos de datos grandes. En ese caso, crear un conjunto de datos simple aunque grande podría tener más sentido.

Delimitando gradualmente la situación o el contexto en la que surge el problema, no sólo aumentas tu claridad de miras acerca de lo que hace y no funciona, sino que, de manera natural, empiezas a construir tus propias hipótesis sobre lo que podría estar causando el problema.

Los casos de prueba simples son útiles para comunicar con precisión el error a terceros, para probar rápidamente si los cambios afectan al error, y también pueden convertirse en parte de tus pruebas de anti-regresión (consulta el paso 7). Puesto que los casos de prueba simples generalmente se pueden ejecutar rápidamente, también apoyan la prueba de la hipótesis (véase el paso 5).

Paso 4: establece hipótesis

Quizás llegues a este punto después de minutos, horas, días o incluso semanas de trabajo. No importa cómo llegues hasta aquí, o cuánto tiempo te tomó, ahora tendrás datos, y habrás aprendido algo acerca de la forma en que el problema se manifiesta. Este conocimiento te permite formar hipótesis acerca de lo que podría estar causando el error. Estas son teorías acerca de qué proceso dentro (o incluso fuera) del sistema podría estar conduciendo al comportamiento problemático observado en tu aplicación de software.

Paso 5: prueba tus hipótesis usando el ‘divide y vencerás’

Toma cada una de tus hipótesis y pruébalas de una en una, indaga en tu sistema y encuentra una sub-unidad donde creas que algo puede estar yendo mal. A continuación, ejecuta tu pequeño caso de prueba y observa el comportamiento interno de software hasta antes de esa sub-unidad y después de la misma. Si encuentras un problema antes de la sub-unidad, entonces tu hipótesis probablemente sea incorrecta, y al menos ya sabes lo que tienes que hacer: investigar más atrás hacia la entrada del sistema. Si, por el contrario, la entrada a esa parte del sistema parece correcta, pero la salida parece incorrecta, entonces tienes evidencias de que tu hipótesis no va por mal camino y puedes ir delimitando el mismo, acercándote al origen del mismo.

En este punto, si no estás completamente seguro de dónde está el error, entonces aplica vuelve al paso 1 de este artículo y aplícalo solo a esa  sub-unidad que ya has delimitado como posible origen del error.

Hay programadores que aplican este punto 5 de divide y vencerás de una manera más ingenua, sin establecer hipótesis previas. Dividen el programa en dos mitades, buscan en qué mitad del sistema ocurre el error, y luego ponen el foco en la parte que no funciona. Aunque parece una buena idea, este enfoque a la hora de depurar errores en software suele ser más lento y engorroso.

En verdad, analizando cada sub-unidad -en base a la fijación de una serie de hipótesis antes de hacer nada- se ahorra mucho tiempo y esfuerzo aunque pueda parecer lo contrario. Cualquier grieta que pueda aparecer en base a hacer conjeturas lógicas te obliga a repensar y mejorar tu sistema, a encontrar errores y a prevenir bugs futuros.

Divide tu software en sub-unidades de funcionalidad para analizar los errores y siempre vencerás. Pones el foco en el input de la sub-unidad y en su salida, y te permite delimitar el ámbito del problema con mucha más precisión. Si tienes un hipótesis razonada sobre los puntos críticos donde puede romper el software, vas a la entrada de esa sub-unidad y si funciona bien, vas a la salida. Si todo funciona según lo esperado vas a la siguiente sub-unidad que según tus hipótesis puede ser errática y haces la prueba, en orden, para ir arrinconando el ámbito del bug. Esto permite hacer un zoom muy rápido en el bug.

Solo pasa al siguiente paso una vez que tengas claro cuál es el error.

Paso 6: piensa en otra clase de esta versión del bug identificado

A veces los errores son causados por errores tipográficos simples, o fallos que solo ocurren una vez, y este tipo de errores sólo se pueden identificar en aislamiento. Sin embargo, es mucho más común que los bugs que identifiques sean representativos de un tipo de problemas mucho más grandes.

Después de dedicarle el tiempo y el esfuerzo para llegar a este paso, por lo general tendrás una percepción increíblemente clara de las partes pertinentes del sistema y del problema identificado. Serás un experto de clase mundial en este tipo de bug que acabas de localizar. Por esta razón, justo es ese el momento de aprovechar todo ese conocimiento adquirido. En un mes, ya no tendrás la misma claridad de percepción con respecto a este problema específico.

Así que dedícale tiempo en ese momento para aprovechar plenamente tu inversión de esfuerzo. Piensa y documenta la clase general de error, y piensa si el sistema probablemente manifestará otras expresiones de los problemas subyacentes, independientemente de que esas expresiones concretas se hayan manifestado ya en ejecución para los usuarios o no. Es lo que se denomina la depuración de errores preventiva. Te anticipas a otros posibles problemas del sistema basadas en la misma lógica de programación que generó el error.

No es muy buena idea eliminar un tumor sin saber si ese tumor se ha reproducido en el resto del organismo, independientemente de si el paciente lo haya identificado o no.

Paso 7: genera pruebas de regresión

Incluso si no diseñas sistemas de software utilizando el desarrollo guiado en pruebas, te recomiendo que sí utilices la corrección de errores del desarrollo guiado en pruebas.

Asegúrate de escribir las pruebas de nivel de unidad y/o de nivel de sistema que ejercen la mayor cantidad posible de la clase del error. Asegúrate de que las pruebas que esperas que fallen, de hecho fallen. La razón principal por la que existe el error en primer lugar es porque no se hicieron pruebas para identificarlo. Esto significa que hubo un agujero ,una laguna, en el conjunto de pruebas. Muchos desarrolladores opinan que si algo no se prueba, es imposible que funcione  bien y seguro que va a romper. Los buenos programadores asumen por defecto que una aplicación siempre rompe o romperá en algún momento en el futuro. Y lo cierto es que la mayoría de los bugs los encuentran los clientes…

Ya que sabes que el software falla debido a un bug concreto que ya has identificado, es una oportunidad perfecta para desarrollar pruebas, y de asegurarse de que en verdad fallan. Estas oportunidades no surgen a menudo, así que sácales todo el provecho que puedas.

Cuando hacemos pruebas de regresión, estamos comprobando que el código que hemos modificado se comporta como queremos, y que el cambio no ha causado otros problemas en otros sitios del código, que funcionaban correctamente la última vez que los probamos.

Paso 8: arregla los errores

Si has sido diligente hasta este paso, solucionar ahora los errores será extremadamente fácil; es solo una mera formalidad.

Este tipo de corrección de errores se puede realizar con mucha calma y confianza. La solución está ya encauzada en un proceso de ingeniería de software de alta calidad, un proceso que nos indica y prueba la solución al bug. En contraste, muchos desarrolladores operan en el extremo opuesto, cambiando el código casi al azar con la esperanza de que así se solucionará el problema general. Ese tipo de enfoque es más probable que introduzca nuevos errores que que corrija los existentes.

Al corregir los errores, es posible que observes otros problemas. En ese caso, también retrocede al paso 6 y aplícalos a esos errores nuevos observados.

Paso 9: asegúrate de que las pruebas ahora funcionan

Todas las nuevas pruebas ahora deberían ir bien. Si algo no funciona entonces vuelve atrás en el proceso y busca de nuevo otra solución al error.

Paso 10: verifica el caso de prueba simple

A esta altura del proceso, debería ser posible ejecutar los casos de prueba simples que desarrollaste en el paso 3 arriba, y todo debería ir como la seda. Si algo no funciona entonces vuelve atrás en el proceso y busca de nuevo otra solución al error.

Paso 11: comprueba el error original

Ahora ya deberías ser capaz de realizar las acciones que originalmente dieron paso al error, y ya debería funcionar sin problemas. Si identificas un problema nuevo o persiste el mismo, vuelve atrás a un paso anterior y encauza el problema.

Paso 12: documenta la solución al error

¿Cómo has arreglado el bug? Apúntalo.

Acabas de realizar un conjunto de maniobras de programación de muy alta calidad. ¡Así se forjan las leyendas! Es posible que seas la única persona consciente de tus acciones heroicas. Anótalas para que otros puedan aprender de ti: documenta el código, documenta el plan de prueba, documenta el conjunto de pruebas, escribe en el foro de la herramienta o haz una entrada en un blog para que conste para la eternidad y para que esté disponible para otros. Tu documentación también educará y asesorará a otros. Darás un buen ejemplo de cómo usar los recursos de manera efectiva y eficiente, y también de cómo ejecutar tareas de programación desafiantes.

Paso 13: anota otras posibles clases de errores

Durante el tiempo que has estado enfocando tu atención en resolver este problema en particular, puedes haber notado otras clases potenciales de errores, y posiblemente otras clases manifiestas de errores. Redacta un informe de errores para problemas que se manifiestan en un comportamiento disfuncional de la aplicación, o sí estás seguro de que están al acecho sin ser detectados aún.

Para otras posibles clases de errores que pueden no estar presentes pero que tampoco se pueden probar actualmente, toma las medidas necesarias para dirigir el esfuerzo de prueba hacia ellos. Por ejemplo, puedes hacer  un documento de ideas para un posible plan de prueba.

Paso 14: libera la solución del bug

Libera tu solución, ya sea interna o externamente, y asegúrate de que todos sepan lo que hiciste. Resume el problema y la solución de manera resumida e incluye enlaces a la documentación que hayas creado.

depuración de errores en software

Proceso de depuración de errores en software por Duncan Riach

Nota: este post es una adaptación de este artículo.

Este artículo 14 pasos para depurar tu software es original de Velneo.