Debugging Software


In this post, we'll talk about what you should know about debugging, some debugging methods, and a process you can follow when debugging your software.

Difference between debugging and testing

Testing focuses on finding bugs, errors, crashes, etc. Debugging starts after a bug has been identified in the software.

Testing is used to ensure that the program is functioning correctly based on predefined conditions. Testing can be manual or automated. There are several different types of testing like unit testing, integration testing, alpha, and beta testing.

Debugging requires knowledge of the software and specific types of access to the underlying system of the software. Debugging can take many forms, some of the methods are listed below.

Bug vs regressions

A bug is an issue with the software that makes functionality stop working as intended.

Regression is a return to a former or less developed state. For example, a regression is a bug in a new version of a software that does not exist in the previous version of the software.

All regressions are bugs but not all bugs are regressions.

Debugging Methods

Debugging methods are a structured way to find where the bug in your software is. Using a structured method should make debugging easier. If a method is not helping it can be better to step back and review if another method would make your debugging easier.

Here are some examples of valuable debugging methods.

Identifying recent changes

An easy way to identify an issue if you have a regression or bug that does not exist in a previous version is to look at what has changed in the software since the software was functioning correctly.

This is why a version control system like Git is important. Using Git you can look back at previous commits and see exactly what code has changed in your software.

Brute Force

This is the most common method of debugging and the method that can be least helpful. With this approach, the software is built multiple times while you add print statements or remove code to try and guess where the functionality of the software breaks.

Backward and Forwards Analysis

The backward and forward analysis approach involves tracing backward from the exact location of the breaking functionality and then tracing the functionality forwards up until the breaking functionality. This helps identify the region of the code that is causing the bug. After the region of code is identified you can then search line by line to find exactly what code is causing the bug.

With this method, you can still use print statements but breakpoints using your platform's debugging tools can be more valuable.

Cause Elimination

Cause elimination is a recursive method of forming a hypothesis of where the bug originates, testing your fix in that region, then forming another hypothesis and continue the process until the bug is fixed. This method is based on simplifying the hypothesis to reduce the number of possible hypotheses at each step.

The difference between cause elimination and backward and forward analysis is that cause elimination is driven by active thinking and explanation rather than using mechanical techniques like print statements and debugging tools.


When debugging creating unit and integration tests can be faster than testing the software manually. If you have properly decoupled your code to have a simple input and output, unit tests are beneficial to set up and can simplify identifying the region in which a bug is located. Unit tests can also prevent the bug from popping up again with a later version.

Integration tests are beneficial to test multiple functionalities of your software and can be used in conjunction with backward and forward analysis to identify the location of your bug.

Ask for help

Structured debugging methods can still fail to help you identify where your bug is coming from. It is important to not resort to exclusively brute force debugging over a long amount of time.

There is no shame in asking for help. It will save you time and save you from headaches.

Debugging Process

Understand the system and functionality you are debugging

Before you debug some software you should have an understanding of the software's basic functionality. Understanding the functions of the software, the platform, the codebase, and design patterns will make debugging easier.

Reproduce the issue

Before doing anything you must reproduce the issue. When a bug is found it is beneficial to outline the issue, the steps to reproduce the issue, and the expected results. Do this in conjunction with the team member or user that reports the bug

Use past experience

If you developed the software you may have introduced the bug. Take your past experience of debugging this software and your experience building the software to narrow down the location of the bug.

Use clearly defined methods of debugging

The methods above are a good starting place for methods of debugging. As you use these methods and develop your own, document these methods, and how you have refined them to help you and your team.

Do not create another bug

When fixing a bug you'll be changing something in your platform. Changing something in the software means there is a possibility for another bug. Don't replace one bug with another. To do this, make small changes and test for regressions.

Validate correction

Validate you fixed the reported bug by reproducing the steps with the expected result.

Test other effected functionality

Test functionality that may be affected by the bug you fixed. If there is time, do a complete regression test of the software.

Ask for help

If you are stuck, you don't understand something, or you are not sure of what you are debugging and fixing. Ask for help. You can talk through the issue with another team member, ask someone who has more knowledge about the software and ask for help reproducing the issue.

There's no shame in asking for help and every member of your team is there to help.