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.log
s 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.log
s 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.
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
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?
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"
// :(
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/>`
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)