“As soon as we started programming, we found out to our surprise that it wasn't as easy to get programs right as we had thought it would be. Debugging had to be discovered. And I can remember the exact instant where I was—our tape equipment was on one floor, the computer was on the other, and and I was passing down from the computer to make a change in my program tape—and in that instant I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.”
—Maurice Wilkes in 1979 talking about his work in the 1940s.
“Debugging is like a murder mystery where you are both the detective and the murderer.”
A gap between how we think a program works and how it actually works.
Misunderstanding something about how our programming language works.
Writing something different than what we actually meant (e.g. using =
when we meant ===
).
Forgetting or misunderstanding details of how some code actually works.
It’s to fix our understanding.
Then fix the program.
Make a hypothesis.
Design an experiment.
Run the experiment.
Update our mental model.
Hypothesis is just a fancy word for something you think is true.
“I think that after this function is called, there will be an X in the cell that was just clicked.”
“I think that the move counter increases by one after each move.”
Make a small change to the code that will give you information about what is, in fact, happening.
Ideally the information will tell you one way or the other whether your current hypothesis is true or false.
console.log
is a great way to get more information.
But try to predict what will happen: “If this is true, it should log, ‘X’ after we click the cell.”
Now rerun the code and see if the thing you expected happened.
If the thing you expected happened, great. Now you know that part of your understanding of your code is correct.
But that also means you’ve got to look elsewhere for the gap in your understanding.
The best thing that can happen is when your experiment reveals that something you thought was true isn’t. Now you can try to narrow it down.
Sometimes hypotheses need to be really simple.
Say you’re debugging a problem where something isn’t happening that should be.
Is the file you are debugging actually being loaded?
Is the function you are debugging actually being called?
Is the line you are debugging actually being reached?
It’s very tempting to put energy into trying to prove that the code should be working.
That’s a waste of energy. If it’s not working, you want to spend your energy on thinking creatively about what you may have misunderstood.
Then rule out as many as you can with your experiments.
If you can’t find the gap in your understanding, make the code simpler.
Delete or comment out chunks of code so you no longer have to account for them.
Once you understand the behavior of a stripped down program, then start slowly putting pieces back and make sure you understand how each change affects things.
console.log
// prints "here" in the console
console.log('here');
// prints "x: " followed by the value of x
console.log('x: ' + x);
// prints the value of x in a pretty form
console.log(x);
// print a static representation of x, even if it's a complex value
console.log(JSON.stringify(x));
Beware, when you print just a variable sometimes the value is live meaning that if it changes in the program the place it was printed will be updated.
That can be confusing.
You should be able to explain every line of code in your program.
Change it and see what happens.
Make a hypothesis.
Test your hypothesis.
If you can’t figure out what something does, in the help queue paste the line of code you don’t understand and your best guess about what it does.
If you understand all your code but are still stuck, describe in your question what you are trying to do and what you’ve tried so far.