debugging - ¿Cómo arreglas un error que no puedes replicar?
replicate (15)
A veces solo tengo que sentarme y estudiar el código hasta que encuentre el error. Intenta demostrar que el error es imposible y, en el proceso, podrás descubrir dónde te puedes equivocar. Si logras convencerte de que es imposible, da por hecho que te equivocaste en algún lado.
Puede ser útil agregar un montón de comprobaciones de errores y afirmaciones para confirmar o negar sus creencias / suposiciones. Algo puede fallar que nunca esperarías.
La pregunta lo dice todo. Si tiene un error que informan varios usuarios, pero no hay ningún registro de la ocurrencia del error en el registro, ni se puede repetir el error, no importa cuánto lo intente, ¿cómo lo soluciona? O incluso puedes?
Estoy seguro de que esto les ha sucedido a muchos de ustedes allá afuera. ¿Qué hiciste en esta situación y cuál fue el resultado final?
Editar: estoy más interesado en lo que se hizo sobre un error no modificable , no en un error no resuelto. Los errores no resueltos son tales que al menos sabe que hay un problema y tiene un punto de partida, en la mayoría de los casos, para buscarlo. En el caso de un no codificable, ¿qué haces? ¿Puedes siquiera hacer algo?
Comience mirando las herramientas que tiene disponibles para usted. Por ejemplo, bloqueos en una plataforma Windows, vaya a WinQual, de modo que si este es su caso, ahora tiene información de volcado de bloqueo. ¿Puede herramientas de análisis estáticas que detectan posibles errores, herramientas de análisis de tiempo de ejecución, herramientas de creación de perfiles?
Luego mira la entrada y la salida. ¿Hay algo similar sobre las entradas en situaciones en las que los usuarios informan el error o algo fuera de lugar en la salida? Compile una lista de informes y busque patrones.
Finalmente, como dijo David, mira el código.
Discuta el problema, lea el código, a menudo bastante. A menudo lo hacemos por parejas, porque generalmente puede eliminar las posibilidades analíticamente con bastante rapidez.
Estos son conocidos como Heisenbugs .
Idioma
Los diferentes lenguajes de programación tendrán su propio sabor de errores.
do
Agregar instrucciones de depuración puede hacer que el problema sea imposible de duplicar porque la declaración de depuración cambia los punteros (lo suficientemente lejos como para evitar un SEGFAULT). Los problemas del puntero son una pesadilla para rastrear y replicar, pero hay depuradores (como GDB y DDD ) que pueden ayudar.
Java
Una aplicación que tiene varios subprocesos solo puede mostrar sus errores con un tiempo muy específico o una secuencia de eventos. Las implementaciones de simultaneidad inadecuadas pueden causar interbloqueos en situaciones que son difíciles de replicar.
JavaScript
Algunos navegadores web son notorios por las pérdidas de memoria. El código JavaScript que funciona bien en un navegador puede causar un comportamiento incorrecto en otro navegador. Usar bibliotecas de terceros que miles de usuarios han probado rigurosamente puede ser una ventaja para evitar ciertos errores desconocidos.
Ambiente
Dependiendo de la complejidad del entorno en el que se ejecuta la aplicación (que tiene el error), el único recurso podría ser simplificar el entorno. Funciona la aplicación:
- en un servidor?
- en un escritorio?
- en un navegador web?
¿En qué entorno produce la aplicación el problema?
- ¿desarrollo?
- ¿prueba?
- ¿producción?
Salga de las aplicaciones externas, elimine las tareas en segundo plano, detenga todos los eventos programados (trabajos cron), elimine los complementos y desinstale los complementos del navegador.
Redes
Como la creación de redes es esencial para tantas aplicaciones:
- Asegure las conexiones de red estables, incluidas las señales inalámbricas.
- ¿El software se vuelve a conectar después de las fallas de la red de manera robusta?
- ¿Se cierran todas las conexiones correctamente para liberar los descriptores de archivos?
- ¿La gente está usando la máquina que no debería ser?
- ¿Los dispositivos fraudulentos interactúan con la red de la máquina?
- ¿Hay fábricas o torres de radio cerca que puedan causar interferencia?
- ¿Los tamaños y la frecuencia de los paquetes caen dentro de los rangos nominales?
- ¿Son todos los dispositivos de red adecuados para el uso de ancho de banda?
Consistencia
Eliminar tantas incógnitas como sea posible:
- Aislar componentes arquitectónicos.
- Elimine los elementos no esenciales o posiblemente problemáticos (en conflicto).
- Desactivar diferentes módulos de aplicaciones.
Elimine todas las diferencias entre producción, prueba y desarrollo. Usa el mismo hardware Siga exactamente los mismos pasos para configurar las computadoras. La consistencia es clave.
Explotación florestal
Use cantidades liberales de registro para correlacionar el tiempo en que sucedieron los eventos. Examine los registros en busca de errores obvios, problemas de tiempo, etc.
Hardware
Si el software parece estar bien, considere las fallas de hardware:
- ¿Son sólidas las conexiones de red físicas?
- ¿Hay algún cable suelto?
- ¿Las patatas fritas están bien colocadas?
- ¿Todos los cables tienen conexiones limpias?
- ¿El ambiente de trabajo está limpio y libre de polvo?
- ¿Los dispositivos o cables ocultos han sido dañados por roedores o insects ?
- ¿Hay bloques defectuosos en las unidades?
- ¿Funcionan los ventiladores de la CPU?
- ¿Puede la placa base alimentar todos los componentes? (CPU, tarjeta de red, tarjeta de video, unidades, etc.)
- ¿Podría ser la interferencia electromagnética la culpable?
Y principalmente para incrustado:
- ¿Desbordamiento de suministro insuficiente?
- Contaminación de la placa?
- ¿Juntas de soldadura malas / reflujo malo?
- ¿La CPU no se reinicia cuando los voltajes de suministro están fuera de tolerancia?
- ¿Se reiniciaron mal porque los rieles de suministro están alimentados por retroceso desde los puertos de E / S y no se descargan completamente?
- ¿Hacer conexion?
- ¿Pines de entrada flotantes?
- ¿Márgenes de ruido insuficientes (a veces negativos) en niveles lógicos?
- ¿Márgenes de tiempo insuficientes (a veces negativos)?
- ¿ Bigotes de estaño ?
- ¿Daño por ESD?
- ¿Trastornos de ESD?
- Chip errata?
- Mal uso de la interfaz (por ejemplo, I2C fuera de placa o en presencia de señales de alta potencia)?
- ¿Condiciones de carrera?
- ¿Componentes falsificados?
Red vs. Local
¿Qué sucede cuando ejecuta la aplicación localmente (es decir, no a través de la red)? ¿Hay otros servidores experimentando los mismos problemas? ¿La base de datos es remota? ¿Puedes usar una base de datos local?
Firmware
Entre el hardware y el software está el firmware.
- ¿El BIOS de la computadora está actualizado?
- ¿Funciona la batería del BIOS?
- ¿Están sincronizados el reloj de la BIOS y el reloj del sistema?
Tiempo y Estadística
Los problemas de sincronización son difíciles de rastrear:
- ¿Cuándo ocurre el problema?
- ¿Con que frecuencia?
- ¿Qué otros sistemas están funcionando en ese momento?
- ¿Es la aplicación sensible al tiempo (por ejemplo, saltará días o saltará segundos causar problemas)?
Reúna datos numéricos difíciles sobre el problema. Un problema que, al principio, podría parecer aleatorio, podría tener un patrón.
Gestión del cambio
A veces los problemas aparecen después de una actualización del sistema.
- ¿Cuándo empezó el problema por primera vez?
- ¿Qué cambió en el entorno (hardware y software)?
- ¿Qué sucede después de retroceder a una versión anterior?
- ¿Qué diferencias existen entre la versión problemática y la buena versión?
Gestión de la biblioteca
Los diferentes sistemas operativos tienen diferentes formas de distribuir bibliotecas conflictivas:
- Windows tiene DLL Hell .
- Unix puede tener numerosos enlaces simbólicos rotos.
- Los archivos de la biblioteca Java pueden ser igualmente de pesadilla para resolver.
Realice una nueva instalación del sistema operativo e incluya solo el software de soporte requerido para su aplicación.
Java
Asegúrese de que cada biblioteca se use solo una vez. En ocasiones, los contenedores de aplicaciones tienen una versión diferente de una biblioteca que la aplicación en sí. Es posible que no se pueda replicar en el entorno de desarrollo.
Use una herramienta de administración de biblioteca como Maven o Ivy .
Depuración
Codifique un método de detección que active una notificación (por ejemplo, registro, correo electrónico, ventana emergente, pitido del buscapersonas) cuando ocurra el error. Use pruebas automatizadas para enviar datos a la aplicación. Usa datos aleatorios. Use datos que cubran casos de borde conocidos y posibles. Finalmente, el error debería reaparecer.
Dormir
Vale la pena reiterar lo que otros han mencionado: dormir en ello. Pase tiempo lejos del problema, termine otras tareas (como la documentación). Manténgase físicamente alejado de las computadoras y haga ejercicio.
Revisión de código
Recorra el código, línea por línea, y describa lo que cada línea le hace a usted, a un compañero de trabajo o a un pato de goma . Esto puede conducir a ideas sobre cómo reproducir el error.
Radiación cósmica
Los rayos cósmicos pueden voltear bits. Esto no es tan grande como un problema en el pasado debido a la comprobación de errores modernos de la memoria. El software para hardware que deja la protección de la Tierra está sujeto a problemas que simplemente no pueden ser replicados debido a la aleatoriedad de la radiación cósmica.
Herramientas
Infrecuente, pero sucede, especialmente para herramientas de nicho (por ejemplo, un compilador de microcontrolador C que sufre un desbordamiento de tabla de símbolos).
Hay dos tipos de errores que no puedes replicar. El tipo que descubriste, y el tipo que alguien más descubrió.
Si descubrió el error, debería poder replicarlo. Si no puede replicarlo, simplemente no ha considerado todos los factores contribuyentes que conducen al error. Esta es la razón por la cual cada vez que tienes un error, debes documentarlo. Guarde el registro, obtenga una captura de pantalla, etc. Si no lo hace, ¿cómo puede probar que el error realmente existe? Tal vez es solo un recuerdo falso?
Si alguien más descubrió un error y no puede replicarlo, obviamente pídales que lo repliquen. Si no pueden replicarlo, intente replicarlo. Si no puede replicarlo rápidamente, ignórelo.
Sé que suena mal, pero creo que está justificado. La cantidad de tiempo que le tomará replicar un error que alguien más descubrió es muy grande. Si el error es real, volverá a suceder de forma natural. Alguien, tal vez incluso tú, lo encontrará nuevamente. Si es difícil de replicar, entonces también es raro, y probablemente no cause demasiado daño si ocurre algunas veces más.
Puede ser mucho más productivo si pasa su tiempo realmente trabajando, solucionando otros errores y escribiendo código nuevo, de lo que intentará replicar un error misterioso que ni siquiera puede garantizar que realmente exista. Simplemente espere a que aparezca de nuevo de forma natural, entonces podrá pasar todo el tiempo arreglándolo, en lugar de perder el tiempo tratando de revelarlo.
Hay herramientas como gotomeeting.com, que puede usar para compartir pantalla con su usuario y observar el comportamiento. Podría haber muchos problemas potenciales, como la cantidad de software instalados en sus máquinas, algunas herramientas que entran en conflicto con su programa. Creo que gotometeo, no es la única solución, pero podría haber problemas de tiempo de espera, problema lento de Internet.
La mayoría de las veces, diría que los programas informáticos no informan que corrija los mensajes de error, por ejemplo, en el caso de que java y c # rastreen todas las excepciones ... no capturen todos sino mantengan un punto donde puedan capturar y registrar. Los errores de interfaz de usuario son difíciles de resolver a menos que use herramientas de escritorio remotas. Y la mayoría de las veces podría ser un error incluso en software de terceros.
Haz cambios aleatorios hasta que algo funcione :-)
Pídale al usuario que le dé acceso remoto a su computadora y vea todo usted mismo. Pídale al usuario que haga un pequeño video de cómo él reproduce este error y se lo envíe.
Claro que ambos no siempre son posibles, pero si lo son puede aclarar algunas cosas. La forma más común de encontrar errores sigue siendo la misma: separar las partes que pueden causar errores, tratar de comprender lo que está sucediendo, reducir el espacio de código que podría causar el error.
Pensar. Difícil. Escóndete, no admitas interposiciones.
Una vez tuve un error donde la evidencia era un volcado hexadecimal de una base de datos corrupta. Las cadenas de punteros fueron sistemáticamente jodidas. Todos los programas del usuario y nuestro software de base de datos funcionaron sin fallas en las pruebas. Lo miré durante una semana (era un cliente importante), y después de eliminar docenas de ideas posibles, me di cuenta de que los datos se distribuían en dos archivos físicos y la corrupción se producía cuando las cadenas cruzaban los límites del archivo. Me di cuenta de que si una operación de copia de seguridad / restauración falla en un punto crítico, los dos archivos podrían terminar "fuera de sincronización", restaurados a diferentes puntos de tiempo. Si luego ejecuta uno de los programas del cliente en los datos ya corrompidos, produciría exactamente las cadenas anudadas de punteros que estaba viendo. Luego demostré una secuencia de eventos que reprodujeron exactamente la corrupción.
Puede ser difícil, y algunas veces casi imposible. Pero mi experiencia es que tarde o temprano serás capaz de reproducir y arreglar el error, si pasas suficiente tiempo en él (si ese tiempo valió la pena, es otro asunto).
Sugerencias generales que podrían ayudar en esta situación.
- Agregue más registros, si es posible, para que tenga más datos la próxima vez que aparezca el error.
- Pregunte a los usuarios si pueden replicar el error. En caso afirmativo, puede hacer que lo repliquen mientras observa por encima de su hombro y, con suerte, descubrir qué desencadena el error.
Si no puede replicarlo, puede solucionarlo, pero no puede saber que lo ha solucionado.
Hice mi mejor explicación sobre cómo se desencadenó el error (incluso si no sabía cómo podría ocurrir esa situación), lo solucioné y me aseguré de que si el error volvía a surgir, nuestros mecanismos de notificación permitieran a un futuro desarrollador saber las cosas que desearía haber sabido En la práctica, esto significaba agregar eventos de registro cuando se cruzaban las rutas que podrían desencadenar el error, y se registraban las métricas para los recursos relacionados. Y, por supuesto, asegurándose de que las pruebas ejercitaran bien el código en general.
Decidir qué notificaciones agregar es una cuestión de factibilidad y triage. Entonces, es decidir cuánto tiempo de desarrollador gastar en el error en primer lugar. No se puede responder sin saber cuán importante es el error.
He tenido buenos resultados (no apareció de nuevo, y el código fue mejor) y malo (pasó demasiado tiempo sin resolver el problema, ya sea que el error haya sido resuelto o no). Para eso son las estimaciones y las prioridades de los problemas.
Si se trata de una aplicación GUI, es invaluable ver al cliente generar el error (o intentarlo). Sin duda estarán haciendo algo que nunca hubieras imaginado que estaban haciendo (no incorrectamente, solo de manera diferente).
De lo contrario, concentre su registro en esa área. Registre casi todo (puede sacarlo más tarde) y haga que su aplicación descargue su entorno también. por ejemplo, tipo de máquina, tipo de VM, codificación utilizada.
¿Su aplicación informa un número de versión, un número de compilación, etc.? Necesita esto para determinar con precisión qué versión está depurando (¡o no!).
Si puede instrumentar su aplicación (por ejemplo, usando JMX si está en el mundo Java), entonces instrumente el área en cuestión. Almacenar estadísticas, por ejemplo, solicitudes + parámetros, tiempo realizado, etc. Utilice los almacenamientos intermedios para almacenar las últimas ''n'' solicitudes / respuestas / versiones de objetos / lo que sea, y elimínelos cuando el usuario reporte un problema.
Si trabaja en una aplicación de tamaño real, probablemente tenga una cola de 1.000 errores, la mayoría de los cuales son definitivamente reproducibles.
Por lo tanto, me temo que probablemente cerraría el error como WORKSFORME (Bugzilla) y luego seguiría corrigiendo algunos errores más tangibles. O haciendo lo que el gerente de proyecto decida hacer.
Ciertamente, hacer cambios aleatorios es una mala idea, incluso si están localizados, porque te arriesgas a introducir nuevos errores.
Suponiendo que ya ha agregado todo el registro que cree que ayudaría y no lo hizo ... dos cosas le vienen a la mente:
Trabaja hacia atrás desde el síntoma informado. Piensa para ti mismo ... "Quería producir el síntoma que se informó, qué parte del código necesitaría para su ejecución, y cómo llegaría a él, y cómo llegaría a eso". D conduce a C conduce a B conduce a A. Acepte que si un error no es reproducible, los métodos normales no ayudarán. He tenido que mirar el código durante muchas horas con este tipo de procesos de pensamiento para encontrar algunos errores. Por lo general, resulta ser algo realmente estúpido.
Recuerda la primera ley de depuración de Bob: si no puedes encontrar algo, es porque estás buscando en el lugar equivocado :-)
modifique el código donde cree que está pasando el problema, para que la información de depuración adicional se grabe en algún lugar. cuando suceda la próxima vez, tendrá lo que necesita para resolver el problema.