In your software development career, you will have to spend a lot of time finding bugs in the code and figuring out why it doesn’t do the thing it’s supposed to do. This is what the process of debugging is all about.
Because debugging is where the majority of developers will spend their lion share of working hours, every developer needs to be aware that there is two way to debug the code – the right way and the wrong way.
The wrong way is how most of the developers do it. It goes like this:
The code doesn’t work? No problem!
Let’s tweak this variable over here. Still doesn’t work? Let’s tweak another variable. Let’s just keep tweaking random things until the code is doing what it’s supposed to do.
Finally, the bug is fixed. What exactly have we done to make it work? I have no idea! But who cares anyway? It now works and it’s all that matters.
Yes, I am exaggerating a bit, but not by much. Unfortunately, this is how bugs do often get fixed. It’s not uncommon to see a developer fixing a bug without having a deep enough understanding of how the part of the system that he is working on actually works. And yes, I’ve been guilty of this myself. Everyone has been at some point.
But there is also a different approach to debugging; the only approach that is correct – the scientific debugging.
What scientific debugging is
Scientific debugging is not a term that is commonly used in the software development industry. This is why you may have never heard it. However, this term appropriately describes how proper debugging is supposed to be done.
I’ve coined the term “scientific debugging”, because proper debugging should be conducted as if the problem that is being solved is a scientific problem. Exactly the same principles apply. We solve it by making hypotheses and testing them.
For those who don’t know, this is how a scientific hypothesis is constructed:
- An assertion is made that something works in a specific way.
- A test is constructed to verify whether that thing indeed works in this particular way.
- A null hypothesis is proposed to rule out other factors.
- The tests are conducted.
- The original hypothesis is confirmed or modified, depending on the test results.
And these are the exact steps that good developers will apply to debugging. Of course, this will not necessarily be the terminology they will use. And those who don’t have scientific background would probably arrive to this methodology by trial and error from their own experience. But nevertheless, this is the best way to debug the code effectively.
How does it translate to actual debugging
It may still not be obvious how to apply these concepts to the process of software development. After all, programming is not a pure science, right?
Well, the terminology may be different, but the process would still be the same. So, let’s have a look at an example of a bug to see how scientific principles can be applied to solve it.
Let’s assume that the you have a green button on the GUI that is supposed to trigger an event that is totally different from what is being observed. However, you know for sure that you have some bullet-proof code that will produce a behavior that is different from what this bug is all about.
In this situation, this is how you construct your hypothesis:
- I assert tat this specific piece of code gets executed if I press the green button.
- To test this, I will insert an unhandled exception (error) into this block of code.
- If the exception is thrown and the application crashes, the cause of the bug is something other than the code not being executed.
- If the application doesn’t crash, I need to see what happens upstream of that code. If the application crashes, I will need to see what happens downstream of that code.
So, essentially, instead of staring at what looks like a perfectly good code and wondering what you should tweak in it, you are first ruling out whether that piece of code even gets executed at all. If you have an unhandled exception in that piece of code, then you know that it gets executed if your application crashes during the execution. Otherwise, you know for sure that this particular piece of code never even gets executed to start with.
And this way of thinking should be applied to absolutely any problem in software. Proposing a hypothesis forces you to actually think about what may be wrong with your code. And while you are going through a number of cycles of proposing and modifying your hypothesis, you gain better understanding of the system.
At the end, when you actually solve the problem, you will know exactly what the problem was and what solved it. And you will know how that part of the system actually works. Next time, you will be able to add features to that system easily. Or if any new bugs pop up, you will be able to solve them quickly.
One way of making your job more exciting
As well as being effective, scientific debugging has another benefit. It is one of the best ways to make your programming job really interesting.
When you are debugging just by randomly changing bits of code until it works, it is extremely boring. Nothing makes you want to just drop everything and start scrolling down your Facebook feed instead.
However, when you consciously think what part of the system may not be working how it should, you get absorbed in the process and forget for the moment that anything outside this problem even exist.
Then, as you go through the cycles of modifying your hypothesis, it starts to feel like you are hunting down the prey. Dopamine, the hormone of pleasure and anticipation, kicks in as you get closer and closer.
It is very similar to what problem gamblers experience and this is what keeps them gambling until they either win, or lose all of their money. And yes, this may become addictive.
However, unlike gambling, addiction to programming is a great addiction. It is something that will pay your bills. And just imagine how far ahead can you go if you get addicted to the thing that you do for a living.
And if you have ever wondered how some people get addicted to programming, this is how. They start consciously asking questions about why the code works in a particular way and then they go ahead and try to propose the answers and test them. They get completely absorbed in their craft. They enter the state of flow.
The discipline of software development originated from science. Therefore, scientific methodology is the best tool to make the process of software development effective. This is why every software developer needs to be acquainted with science, at least at the most fundamental level.