Debugging with Humility

December 18, 2016

Back when I was in university, I was working as a software engineering student at Intel. At any given point, there was a real software engineer that was my responsible adult. It so happened that I was lucky to work with several engineers and got to experience different approaches to programming.

One of these engineers did something I remember to this day. I often needed his help to solve one bug or another, and ask him to come over and take a look. “I’m getting a weird compilation error…” I would say. He would gladly come over and help. I would start to explain, “I was trying to add an import for the boost library when I —”.

“May I?”, He would cut me off and gesture toward the keyboard, asking if he could take over. I’d nod to agree and continue, “I tried adding the library to gcc so it could find the headers, but —”

“Give me a minute, okay?”, he would cut me off again.

After a few minutes, he would, without fail, find the bug. But even though he helped me, I couldn’t help but feel angry. Why didn’t he listen? Why didn’t he care to hear my attempts at fixing the bug?

Fast forward five years. I was working at a different place, leading a small team building a web application. One of the programmers in my team called me up to consult about a bug. She showed me her code and started to explain the behavior she encountered. It sounded pretty simple and I was pretty sure I could solve it if I could zoom around the code freely for a minute or two. “May I?”, I said. She started laughing and said “When you say that, I know you mean business.”

I think the most interesting transition is between the third and fourth stages. The first three stages are a mixture of denial and self delusion. This transition is the understanding that one of your assumptions is wrong. It is the acceptance that in the battle between reality and our thoughts, reality wins.

Why did I ignore my teammate? Why did I perpetuate the behavior that made me mad when a senior engineer directed it at me? The realization that I do this often caught me by surprise. I tried to understand what internal motivation is causing me to behave this way. I came to the conclusion that when you’re helping someone in the first three stages, there is a 100% guarantee that they will lie to you. Not intentionally, of course. But one of their assumptions is false. Itz feels easier to just see the problem firsthand, perhaps lacking the falsehood that is preventing them from figuring out what’s wrong.

Ignoring a person completely is obviously not the correct way to handle this situation. Fortunately, realizing you have a problem is the first step in quitting. When I help others, I try to be explicit about my suspicions: “You are claiming that this shouldn’t happen. Obviously, it can. I want to try to reproduce this bug myself, to make sure one of your assumptions is not covering up the problem here”. If this course of action reveals the bug - great. If not, we can now put our heads together and try to understand what wrong assumption are we both sharing.

More importantly, whenever I ask for help these days, I try to be consciously aware to not infect the other person before they get to see the behavior themselves. Even after that, I try to minimize the perceived correctness of my previous efforts to solve this bug. I try to phrase myself in non-conclusive ways such as “I tried adding the library to gcc and it didn’t seem to work, but I may have done that wrong. If you think it’s in the right direction, you can try it yourself. I think there is a problem with version compatibility, but I’m not sure”. Phrasing yourself this way allows the other person to more easily question your assumptions and methods, which will generally lead to move from this shouldn’t happen to why is this happening?