Cómo depurar un programa al que no tiene acceso



Foto: Intricate Explorer, Unsplash



Hoy recordé uno de mis "mitos de programación" favoritos, que muy bien puede ser una leyenda urbana, y mi propia versión de la "caja negra" que requería depuración.



La leyenda urbana cuenta sobre los vagones radiactivos de Ucrania que causaron errores en el sistema informático, puedes leerlo aquí .



Nos ocupamos de las "cajas negras" y de lo que son hoy



Una caja negra es un concepto de programación popular que asume que estamos fuera de un sistema o componente sin acceso directo al código. Esto puede deberse a varios factores:



  • Trabaja con software de terceros cuyos desarrolladores simplemente no divulgan el código.
  • Estás interactuando con una API cuya lógica interna está abstraída.
  • No tiene los permisos necesarios para acceder al repositorio de Git.
  • Incluso un sistema con acceso completo puede convertirse en una caja negra de facto debido a su complejidad.
  • Un empleado que posea todas las claves y el conocimiento de repente renunciará / desaparecerá / morirá.
  • El sistema heredado consiste en un .dll que "siempre funcionó" en el servidor y no estaba conectado a un sistema de control de versiones. Para mirar el código, es necesario descompilarlo, si es posible, por supuesto.


Todos estos factores se reducen al hecho de que tenemos un problema que no podemos solucionar al instante y no sabemos cuál es el error. Por tanto, tenemos que ponernos manos a la obra.



Nuestro propio problema fue una combinación de todo lo anterior.



La lista de factores enumerados anteriormente probablemente no cubre todas las situaciones, porque es una lista directa de factores que influyeron en nuestra situación. Acabábamos de despedir a un desarrollador, un sistema complejo distribuido en varios servidores, con un .dll central que "hacía su trabajo", aunque nadie sabía por qué ni cuál.



Llamó a servicios de terceros, prácticamente no había registro en él, y las únicas copias de seguridad que teníamos eran los almacenamientos en el sistema de archivos con este .dll

y sin ningún código. Como puede comprender, nada de esto se pudo mantener, y planearon reescribir el sistema a su debido tiempo, pero el error era urgente y requería eliminación.



Podemos decir que la mayor parte del tiempo el sistema estaba haciendo frente al trabajo casi por completo, y podríamos aguantar soluciones parciales al problema si mostraban coherencia. Sin embargo, aproximadamente cada centésimo conjunto de datos resultó tener resultados incorrectos y lo único que pudimos hacer fue depurarlos desde el exterior (ahora recordamos esto con una sonrisa).



Este es uno de esos momentos en los que me sentí agradecido por el caótico mundo en el que crecí, porque la mayoría de las empresas no se enfrentarán a problemas tan graves y no nombrarán a un recién graduado para que los resuelva. Tuve suerte en ese sentido, y aún más, porque conté con el apoyo de desarrolladores experimentados que me ayudaron durante todo el proceso. Entonces esta fue nuestra solución.



Reproducimos el error (idealmente en varios casos de prueba)



Una vez que sepa cuál es el error real, el problema está casi resuelto, pero puede ser increíblemente difícil llegar a él si el error se produce de forma irregular. Piense de nuevo en el ejemplo del tren: si no fuera posible identificar el patrón, la razón sería casi imposible de encontrar. Porque esto es lo que estamos buscando en tal situación: el patrón de cuando ocurre un error.



En nuestro caso, lo encontramos relativamente simple: sabíamos el tipo de error y se producía repetidamente, pero tan raramente que nos llevó muchas veces reducir el espacio de búsqueda de casos y revelar su lógica.



Una vez que hayamos identificado una gran cantidad de casos de prueba que regularmente conducen a fallas, puede comenzar a depurar. A continuación, se muestra un ejemplo de otro proceso en el que reducimos la búsqueda de la fuente del problema haciendo coincidir patrones: uno de los sistemas se colgaba todos los jueves por la noche y no había nada extraño en los archivos de registro:



  • Sabíamos que nuestro sistema no estaba dando ningún mensaje de error, pero se colgó.
  • Comparamos los casos hasta que estuvimos seguros de que el problema ocurrió el jueves y ningún otro día.
  • Verificamos que no haya actualizaciones automáticas programadas para este momento, verificamos todas las tareas automatizadas que se ejecutan en el mismo servidor, nada.
  • Observamos lo que estaba haciendo el sistema en el metanivel y lo redujimos a un tiempo de espera de disco compartido, al que se accedía cada dos semanas mediante una tarea de limpieza de disco que se ejecutaba en un servidor completamente diferente mientras nuestro servicio estaba en ejecución. Nadie pensó que ambos empezaron a despegar a las tres de la mañana.


Cree un entorno de prueba (incluso si es producción)



Una vez que tenga un conjunto de errores, puede comenzar a trabajar en la verdadera causa y solución, lo que requiere un sistema de prueba.



Con eso, quiero decir que necesitas dos constantes:



  • Los datos utilizados no deben ser modificados por otros sistemas.
  • Los posibles daños deben limitarse tanto como sea posible


En nuestro caso, no pudimos reproducir los errores en el servidor de prueba, esto era obvio, ya que la biblioteca .dll estaba en un estado completamente diferente en comparación con el servidor en producción. Revertir a este antiguo estado no funcionó porque rompió otros elementos que eran igualmente importantes.



Así que nos reunimos e hicimos la pregunta: "¿Qué es lo peor que podría pasar si estropeamos esto?" Y luego escribimos un script de base de datos que reescribía todos los resultados en un estado de error para que los sistemas posteriores no los procesaran.



Era posible, por ejemplo, desconectar servidores y tareas, eliminar el siguiente paso lógico del proceso, etc., pero la posibilidad de esto depende de la arquitectura de un sistema en particular.



Compare los datos de entrada para encontrar similitudes y diferencias con conjuntos de datos de trabajo



Aunque no podemos averiguar qué hace exactamente el código en el caso de una "caja negra", fue posible llevar a cabo una especie de "ingeniería inversa", que a menudo da una buena comprensión de las causas de los problemas.



En nuestro caso, tuvimos el lujo de archivos JSON razonablemente bien formateados del sistema anterior del que dependía nuestra entrada. Después de que tuvimos todo configurado, quedó literalmente comenzar a comparar un par de archivos de texto en Notepad ++ hasta que encontramos las similitudes entre los archivos que causan los errores, y luego las diferencias entre ellos y los archivos que funcionan correctamente.



Tuvimos suerte aquí: pudimos descubrir rápidamente que el error causó una combinación específica de indicadores de clientes e inmediatamente logramos evitarlos, porque este caso podría ser "imitado" con indicadores similares pero diferentes. Por lo tanto, como ya sabíamos que el sistema sería reescrito (de hecho, no teníamos otra opción), se decidió solucionar este error en lugar de descompilarlo y arreglarlo.



Modificar la entrada para asegurarnos de que nuestra suposición condujo a los resultados esperados (y limita cualquier daño)



Obviamente, es una mala idea cambiar datos en vivo en una base de datos en producción, esperando que todo funcione sin pruebas reales, pero no teníamos otra opción.



Funcionó muy bien porque el número de casos era bajo y las primeras pruebas que realizamos manualmente resultaron ser exactamente lo que queríamos.



Así que terminamos escribiendo otra tarea automatizada para solucionar estos problemas antes de que llegaran al sistema, y ​​luego nos embarcamos en un proyecto de tres meses para reescribir este programa desde cero, esta vez de forma transparente, con control de versiones y compilación de pipelines.



Aquí tienes una aventura.



Conclusión: puede aprender bastante sobre el sistema, incluso si simplemente camina alrededor y lo golpea con un palo



Estoy encantado con esta forma de depurar y encontrar errores, me encanta cuando la programación se combina con una descarga de adrenalina.



Si no ha visto el video sobre la inyección de SQL y la ingeniería inversa de la base de datos en los mensajes de error, le recomiendo que lo vea . Las técnicas utilizadas en este video son casi idénticas a las que se pueden utilizar para la depuración no maliciosa.






Publicidad



¡Ordene y trabaje inmediatamente! Creación de VDS de cualquier configuración en un minuto, incluidos servidores para almacenar grandes cantidades de datos hasta 4000 GB. Epic :)



Suscríbete a nuestro chat en Telegram .






All Articles