The Debugging Book • Andreas Zeller & Clare Sudbery
Professor Andreas Zeller discusses his interactive 'Debugging Book,' arguing that systematic, automated debugging is a critical but neglected skill. He explores powerful techniques like delta debugging and automated repair, explaining how developers can build their own tools to make debugging a more plannable and efficient process.
In software development, debugging is often treated as an afterthought in education, yet it consumes nearly half of all development time and represents a significant business risk. Professor Andreas Zeller aims to address this gap by teaching systematic and automated debugging techniques, moving the practice from a frustrating art to a structured science.
An Interactive, Executable Book Format
The “Debugging Book” departs from the traditional static format of text and images. It’s an interactive, executable experience built using Jupyter Notebooks. This format uniquely combines:
- Rich Text: Explanations, formulas, and concepts are presented as in a traditional book.
- Executable Code: The principles discussed are immediately implemented in Python code snippets.
- Interactivity: Readers can execute the code, modify parameters, and experiment with the debugging tools being built, directly within the book itself.
This approach creates a “playground” where developers can learn not just the theory but also the practical implementation of debugging tools, bridging the gap between a paper’s description and a usable artifact.
Why Python?
Python was chosen as the language for the book for several key reasons:
- Accessibility: It’s a popular, easy-to-learn language, making the content accessible even to those not primarily Python developers.
- Interpreted Nature: Python’s interpreted execution model avoids complex compilation steps, allowing readers to run code examples instantly. This is contrasted with the boilerplate required in languages like Java (e.g.,
public static void main...). - Introspection: Most importantly, Python’s powerful introspection capabilities allow programs to easily inspect themselves and other programs at runtime. This makes it possible to build a functional interactive debugger in just 30-50 lines of code, whereas achieving the same in a compiled language like C or Java would be a monumental effort requiring deep interaction with the compiler and runtime.
Key Automated Debugging Techniques
The book provides hands-on implementations of several powerful debugging techniques.
Beyond Basic Interactive Debugging
While most developers are familiar with basic debuggers, many underutilize their advanced features. The book highlights the power of watchpoints, which are more advanced than conditional breakpoints. A watchpoint can halt execution the moment a specific variable’s value changes, allowing the developer to jump directly to the line of code responsible for the state change, which is invaluable for tracking down the origin of bugs.
Tracking Data Flows and Dependencies
A core challenge in debugging is that programs execute forwards, but the investigation into a bug’s origin must go backward in time. To solve this, the book demonstrates how to build tools that automatically track the origin of every value assigned to a variable. At the end of a failed computation, the developer has a complete “map” of dependencies, allowing them to easily trace a bad value back through its origins to pinpoint the exact location where the logic went wrong.
Delta Debugging
Delta Debugging is a powerful technique for automatically minimizing a failing input. The process works as follows:
- Start with a long, complex input that reliably causes the program to fail.
- The algorithm systematically removes large chunks of the input (e.g., half, then quarters, then eighths) and re-runs the program.
- If the program still fails, the smaller input is kept.
- This process continues until the input is reduced to the absolute minimum required to trigger the bug—sometimes just a few characters.
This simplifies the bug report immensely, often revealing the nature of the bug just by looking at the minimal input (e.g., discovering a payment system fails whenever an emoji is present in a name).
Automated Software Repair
A cutting-edge topic covered is automated software repair. While still largely in the research phase, the concept is to have tools not just find but also fix bugs. The process relies on a comprehensive test suite and works by:
- Using fault localization techniques (like data flow tracking) to identify potential locations of the bug.
- Applying small, targeted changes to the code at these locations.
- Running the entire test suite to validate the change. A potential fix is one that makes a failing test pass without causing any previously passing tests to fail.
This technique underscores the critical importance of a robust test suite to prevent the tool from simply removing functionality (e.g., adding if (pointer == null) return;) to pass a test.
The Symbiotic Relationship with Testing
Effective debugging is inextricably linked to thorough testing. Automated techniques like statistical debugging and automated repair are entirely dependent on a good suite of automated tests. Zeller emphasizes that testing effort is plannable, whereas debugging is an unpredictable time sink and business risk. Practices like Test-Driven Development (TDD) are therefore crucial, as they naturally produce the comprehensive test coverage needed to enable these advanced debugging strategies.
Debugging in the Age of AI
While Large Language Models (LLMs) can accelerate code generation, they also introduce new challenges. Zeller shares an anecdote of using an LLM to port Python code to C++, which compiled successfully but contained subtle bugs that took four hours to debug. He argues that current AI lacks the deep, execution-based understanding of a program’s state needed for effective debugging. The future of AI in this space will require moving beyond static code analysis to models that can execute, test, and debug the code they generate.