DEV Community

Adrian Bernardo
Adrian Bernardo

Posted on

5 Things You Shouldn't Do When Debugging šŸž

To start this year off I really wanted to focus on bettering myself as a dev and as a person. My first goals that will help me achieve that is to take a course in a weakness of my skills and to also put myself out there more by blogging.

One weakness that I wanted to improve was my debugging skills. For the past few years I found my own way to find the root cause of a bug. But I often wondered if there's a framework out there that could make the process more efficient. Knowing a framework like that would be very valuable to me, for the company I work for, and hopefully for you all who are reading this. So far Udacity's Software Debugging course is showing me that process Iā€™m looking for.

If you like to check out the course and take it yourself you can find it here.

One of the things that stood out to me so far in this course was what not to do when debugging and I liked the name of the section: The Devil's Guide to Debugging šŸ˜ˆ

The guide explains the 5 important things you shouldnā€™t do when debugging:

1. Scatter Output Statements Everywhere

This means that we shouldnā€™t use our go-to console.logs for us JavaScript people, System.out.println for Java, or the equivalent to many others at all possible places to find the bug.

In the below example we have a function removeHtmlMarkup that removes HTML markup and returns what's leftover. There is a bug in the program so we might end up using a lot of console.logs to see if we can find the error.

function removeHtmlMarkup(htmlString) {
  let isTag = false;
  let output = '';
  console.log(htmlString);
  [...htmlString].forEach(character => {
    console.log(character);
    if (character === '<') {
      console.log('open tag');
      isTag = true;
    } else if (character === '>') {
      console.log('close tag');
      isTag = false;
    } else if (!isTag) {
      console.log('non html');
      output = output.concat(character);
    }
  });

  return output;
}

console.log(removeHtmlMarkup('<b class=">">foo</b>'));
// output: "foo
// Since the quote is part of the HTML markup 
// it isn't working as expected.
Enter fullscreen mode Exit fullscreen mode

The above would output a wall of text that doesn't seem too helpful. We'd have to take quite a bit of time to understand what each line of text means.

<b class=">">foo</b>
<
open tag
b

c
l
a
s
s
=
"
>
close tag
"
non html
>
close tag
f
non html
o
non html
o
non html
<
open tag
/
b
>
close tag
"foo
Enter fullscreen mode Exit fullscreen mode

I know Iā€™ve done the above many times thinking that it would help me spot the error. And eventually I would find the error after some time. But I now realize that I could save myself more time by thinking through my logic to lead me to the error.

Donā€™t get me wrong, it's okay to use our print statements but only after thinking it through. Print statements should mainly be used as a way to verify our best guess as to what the problem could be.

2. Debug the Program into Existence

Before when I started doing side projects or practicing solving coding questions there would be moments where I get frustrated at some edge case that I couldnā€™t figure out. I felt like no matter what I did I just couldnā€™t get to the right solution. So Iā€™d end up just adding or removing random lines of code just to see what output Iā€™d get.

function removeHtmlMarkup(htmlString) {
  let isTag = false;
  let output = '';
  [...htmlString].forEach(character => {
    if (character === '<') {
      isTag = true;
    } else if (character === '>') {
      isTag = false;
    } else if (!isTag && character !== '"') {
      // In the above condition we added `character !== '"'`
      output = output.concat(character);
    }
  });

  return output;
}

console.log(removeHtmlMarkup('<b class=">">foo</b>'));
// output: foo
// This looks correct but is the function working
// as we intend it to?
Enter fullscreen mode Exit fullscreen mode

Sometimes Iā€™d get the output Iā€™m expecting but I would see that the other edge cases would still be wrong or worse if they were previously working would not work anymore. Doing all of that would just waste time and Iā€™d feel pretty bad about myself.

function removeHtmlMarkup(htmlString) {
  let isTag = false;
  let output = '';
  [...htmlString].forEach(character => {
    if (character === '<') {
      isTag = true;
    } else if (character === '>') {
      isTag = false;
    } else if (!isTag && character !== '"') {
      // Above condition helps produce what I expect
      // but what if our input contains quotes outside
      // of HTML tags?
      output = output.concat(character);
    }
  });

  return output;
}

console.log(removeHtmlMarkup('<b class=">">"foo"</b>'));
// output: foo
// Since the two double quotes are not part of
// the HTML tag we should've expected: "foo"
// :(
Enter fullscreen mode Exit fullscreen mode

We shouldnā€™t just debug the program into existence hoping to just find the right answer. Instead, we should always go back to thinking through our code.

3. Never Back Up Earlier Versions

Version control like Git really helps here. Itā€™s very useful to keep a snapshot of the history of our code because there will be times when a bug is presented and sometimes reverting back to an older working change is a decent solution. But can you imagine not having an undo capability or being able to go back to the most recent stable state? I donā€™t want to imagine that but I know it would make life difficult because we donā€™t want to lose track of all of our hard work that was correct.

One of the things Iā€™ve learned in the course was the idea of not keeping track of previous best guesses as to what went wrong. This stood out to me a lot because before I would try many solutions to fix a bug in my head and if it still didnā€™t work Iā€™d sometimes leave to go take a break. After some time I would come back to try to fix the problem but I had forgotten the previous solutions Iā€™ve tried or what the outcomes of those were and end up redoing things and wasting more time.

To prevent that I keep a note somewhere or write down on a piece of paper of all the edge cases or solutions Iā€™ve tried. If I were to take a break or come back the next day I can pick up where I left off. Sometimes Iā€™d come back seeing the best answer right in front of me.

4. Don't Bother Understanding What the Program Should Do

This is very important especially when working with a large complex code base and when trying to understand the task assigned to you.

If all we care about is finding the problem without fully understanding what it should do it could lead to more bugs being inadvertently introduced. Even worse it could negatively affect the user.

Only fixing the symptom and not the root cause creates more complications and more time down the road. Thatā€™s really bad. It serves you better to take the time to fully understand what is being asked and what a program should output in order to provide the right solution and also cover all expected paths from a program.

5. Use the Most Obvious Fix

I wish it were that easy to fix for the error we see for a certain condition but it wouldnā€™t fix the main problem.

function removeHtmlMarkup(htmlString) {
  if (htmlString.includes('"foo"')) {
    return '"foo"';
  }
  let isTag = false;
  let output = '';
  [...htmlString].forEach(character => {
    if (character === '<') {
      isTag = true;
    } else if (character === '>') {
      isTag = false;
    } else if (!isTag && character !== '"') {
      output = output.concat(character);
    }
  });

  return output;
}

console.log(removeHtmlMarkup('<b class=">">"foo"</b>'));
// output: "foo"
// This "works" but it wouldn't cover different inputs 
// that have quotes in them like `<b>""<b/>`
Enter fullscreen mode Exit fullscreen mode

This section is similar to the previous one because using the most obvious fix means that we donā€™t fully understand what our code should do.

Instead we should strive to understand the actual problem and find the origin. Once we understand the problem we can then implement the best solution to remove the bug.

Conclusion

I know some of these points from the guide might sound like a given but I know Iā€™ve fallen for some and really tempted to do others.

The main takeaway from these points and the course so far is to lean on a good systematic way to debug so that we wonā€™t waste time and not go too crazy when figuring out what went wrong in our program.

What is a good systematic way to debug? That will be explained in my next blog post.

I look forward to sharing more of what I learned from this course and hopefully we get a lot better at debugging.

Say hi and follow me on twitter @AdrianBruhnardo

Top comments (0)