2 puntos por GN⁺ 2025-01-14 | 1 comentarios | Compartir por WhatsApp
  • Debugging de David J. Agans trata los fundamentos de la depuración: cómo encontrar la causa de un bug y corregirlo después de detectarlo; ofrece principios a los que vale la pena volver una y otra vez tanto para desarrolladores principiantes e intermedios como para los más experimentados
  • El libro está organizado en 9 reglas que conectan con casos prácticos temas como entender el sistema, reproducir la falla, observar, dividir y vencer, controlar los cambios, mantener una pista de auditoría, revisar supuestos, obtener una mirada externa y verificar la corrección
  • Aunque aparecen tecnologías antiguas o ejemplos fuera del mundo de las computadoras, la idea central no es una herramienta específica sino una forma de pensar para acotar el problema, aplicable tanto a la depuración de hardware como de software
  • Para bugs difíciles de manejar, como los problemas intermitentes, el consejo de Make it Fail resulta especialmente útil, aunque queda la deuda de no tratar directamente el término Heisenbug
  • A diferencia de libros que explican cómo usar GDB o cómo escribir pruebas, este se enfoca en la visión general de la depuración, por lo que el uso de herramientas y las pruebas de regresión deben complementarse con otros materiales

El problema al que apunta el libro

  • Debugging: The 9 Indispensable Rules for Finding Even the Most Elusive Software and Hardware Problems de David J. Agans trata el proceso de encontrar la causa de un bug y corregirlo de verdad una vez que fue detectado
  • Más que centrarse en una tecnología o herramienta concreta, organiza los principios de depuración que necesitan los desarrolladores de software y hardware de computadoras
  • Es especialmente adecuado para desarrolladores principiantes e intermedios, y también sirve a los más experimentados para recuperar fundamentos que pueden pasarse por alto en situaciones urgentes
  • Uno de sus puntos fuertes es condensar en principios y casos prácticos lo que normalmente se aprende sobre depuración a fuerza de experiencia

Las 9 reglas de depuración

  • Entiende el sistema

    • Lee el manual, comprende la estructura general y entiende tanto los principios básicos como el funcionamiento detallado
    • Verifica también qué muestra la herramienta que usas y qué cosas oculta
  • Haz que falle

    • Ejecuta el problema otra vez y empieza desde el principio para provocar directamente las condiciones de falla
    • En lugar de imitar la falla, provoca la falla real y busca las condiciones no controladas que generan bugs intermitentes
    • Registra todo, no confíes demasiado en las estadísticas y acepta que las cosas raras realmente pueden pasar
    • No descartes las herramientas de depuración: úsalas para hacer visible el problema
  • Deja de pensar y mira

    • Antes de empezar una reparación compleja basada en suposiciones, consigue primero datos observables
    • Examina la falla y sus detalles, crea instrumentación interna o agrega instrumentación externa
    • No evites profundizar, pero ten cuidado con el efecto Heisenberg: la observación misma puede cambiar el comportamiento
    • Usa las conjeturas no como conclusión, sino solo como herramienta para reducir el área de búsqueda
  • Divide y vencerás

    • Reduce el rango de búsqueda mediante aproximaciones sucesivas (successive approximation) y determina de qué lado está el bug
    • Usa patrones de prueba fáciles de distinguir y parte de un estado malo para ir acotando la causa
    • Elimina primero los bugs ya conocidos y el ruido para simplificar aquello que vas a investigar
  • Cambia solo una cosa a la vez

    • Aísla los factores clave y entiende qué está mal antes de corregirlo
    • Cambia también las pruebas de una en una y compáralas con casos normales
    • Revisa qué cambió desde la última vez que funcionó correctamente
  • Mantén una pista de auditoría

    • Deja una pista de auditoría de qué hiciste, en qué orden y cuáles fueron los resultados
    • Incluso los detalles que parecen triviales pueden ser la causa, así que registra los eventos conectándolos entre sí
    • La pista de auditoría del proceso de diseño también ayuda en las pruebas y debe quedar por escrito
  • Revisa el enchufe

    • Pon en duda los supuestos que dabas por obvios y vuelve a comprobar todo desde el inicio
    • Incluye entre los objetos de prueba a la propia herramienta que usas para buscar el problema
  • Consigue una nueva perspectiva

    • Si te atoras trabajando solo, busca una nueva idea mediante otra persona o una forma distinta de explicar el problema
    • Incluso explicárselo a un maniquí puede ayudarte a ordenar el pensamiento
    • Aprovecha la experiencia de especialistas y de quienes ya han pasado por eso; prioriza compartir síntomas y pedir ayuda antes que el orgullo
  • Si no lo arreglaste, no está arreglado

    • Después del cambio, confirma que realmente quedó resuelto y verifica que tu modificación eliminó la causa real
    • Los problemas no desaparecen por sí solos, así que hay que corregir tanto la causa como el proceso

Cómo los casos prácticos hacen vivir los principios

  • La lista de reglas por sí sola puede parecer seca, pero las explicaciones detalladas y las anécdotas de casos llevan los principios a situaciones reales
  • Muchos ejemplos entran en detalles técnicos, lo que puede resultar pesado para algunos lectores
  • Hay casos que tratan tecnologías antiguas, pero eso no es un gran problema porque lo importante no es la tecnología específica sino el principio
  • No todos los ejemplos son de computación; también incluye un caso entretenido relacionado con el cableado de una casa
  • Si no sabes nada de hardware o software de computadoras, será difícil seguir muchos de los ejemplos
  • Después de explicar las reglas, siguen historias donde se aplican varias a la vez, ejercicios sencillos para el lector, consejos de help desk y comentarios de cierre

Puntos que más destacan y sus límites

  • La regla de “Deja de pensar y mira” es especialmente importante
    • Porque mucha gente intenta arreglar problemas a partir de suposiciones antes de reunir datos que permitan confirmar o refutar una hipótesis
  • Si no lo arreglaste, no está arreglado” es otra regla que deja una impresión fuerte
    • No basta con comprobar que algo cambió; también hay que confirmar cuál era la causa y por qué quedó corregida
  • La idea de “estimula la falla, no la imites” no está tan claramente explicada como otras partes del libro, pero sigue siendo un punto que vale la pena entender
  • Los problemas intermitentes suelen ser los más difíciles de manejar, y el libro ofrece en Make it Fail consejos directos para enfrentarlos
  • Menciona a Heisenberg, pero no trata el término habitual en desarrollo de software, Heisenbug
    • Heisenbug se refiere a un bug que desaparece o cambia de comportamiento cuando intentas observarlo o aislarlo

Diferencias frente a otros materiales

  • Este libro se distingue de los manuales de herramientas o de los libros de pruebas porque pone en el centro los principios básicos de la depuración
  • Debugging with GDB: The GNU Source-Level Debugger de Richard Stallman y otros explica principalmente tecnologías o comandos de herramientas específicas
  • También existen materiales con consejos generales, como Guide to Faster, Less Frustrating Debugging de Norman Matloff, pero no abarcan tanto como el libro de Agans
  • Libros de pruebas como Software Testing Techniques de Boris Beizer se enfocan en escribir pruebas para encontrar bugs, y tratan relativamente menos cómo corregir un bug una vez detectado
  • Después de encontrar un bug, hay que agregar una prueba para ese caso al conjunto de pruebas de regresión, pero las pruebas y la regresión quedan fuera del alcance de este libro

Materiales complementarios y puntos mejorables

  • El sitio web complementario del libro, debuggingrules.com, incluye enlaces a información relacionada y un póster descargable e imprimible con las 9 reglas
  • Se echa de menos que la lista completa de subreglas, importante para entender bien las reglas, no esté reunida en una sola página ni en el libro ni en el sitio web
  • Habría sido más útil si incluyera consejos y ejemplos más concretos sobre herramientas comunes y tipos de problemas, como depuradores simbólicos, sondas de lógica digital o ddd on gdb
  • También parecería útil otro libro aparte que extendiera estas mismas reglas a la resolución de problemas generales fuera de la computación, aunque los ejemplos de este libro son demasiado técnicos para lectores no informáticos
  • Los principios básicos pueden parecer obvios a simple vista, pero los principiantes tienen que aprenderlos y los experimentados deben recordarlos una y otra vez; este libro es adecuado para ambas cosas

1 comentarios

 
GN⁺ 2025-01-14
Opiniones de Hacker News
  • Creo que la tentación más dañina es intentar hacer que el código roto que ya tienes funcione agregándole “arreglos”
    El código roto es difícil de corregir porque hay demasiados puntos posibles de cambio, y es mucho más fácil romper código que sí funciona
    El método de probar cambiando un foco a la vez cuando una serie de luces navideñas entera no enciende falla si hay varios focos descompuestos
    En cambio, hay que empezar con un ejemplo mínimo funcional e ir agregando poco a poco hasta encontrar el punto donde aparece el error; en la práctica, muchas veces empezar de nuevo desde cero ahorra tiempo

    • Si aprender del problema no es la prioridad, quizá lo más rápido sea cambiar toda la serie de focos en vez de revisar cada foco uno por uno
      En un problema difícil de atrapar en producción, algunos miembros del equipo reescribieron la rutina problemática, y esa versión reescrita se desplegó antes de que los demás terminaran de depurar
      Al menos una vez, nunca se llegó a encontrar el bug original porque no se podía dedicar tiempo indefinidamente a un problema ya “arreglado”
  • La regla número 0 es no entrar en pánico
    Las fechas límite y los clientes enojados dificultan pensar con claridad, así que un buen gerente confiable debe proteger a los ingenieros de esa presión para que puedan concentrarse en resolver el problema

    • Muy de acuerdo. Cuando estás de guardia por un SEV-2 y entran de golpe los gerentes de los equipos afectados, cada uno interrumpiendo, se vuelve muy frustrante
      Un buen manager nos movió a otra llamada y dijo: “ignoren lo que digan esas personas y concéntrense; yo me encargo”, y desde entonces mi respeto por ese manager subió muchísimo
    • Según una historia del libro, en un submarino nuclear hay una barra de latón frente al panel de instrumentos y las manijas, y a los ingenieros se les entrena para que, cuando surge un problema, no toquen de inmediato las manijas sino que “agarren la barra”
    • Lo lento es fluido, y lo fluido es rápido
      Si no tienes tiempo para hacerlo bien, ¿por qué crees que sí tendrás tiempo para hacerlo dos veces?
    • Un jefe anterior describía su papel como “paraguas de mierda”
      Quería decir que su trabajo era bloquear lo que cayera desde arriba para que los ingenieros pudieran concentrarse en su trabajo real
    • Un principio que se deriva de esto es tener siempre un buen plan de rollback
      Es mucho mejor poder volver a una versión que funciona y luego depurar sin una presión de nivel crisis
  • Para el punto 4, “divide y vencerás”, git bisect ayuda muchísimo
    Si tienes un commit bueno y, entre decenas o cientos de commits posteriores, hay uno malo, en pocos pasos puedes acotar el commit o el código problemático
    Hay un ejemplo de uso en https://nickjanetakis.com/blog/using-git-bisect-to-help-find...
    Lo usé durante una consultoría en vivo para acotar rápidamente un codebase grande que no conocía; de lo contrario, el rango de cosas que podían estar rotas habría sido demasiado amplio

    • Por git bisect, mantengo la disciplina de que cada commit que entra a una rama “real” debe compilar de forma individual, pasar las pruebas conocidas en ese momento y, hasta donde sabemos, ser desplegable
      Le doy más importancia a eso que a principios como conservar cada pulsación de tecla o dejar el último commit de “Fixes.”, porque esos principios vuelven inútil la búsqueda binaria
      No lo uso con frecuencia, pero cuando acierta una sola vez en uno de los bugs más grandes y misteriosos, te da de golpe pistas que valen días de trabajo, así que vale totalmente la pena
    • Al depurar un problema de configuración de red en los años 90, un colega con más experiencia me explicó el principio general detrás de git bisect
      Consiste en comparar un sistema roto con uno que funciona y eliminar sistemáticamente las diferencias para encontrar la falla
      Se puede aplicar más allá de software o hardware; antes, cuando tenía dos motos acuáticas iguales, era útil arreglar una comparándola con la otra
    • La clave aquí no es tanto git bisect en sí, sino el principio más general de la búsqueda binaria
      Se puede usar no solo sobre un rango de commits, sino también para dividir el espacio de un sistema
      Por ejemplo, si un flujo de trabajo de 10 pasos se rompe, puedes comprobar si hasta el paso 5 funciona, o acotar si es o no un problema de hardware
      Esto es especialmente importante cuando la causa del problema quizá no sea un commit de código en el repositorio que estás bisectando en ese momento
    • bisect es excelente, pero hay que distinguir entre las “reglas”, que son la filosofía y forma de pensar de este libro, y las “herramientas”, que son consejos prácticos
      Quien empieza preguntando “¿qué herramienta uso?” está en desventaja frente a quien empieza con “¿esto no funcionaba antes?”
      El mundo está lleno de herramientas, y si intentas guardarlas todas en la cabeza te vas a volver loco; es mejor adoptar primero la filosofía
    • Agrego un artículo que escribí sobre git bisect run. Es una pequeña herramienta realmente sorprendente
      https://andrewrepp.com/git_bisect_run
  • Hay que asegurarse de estar modificando el archivo correcto en la máquina correcta

    • Es una variante de “revisa el enchufe”
      Hoy en día siempre agrego temporalmente una línea que provoque un error fatal, para confirmar que el archivo es el correcto y, según el caso, que la línea también lo sea
    • Solo Dios sabe cuánto tiempo he perdido modificando archivos generados, archivos de otra versión o simplemente por olvidar guardar
    • La regla más importante que siempre me he repetido y enseñado a otros es verificar que el código en ejecución sea realmente el código que creo que es
    • Por eso, primero hay que hacer que falle de otra manera
      Es para confirmar que mi cambio realmente tiene efecto
  • Hay reglas adicionales
    “Todo es culpa mía”: podría ser un bug del compilador o una falla de hardware, pero es muy raro, así que antes que nada hay que sospechar de mis cambios de código
    “Cuando encuentres un bug, busca también a su familia y amigos”: hay que pensar y comprobar en qué otros lugares pudo haber pasado algo del mismo tipo
    “Optimiza primero para el usuario, segundo para el programador de mantenimiento y al final para la computadora”

    • La primera regla se conoce en The Pragmatic Programmer como “select no está roto
      Hay un resumen en https://blog.codinghorror.com/the-first-rule-of-programming-...
    • A veces también es útil el enfoque de “como podría ser un bug, hagamos un caso de prueba que pueda reportarse a la lista de correo”
      Por lo general, en el proceso de reducir el código que produce el error a un caso más simple, terminas encontrando el bug en tu propia lógica
      Una o dos veces sí quedó un resultado que valía la pena reportarle al desarrollador, y por lo general se trataba de librerías con pocos tests porque tenían, como mucho, unos cientos de usuarios
    • Siempre había tenido la mentalidad de que “es culpa mía”, pero fue sinceramente humillante que mi workstation Linux siguiera crasheando por culpa del i9-13900K
      Al final fue un gran alivio saber que no era un error de código aparentemente imposible, sino un problema de CPU
    • Es más sano asumir que tu código está mal
      Aun así, lo mejor es asegurarse haciendo unas cuantas búsquedas binarias más en la cadena de causa y efecto
    • En relación con “familia y amigos”, varias veces me pasó que, al arreglar problemas periféricos menores y aparentemente no relacionados, terminó apareciendo el bug que estaba buscando
  • El consejo de “entiende el sistema: lee el manual, lee todo en profundidad, conoce los fundamentos, conoce el roadmap, entiende las herramientas y busca los detalles” suena un poco raro
    Parece decir que, si hay un bug en el código, primero deberías leer entero el manual de 700 páginas de la librería que estás usando, leer 7 libros relacionados y recién uno o dos meses después mirar el bug
    Me pregunto si hay siquiera un programador que siga realmente este consejo

    • Este texto fue escrito en 2004, el año de la IPO de Google
      Atwood y Spolsky crearon Stack Overflow en 2008, y era una época en la que la gente conocía libros por nombres como “Camel book” y simplemente tenía ese conocimiento
      0. https://stackoverflow.blog/2021/12/14/podcast-400-an-oral-hi...
      1. https://www.perl.com/article/extracting-the-list-of-o-reilly...
    • Aquí la interpretación parece ser un poco distinta
      “Lee todo en profundidad” no necesariamente significa “primero lee completo el manual de 700 páginas de la librería que usas”
      Si tienes un problema con git bisect, en vez de pegar varios fragmentos de Stack Overflow, puedes entender un poco más a fondo el tema en https://git-scm.com/docs/git-bisect
    • En esencia, es correcto
      Pero el error es pensar que el resultado de meses de trabajo es arreglar a medias un solo bug
      El objetivo es corregir de verdad tantos bugs de ese tipo como sea posible y evitar que se escriban desde el principio
      La alternativa es caer en paracaídas en un sistema que no conoces, tocar cosas sin entenderlas hasta que los tests estén en verde, abrir un PR y esperar no haber roto más; hacer eso como rutina es casi una pesadilla
      Además, si el manual de la librería que usas tiene 700 páginas, probablemente estés usando la librería equivocada
  • Como paso 10, ¿no habría que agregar el bug a los tests de CI para evitar regresiones?
    Hay que verificar que antes del arreglo el CI falle y que después del arreglo pase

    • El repositorio de JavaScript puro más grande en el que trabajé, un proyecto de unas 150 mil líneas, tenía esta regla y fue literalmente un salvavidas
      Especialmente porque había commits de más de 5 años y, al ser un componente/librería, tenía bastantes hacks raros para IE
    • No siempre creo que valga la pena
      Algunos tests tardan mucho en escribirse o son complejos y también requieren mantenimiento; además, hay que aceptar que el conjunto de tests no cubre todos los casos límite
      Puede significar que un bug que llegó a producción podría volver a aparecer, pero si fue un error simple, tal vez no tenga más probabilidad de repetirse que cientos de otros errores potenciales
      Al final depende del contexto, y escribir tests no es gratis
    • Más en general, hay que documentarlo
      Vi incontables veces cómo la causa profunda se reactivaba y el mismo problema reaparecía, o cómo nadie sabía que yo lo había arreglado y todos seguían usando workarounds como si el bug todavía existiera
      Incluso después de llegar a “¡arreglado!”, dejar una breve nota y un análisis de causa raíz ayuda a otras personas
    • ¿Qué hacer con los tests de corrección de bugs de hace varios años?
      Después de que los tests se acumulen durante mucho tiempo, ¿qué tan rápido puede correr el CI y sigue teniendo sentido conservarlos a largo plazo?
  • Si quieres inculcar esta forma de pensar en niños, en ti mismo o en otras personas, como mínimo recomiendo lo siguiente:
    The Martian by Andy Weir https://en.wikipedia.org/wiki/The_Martian_(Weir_novel)
    https://en.wikipedia.org/wiki/Zen_and_the_Art_of_Motorcycle_...
    https://en.wikipedia.org/wiki/The_Three-Body_Problem_(novel)
    To Engineer Is Human - The Role of Failure in Successful Design By Henry Petroski
    https://pressbooks.bccampus.ca/engineeringinsociety/front-ma...
    https://en.wikipedia.org/wiki/Surely_You%27re_Joking,_Mr._Fe...!

    • Estoy de acuerdo. Creo que Zen and the Art of Motorcycle Maintenance es el que mejor captura el arte de resolver problemas.
      En particular, me gusta el concepto de “gumption traps”.
      Si caíste en la trampa de la rigidez de valores, de todos modos te vas a volver más lento, así que hay que bajar el ritmo deliberadamente, volver a mirar por donde ya pasaste y comprobar si las cosas que creías importantes realmente lo eran.
      Tampoco está mal quedarse mirando la máquina por un rato; la frase de que, si la observas como si miraras una línea de pesca, llega un momento en que un pequeño hecho te pregunta con cautela si te interesa, es casi una guía de vida.
    • No sé qué parte de Three Body Problem tiene que ver con depuración, resolución de problemas o planificación.
      Los acontecimientos simplemente ocurren con saltos lógicos bruscos, y en realidad me parece más una fantasía recubierta por juegos de palabras científicos muy superficiales.
  • Hace unos años escribí algo parecido. En ese momento no había leído el libro original mencionado aquí.
    https://explog.in/notes/debugging.html
    El zine de depuración de Julia Evans también es muy bueno: https://wizardzines.com/zines/debugging-guide/

  • Incluso después de depurar con éxito, el trabajo no termina.
    La idea central de “Three Questions About Each Bug You Find” <http://www.multicians.org/thvv/threeq.html> son tres preguntas:
    ¿Este error existe también en otros lugares? ¿Cuál es el siguiente bug que se esconde detrás de este? ¿Qué hay que hacer para prevenir bugs como este?