Guess and Pray Debugging

There are two types of debugging.

  1. Guess and Pray Debugging
  2. Systematic Debugging

What is Guess and Pray Debugging?

Guess and Pray Debugging goes like this:

  1. Someone gives you a bug to fix
  2. You try something random (or almost random)
  3. It doesn’t work
  4. You repeat steps 2 and 3 until it works

This method will take much longer and usually doesn’t work. It’s like shooting in the dark.

I’ve seen everyone from co-ops to senior developers use this method. It usually happens when the developer isn’t familiar enough with the language, framework, or codebase to employ systematic debugging.

In its worse form, the developer isn’t familiar enough with the language to do anything except guess and pray. They’ll try things that are obvious syntax errors in a desperate hope that something will compile. This is when you have to slow down and take some time to learn the language, framework, etc.

It’s a skill in itself to recognize your understanding isn’t deep enough yet to debug something, and determine when it’s time to step back. Either ask for help or watch a couple YouTube videos on the subject.

What is Systematic Debugging?

The opposite of “Guess and Pray” debugging is “Systematic Debugging”. This is when you start at the beginning and act methodically, using deductive reasoning to determine the issue.

  1. Someone gives you a bug to fix
  2. You try to reproduce it
  3. You pick a starting point near the bug and follow the trail of evidence such as logs, stack traces, and behaviours until the root cause is discovered. It may also be useful to use an interactive debugger, print statements, wolf-fencing, and other techniques if the bug is not immediately obvious.
  4. Implement a fix based on your insight from step 3
  5. Test your fix worked

This is also sometimes called “first principles thinking” which means boiling a problem down to the fundamental truths, and working up from there.

In my experience, this type of debugging is much faster than “Guess and Pray” debugging. I’ve employed this technique and determined production issue causes very quickly. I also used “Guess and Pray Debugging” when I was just starting out, and I remember the struggle and frustration that comes from this technique. The difference can be a matter of minutes to a matter of hours or even just giving up.

Debugging Short-Cuts

If something is critical priority, you can try to take short-cuts from the more formal systematic debugging. However, you usually need knowledge, context, and experience in the codebase, framework, and languages to take a short-cut. You have to be careful this doesn’t turn into “Guess and Pray” debugging which is defined by a lack of understanding.

Here’s a few examples of debugging short-cuts, which are different from “Guess and Pray” debugging:

  • I saw this exact same error 2 months ago, so this might be because of X
  • We just deployed some code that changed these files, so it’s probably because of pull request Z

There is also a risk with a short-cut that it will go nowhere. If you take a short-cut and it doesn’t feel like you made progress, it may make sense to jump back to before you took the short-cut.

Conclusion

“Systematic Debugging (with or without well-executed short-cuts)” is usually significantly faster and more effective than “Guess and Pray Debugging”. It’s important to recognize which one you’re doing, and try to catch yourself guessing and praying.

Epilogue

A few other notes on debugging while we’re here:

Group Debugging

Group debugging is where at-least 2 people get on a call and try to solve an issue. It often happens when a production incident occurs and everyone is panicking to solve the problem.

These calls can be useful to quickly establish context, but it’s also easy to go wrong.

One thing I want to recommend against, is employing the “Guess and Pray” technique during a group debugging call. This can be distracting, and waste precious time during a production incident response.

Here is how a successful group debugging call usually goes:

  1. Someone says “let’s jump on a call”
  2. Someone with context concisely explains the issue to people without context
  3. 1-2 people start systematically debugging. Any more than that and it can become inefficient. It’s important to listen to the people systematically debugging during this call, and try to avoid “Guess and Pray” debugging. Ideally, we should pick the “systematic debuggers” based on who we think might be able to take the most debugging short-cuts as described earlier. Someone who recently worked in the relevant code, has experience with similar issues, etc.
  4. We identify the issue with reasonable confidence, because we used systematic debugging
  5. Other people on the call help with deploying, prioritization, and communication

Code Quality and Debugging

If even a senior developer is struggling to apply systematic debugging, it’s usually a sign of poor code quality. It’s easier to do systematic debugging when the code is easy to follow with minimal indirection. This is another argument, among many, to adopt an organizational culture that prioritizes high code quality.

Writing a Regression Test

For the last step in systematic debugging, some people also write an automated test that verifies the fix. I think this is a good practice, because it increases the confidence that your fix worked and it also prevents the issue from happening again.

However, it’s important to ensure that the test fails before the fix is applied and passes after the fix is applied. It’s easy to accidentally write an automated test that passes before and after the fix.

In a production incident, sometimes it’s hard to justify this to stakeholders under time pressure, but it’s worth trying. You can also try writing the automated test after the fix is implemented but while some other parallel task is happening (e.g. QA is manually testing, an environment is being provisioned, etc.) so you don’t delay the roll-out for the fix.

Written By Ben Lorantfy

Ben is an award-winning software developer specializing in frontend development. He builds delightful user experiences that are fast, accessible, responsive, and maintainable and helps others to do the same. He lives with his partner and dog in Kitchener, Ontario.More About Ben »Follow @benlorantfy on twitter »