There have never been more debuggers available, and it’s a good thing given how intricate most codebases are. Traditional “breakpoint” debuggers work great when you know what the bug is and roughly where the flawed code is located. But when you don’t know much about the bug or about the codebase, you have to get oriented before the debugger becomes a useful tool – and debuggers aren’t designed to help you get oriented.
How “breakpoint” debuggers fall short
“Get oriented” basically means “Read and interpret a lot of code.” And in a large codebase, it’s a real struggle to sift through all that code, and imagine possible causes and scenarios. It’s just too much to try to keep in your head. And breakpoints are a very tedious way to see the data flows, because (a) they only show you the variables and data in one location at a time (b) you can only step forward, not back.
The problem is compounded when the bug is caused by changes not related to code, like when it’s introduced by a change in an external API or database schema – because in these cases, inspecting the source diff may not point you in the right direction.
So, when I’m tackling a tough bug with no obvious cause, I want to see the variables and data at any code location, without having to restart the process. I want to jump around the code to track down my theories and then be able to quickly backtrack. When I’m working with microservices, I want to be able to identify any unintended side-effects related to web services. And I want to see exactly what HTTP client requests and SQL queries are being issued, without having to step through client libraries and object-relational mappers.
Interactive code maps to the rescue
AppMap provides me with a much more powerful way to dig through a lot of code at once and look for trouble. I don’t need to know where the bug is in order to get started, and I don’t have to try to keep possible causes and scenarios in my head. I can start from a high-level function (like an HTTP server request) or I can go bottom-up and start with a low-level function or SQL query. Either way, AppMap automatically generates interactive maps of all the factors that might be contributing to a bug and helps me figure out where things are going wrong.
Here are some other things AppMap has helped me with when debugging:
- An AppMap that reproduces the bug shows only the code I might need to care about, and none of the code that’s irrelevant to the issue. So right off the bat, I can ignore 90% or more of the code base.
- I can explore code execution in any order I like (forwards, backwards, up, down). I never have to restart the process with new breakpoints, or wait through a tedious startup procedure.
- I can see not just code, but data – parameter values, HTTP server and client requests, and complete SQL queries – to get more context around the flaw.
- I have multiple options to reproduce the bug – either with test cases, recording the app with remote recording, or writing a test program using the AppMap language hooks.
- An AppMap is just a JSON file. So when a developer, QA person, or security tester finds a problem, they can create an AppMap and attach it to the bug report. The amount of information and detail in an AppMap is invaluable to the developer who works on the bug, and there’s no confusion about what the bug actually is, or how to reproduce it.
How AppMap works
The first step in debugging with AppMap is to record a test case or example scenario that reproduces the bug. Once you have the AppMap you need, you can use the trace view to determine where the bug is happening in the codebase.
In many cases, I’ve been able to resolve bugs using just AppMap and no debugger. But when that’s not possible, AppMap kickstarts my debugging process by giving me a solid understanding of where to set my breakpoints.
Here’s a 7 minute demo of me debugging the Rails Sample App in VSCode with AppMap:
For an extended demo, where I show how to modify and create test cases, auto-generate Swagger and attach my AppMap to a PR, check this out.