Ser desarrollador significa que más de la mitad del tiempo tienes que ser un depurador, a veces para tu propio código, y otras veces para ayudar a tus compañeros en la revisión del código o en el caso de la programación en pareja. A pesar de ser una habilidad necesaria para los desarrolladores, la depuración no es algo que se le enseñe a nadie en ningún momento de su carrera, lo que lleva a creer que es muy difícil.
La depuración parece difícil, no por su mecánica, sino porque es difícil entender por dónde empezar como novato. Sin duda, es un arte que se puede adquirir creando y revisando más y más código con el tiempo, pero la intuición se puede desarrollar desde el principio con algunas recomendaciones que discutiremos hoy en este artículo.
Empecemos.
El peor escenario al depurar cualquier problema es cuando el error no se puede reproducir de manera confiable. Esto puede ocurrir debido a varios factores, como condiciones de carrera, sistemas externos o problemas ambientales que conducen a diferentes patrones de comportamiento en los sistemas implementados o en las cajas de etapa del desarrollador.
Esto se reduce tanto al probador como al desarrollador de que cuanto más específico pueda ser en la forma de reproducir el error, mejor. Además, una vez que haya encontrado el problema y una manera de demostrarlo, asegúrese de incluir todos los detalles sobre cómo reproducirlo, comprenderlo y resolverlo en un sistema de seguimiento de errores. Esto no solo lo ayudará a verificar la solución una vez implementada, sino que también ayudará a los otros desarrolladores a comprender la causa y la solución del error.
Aquí hay algunos consejos simples a seguir cuando se describen los pasos para reproducir un problema:
Este paso no siempre es posible; y a veces es posible pero no práctico o realmente necesario, sin embargo, puede haber casos en los que valga la pena implementarlo. La prueba automatizada, en este contexto, podría ser cualquier cosa que su caso de uso de desarrollo ya esté utilizando para la prueba, como una prueba unitaria o una prueba de integración. Siempre que sea posible, las pruebas unitarias son una excelente opción porque están diseñadas para realizarse con frecuencia, por lo que sabrá si el problema vuelve pronto.
Es posible que se encuentre escribiendo muchas pruebas unitarias que pasarían al tratar de identificar el origen del problema. Ocasionalmente, también puede encontrarse escribiendo pruebas unitarias que no tienen sentido fuera de la situación actual, pero aun así, no hay nada de malo en tener una prueba que pueda ayudarlo a señalar la fuente del problema. El hecho de que no sea el problema actual no significa que no encontrará uno más tarde, y también sirve como documentación adicional de cómo debería comportarse el código. Las pruebas de unidades de trabajo suelen ser un enfoque excelente para determinar qué capa dentro de un sistema está generando el problema.
Refactorice sus pruebas unitarias con el mismo vigor que lo haría con su código de producción. Si tiene una prueba unitaria enorme que en realidad está probando una parte significativa del código, intente dividirla en pruebas más pequeñas. Si tiene suerte, descubrirá que una gran prueba unitaria fallida basada en el problema original puede dividirse en varias pruebas aprobadas y una sola prueba menor fallida.
Incluso si encuentra un problema desde el principio y puede resolverlo en una sola línea, cree una prueba unitaria para validarlo siempre que sea posible. Cometer errores al corregir el código es tan simple como desarrollarlo en primer lugar, y los principios de prueba primero aún se aplican.
Tienes que ser un poco paranoico si estás depurando cualquier problema para seguir adelante tan claramente que algo en alguna parte no está funcionando como debería, de lo contrario no habrá ningún problema. Debe tener la mente abierta sobre dónde puede estar el problema y navegar con su conocimiento del sistema involucrado.
El objetivo principal aquí es evitar que nunca afirmes: "El problema no puede estar ahí". Demuéstralo si no lo crees. Si parece serlo, independientemente de lo imposible que parezca, profundice más.
Si el propósito de cualquier pieza de código no está claro para usted, independientemente de si puede o no ser la causa del problema, tómese un tiempo para entenderlo. Siempre puede poner algunas pruebas a su alrededor e intentar documentar lo que hace. Si no está seguro de si el comportamiento es correcto o no, pida ayuda. Una vez que lo tengas claro, intenta documentar todo lo que sabes, ya sea con un test, documentación XML o algún documento externo.
Si una pieza de código es excepcionalmente mala, puede terminar descubriendo otros problemas mientras depura el original. En tal caso, es fundamental decidir qué problema debe abordarse primero y luego centrarse únicamente en ese problema.
En un mundo perfecto, resolvería un problema, verificaría su código en el control de versiones, luego arreglaría el siguiente, y así sucesivamente. Esto hace que sea sencillo determinar qué cambios en el código llevaron a qué cambios en el comportamiento más adelante, lo cual es fundamental cuando la solución de un problema resulta que falla en otra cosa.
Los registros pueden ser increíblemente útiles en la depuración. Pueden brindarle información desde el principio donde los depuradores pueden no ser útiles. Sin embargo, el registro, al igual que la depuración, también es un arte cuidadoso. Si no lo hace correctamente, es posible que no pueda ayudarlo de la mejor manera posible. Por lo tanto, cada vez que se lanza una excepción en el código, asegúrese de no solo registrar el mensaje de la excepción, sino también el seguimiento de la pila.
Esencialmente, las excepciones nunca deben tragarse en silencio sin registrarse. A veces pueden ser la forma más fácil de verificar la entrada del usuario o los ajustes de configuración. En estas situaciones, el registro puede ser verdaderamente su amigo.
Del mismo modo, haga que su código sea resistente a las malas entradas. Cuanto antes se detecte una mala entrada, más fácil será encontrar el problema. Puede ser difícil rastrear la raíz de un problema si solo obtiene una expectativa después de que varios métodos hayan manejado un valor. Los contratos podrían ser útiles para definir las restricciones aquí; de lo contrario, debe estar atento y agregar validaciones si sospecha que hay un problema en el futuro.
Al igual que un Jedi no puede ser excelente sin su sable de luz, no puede ser un gran desarrollador sin conocer las capacidades de su depurador. Los depuradores modernos tienen muchas características que en su mayoría están infrautilizadas porque los desarrolladores las desconocen. Por ejemplo, los puntos de interrupción condicionales o la representación de estructuras de datos definida por el usuario pueden marcar la diferencia entre una sesión de depuración que dura todo un día o una que solo dura 10 minutos.
No necesita saberlo todo de memoria, pero es importante tener una idea decente de lo que su depurador es capaz de hacer y un buen conocimiento de las teclas de método abreviado involucradas para las funcionalidades básicas como pasar por encima, entrar, establecer un punto de interrupción y reanudar la ejecución. .
La depuración es difícil, ya que puede desmoralizarse, y trabajar con un laberinto de código mal documentado puede conducir rápidamente al agotamiento físico. Considere esto: si está atascado, tómese un descanso, salga a caminar, tome un café, una barra de chocolate, lo que sea que lo ayude.
No se avergüence si necesita incluir a alguien más: si el comportamiento del código parece inverosímil o si simplemente no sabe dónde buscar, pregunte. Esté atento a lo que hace la otra persona, tanto para aprender de ella como para advertirle si parece que se dirige a un callejón sin salida que ha observado anteriormente. Hágales saber lo que observó y lo que piensa, una discusión podría dar una pista.
Cuando crea que ha resuelto el problema, haga todo lo que pueda para probarlo (dentro de lo razonable). Obviamente, las pruebas unitarias deberían ser su primer puerto de escala: las pruebas unitarias que introdujo para aislar el problema ahora deberían pasar, pero también deberían pasar todas las demás pruebas.
Un problema de alto nivel suele ser causado por numerosos problemas de bajo nivel: es fácil descubrir el primero de bajo nivel, corregirlo y luego suponer que el problema de alto nivel desaparecerá. A veces ocurre lo contrario: el comportamiento de alto nivel se deteriora como resultado de un problema de bajo nivel más significativo. En ese caso, deberá seguir arreglando y luego probando hasta que vea que todo funciona correctamente.
Los problemas ocurren con frecuencia en grupos. Por ejemplo, si descubre que alguien olvidó escapar/codificar lo suficiente en la entrada del usuario en una instancia, el mismo problema puede surgir en otra. Es significativamente menos costoso ejecutar una auditoría rápida de posibles problemas de una sola vez que dejar que cada problema se plantee como un problema distinto, tal vez involucrando a otros ingenieros que realizan las mismas investigaciones que usted acaba de completar.
Considere las consecuencias de su parche en una línea similar. ¿Causará un problema en otro lugar que no se pueda solucionar a corto plazo? ¿Tendrá un impacto en parches o actualizaciones? ¿Es una reparación importante en esta etapa del ciclo de vida de su producto? Por lo general, siempre vale la pena descubrir qué está mal, pero ocasionalmente es más seguro dejar el código roto, posiblemente con una reparación de "curita" que aborde los síntomas pero no la causa, y dejar la cura completa para la próxima versión. Esto no significa que deba dejar el informe de error como está.
Si tiene una sugerencia para una reparación, intente crear un archivo de parche y agréguelo al informe de errores (dejando en claro qué versiones de qué archivos necesitan parches, por supuesto). Como mínimo, proporcione una explicación detallada de su investigación en el informe de errores para evitar perder el tiempo más adelante. Un estado de error de "Resolver la próxima versión" (o cualquiera que sea su equivalente) debería indicar solo eso, no "Es poco probable que alguna vez solucionemos esto, pero lo retrasaremos una versión a la vez".
Estas recomendaciones no pueden convertirlo en un depurador profesional en uno o dos días, pero seguramente lo ayudarán a comenzar en la dirección correcta si las sigue con paciencia y buenas prácticas. El código de alta calidad no sucede por accidente, requiere paciencia y precisión.
Eso fue todo por este artículo. Déjame saber lo que piensas sobre los consejos anteriores para la depuración y siéntete libre de agregar tu enfoque, consejos y trucos para convertirte en un depurador profesional en los comentarios a continuación.
¡Sigue leyendo!