Debugging like a pro

Gonzalo Osco Hernández
8 min readApr 26, 2020

--

Bugs are always on the development process and day by day we need to fix issues that were caused by wrong logic, incomplete validations, mistakes, code exceptions, missing development on the business logic, unexpected inputs, unsupported data, etc. It is normal on front-end, back-end, and DB side no matter language, framework, technology that we use to develop our applications. Fortunately, we have multiples tools to check and debug* our code and fix it on time.

However, bugs also happen in production and we had better fix it as soon as possible because it affects our clients and the quality of our products. When these products are big, support guys in the company are in trouble because they need to figure out what is happening and get a simple response explaining the issue to fix it, or in the worst-case get a workaround.

So, we will have to know a method that helps us to fix issues on our applications, not only search a workaround or adding a patch that most likely will come back with other issues, bugs, and headaches.

Let me introduce to debugging.

What is debugging?

Usually, we think that debugging is only to use a tool to check code and figure out the issue, but this one is some more complex. Maybe, empirically we realized that fix a bug it not simple like just modify code, it implies multiples tasks and criteria to follow.

Is “debugging is finding a fix”?… NO!

Debugging is the PROCESS of finding and resolving defects or problems within a computer program that prevent correct operation of computer software or system.

Effective Debugging (Like a dream)

In a magical and ideal world, effective debugging requires that we take these steps:

1. Work out why the software is behaving unexpectedly.

2. Fix the problem.

3. Avoid breaking anything else.

4. Maintain or improve the overall quality of the code.

5. Ensure that the same problem does not occur elsewhere and cannot occur again.

However, it does not happen like a waterfall model because we will need to repeat steps, come back to the previous step, or start again a lot of times. In order to find a solid fix that works for all cases and it can exist with my original code, not just a patch.

The Core debugging Process

This is the famous process that I am talking about that we follow to fix an issue. We discovered and rediscovered the same process when we develop any application, but sometimes we think that is implicit or it is obvious and we do not give due importance.

Debugging Process
Debugging Process

The secret to follow this process and get successful results is you need to know exactly what is happening, and what should?

Understanding is everything

I will try to explain all these points and figure out a reference like a recipe that we can follow including actions and techniques that help me for many years.

Reproduce it!

DEV and QA

Usually, reproduce a bug in our test environment might be the most difficult task because we will need to recreate the same scenario, set up similar configurations, replicate data, imagine the flow that the user followed. Also, we have to analyze all technical information as logs and device information including attachments that QA guys or escalation engineers added.

In order to find a way to reliably and conveniently reproduce the problem on demand, most likely we should follow these suggestions:

  • Reproduce First, Ask Questions Later
  • Start with the Obvious
  • Controlling the Software, Environment, and Inputs
  • Force Error Conditions
  • Check not only the “happy path”
  • Logging
  • As Simple as Possible

When you know steps to reproduce it, it is very important to reduce those ones and rule out other possible causes in order to minimize your field of action.

Reproduce it!- PUT IN ACTION

  • Find a reproduction before doing anything else.
  • Ensure that you’re running the same version as the bug was reported against.
  • Duplicate the environment that the bug was reported in.
  • Determine the input necessary to reproduce the bug by:
    - Inference
    - Recording appropriate inputs via logging
  • Ensure that your reproduction is both reliable and convenient through iterative refinement:
    - Reduce the number of steps, amount of data, or time required.
    - Remove nondeterminism.
    - Automate.

Diagnose it!

Diagnostic an issue needs lots of knowledge about the bug and business logic. It will need lots of tests, analyze more examples, and investigate more according to symptoms and current behavior.

In order to get a good diagnosis, we should construct hypotheses, and test them by performing experiments until we are confident that we have identified the underlying cause of the bug.

This flowchart can explain better what we should do.

Diagnose it! — THE EUREKA MOMENT

In this part, we have lots of information in our head about the bug including findings, tests, and source code that was analyzed with a debug tool, etc.

There is a time when suddenly realized what is happening and why. This is the Eureka moment and all our findings and tests already make sense.

I already know why it does not work!

Diagnose it! — PUT IN ACTION

  • Construct hypotheses, and test them with experiments.
    - Make sure you understand what your experiments are going to tell you.
    - Make only one change at a time.
    - Keep a record of what you’ve tried.
    - Ignore nothing.
  • When things aren’t going well:
    - If the changes you’re making don’t seem to be having an effect, you’re not changing what you think you are.
    - Validate your assumptions.
    - Are you facing multiple interacting causes or a changing underlying system?
    - Validate your diagnosis

Fix it!

Basically, we should design and implement changes that fix the problem, it sounds simple I know how difficult can it be but at this point, we already finish the hard work and we just need to add some lines of code or conditions and refactor small source code with the correct logic. This fix should avoid introduce regressions and maintain or improve the overall quality of the software.

Usually, make a fix is very easy when we can reproduce the issue and have a solid diagnosis, but we must be very careful to fix the main problem (Root Cause) instead of a symptom. Fix the symptom might become a potential and a very dangerous bug in the future may be more dangerous than the original.

Fix the Cause, NOT the Symptoms!

But pay attention to the Symptoms!

Fix it! — How to find the ROOT cause

There is a technique that helped me to fix lots of issues for any kind of application. This is useful for any area that you can imagine.

5 Why Analysis

The 5 whys strategy helps us to examine any problem in order to identify/make sure that we know the problem root cause. We start to wonder the question: “Why … ?” The first answer will generate another “why”, the second answer will generate another “why … ?” so it will ask you for another and so on.

Fix it! — Keep a Record of What You’ve Tried

Daybook

When we are working on multiples issues it’s useful to maintain a daybook in order to record notes from meetings, steps to install/run our applications, add documentation, or anything that you consider useful in the future for your work. It is better if we prefer to keep your notes electronically or using a personal wiki in order to have them at hand at any time.

Also, we need to write details about all our changes, fixes, and important details that we discover about our applications. I can assure you that will use these notes lots of times to new issues.

Fix it! — PUT IN ACTION

  • Bug fixing involves three goals:
    - Fix the problem.
    - Avoid introducing regressions.
    - Maintain or improve overall quality (readability, architecture, test coverage, and so on) of the code.
  • Start from a clean source tree.
  • Ensure that the tests pass before making any changes.
  • Work out how you’re going to test your fix before making changes.
  • Fix the cause, not the symptoms.
  • Refactor, but never at the same time as modifying functionality.
    One logical change, one check-in.

Reflect it!

If we arrive at this point I know that minutes or hours or days passed to fix the bug on our application following the debugging process. Then it is mandatory to learn lessons of the bug in order to prevent similar issues, identify more easily those ones, and do not lose time again.

We should ask the following question:

  • Where did things go wrong?
  • Are there any other examples of the same problem that will also need fixing?
  • What can you do to ensure that the same problem doesn't happen again?

Reflect it! — PUT IN ACTION

  • Take the time to perform a root cause analysis:
    - At what point in your process did the error arise?
    - What went wrong?
  • Ensure that the same problem can’t happen again:
    - Automatically check for problems.
    - Refactor code to remove the opportunity for incorrect usage.
    - Talk to your colleagues, and modify your process if appropriate.
  • Close the loop with other stakeholders.

when you have eliminated the impossible, whatever remains, however improbable, must be the truth?

I wrote this short text according to my personal experience working as a support engineer and following some points that Paul Butcher establish in his book Debug it! I know that this kind of suggestion and technique that I tried to explain sounds obvious but a little improvement is a big difference working as a software developer.

--

--