Learning how to program can be challenging as you have all these different new skills to learn. One of those things is Debugging and this is a challenge for most of my students.
In this post I want to give some debugging tips for beginner programmers I which I knew when I started programming.
In the television series Star Trek there is the character called Spock. He is an alien from a race called Vulcans which are solely driven by logic. If he was real he'd probably be the greatest debugger in the universe.
Why? because Spock would look at the code as it actually is, and not at look at the code for what he wants the code to do!
My students often ask me for help with code that looks something like this:
const h1 = document.getElementById('h1'); h1.textContent === 'Hello world';
Can you spot the bug, probably it does not take you that long as it is very isolated. The === of course should be a =, we want to assign and not compare.
The intent is to assign "Hello world" to the textContentof the h1, but instead we are comparing if the current text of the h1 is equal to "Hello world".
These types of errors are logical errors. A logical error is an error in your head, or as an old joke says: "An error occurred between the chair and the keyboard".
Logical errors are not syntax errors: the code is syntactically correct and will execute, except it does not do what you want it to do.
So unlike syntax errors that blow up with all sorts of error messages, logical errors are silent, and hide in your code.
To sniff them out: be like Spock, look at your code detached from emotion, look at what the code does, and not what you think it does. Your own attachment to your code clouds your judgement. Keep an open mind. Know that it is most likely you that made a mistake.
For me it also helps in these scenarios to take a step back, get something to drink, go for a walk and then come back. Pretend that you are reading someone elses code and not your own.
Sometimes my students will ask me "Why doesn't this code work?" and the email me some code. For example they might send me:
const age = 10; // Uncaught TypeError: Assignment to constant variable. age = 15
Then I try to run the code and I see the error messages in the console or the terminal. Then I tell them "Do you see the error message in the console?"
Then they respond: "What error message?", they then proceed to feel quite guilty for even mailing me... but honestly it is a mistake many people make.
The lesson here: do not focus all your attention on the output of your code. Especially if the output is graphical like a web page for example. Look at the secondary output as well such as the error console.
When you get a syntax error it is your fault. This is sometimes very hard for people to accept for some reason.
No amount of pressing the refresh button or re-running your code is going to fix a syntax error.
So if you encounter an error such as:
Uncaught TypeError: Assignment to constant variable.
Read it aloud!
Look at the line numbers mentioned in the error, and objectively look at your code, and really try to understand what the error message is saying.
I admit that not every programming language has easy to read error messages, but most of the time they do have something useful to tell.
It is very unlikely you are the only / first person in the world that has every encountered a specific error. Copy and pasting error messages verbatim in Google often results in Stackoverflow questions for the same problem as you have.
Sometimes when my students write code they write to much code at once.
This makes it very difficult to know in which part of the code is responsible for the bug.
Instead write your code one single step at a time especially when you are just learning how to program. As you get more experience you can write more code at the same time, because the syntax does not get in the way as much.
Say for example you are writing a function: first write the functions definition, and give it a single console.log as the body of the function printing out the name of the function.
Call it an see if the name of the function is printed, now defined the function's parameters, and log the parameters as well in the body. Call the function to see if the parameters are logged as well.
Only if those parameters are logged correctly write the body of the function.
The same process also works for if-statements, check if your branches are hit correctly before writing the body of the branch.
Now if the code breaks down, you will have a much easier time figuring out where the code went wrong.
When you think you know where the problem lies, start logging everything surrounding that code.
It is very tempting to make assumptions about your own code.You can quite easily end up in a state of denial.
So if you think a variable has a certain value, log it to see it it actually has that value. This is the reason for many bugs you think the value is a number but instead it is a string.
Logging lets you see the truth about your code. There have been so many times that my students tell me with absolute certainty: "this code does this" or "this variable contains that".
Sometimes I ask them: "How do you know that? Are you sure?". Sometimes people then go on the defensive, and start talking, drawing diagrams on whiteboards, give powerpoint presentations, or write essays about what the value of a variable is.
Why spend so much time debating the truth when you can just log the truth instead.
A debugger is a piece of software that is literally designed to help you debug (aka fix bugs).
The basics of a debugger is that they allow you to set breakpoints. The code will stop running at these breakpoints allowing you to inspect your code, and see all the values of all variables currently in scope.
You can then move your code forwards or even backwards, you can get a really powerful view of what your code is doing.
One of my favorite features is the conditional breakpoint, a breakpoint that only stops the debugger when a condition is true. For example only stop when status === 'failed'.
Bottom line learn your debugger / dev tools, whether it is Xcode, Chrome, Firefox, Webstorm or Visual Studio Code.
In my experience all programmers fall into a spectrum when it comes to their favorite debugging tool, some only log, some only use a debugger, and some only use debuggers in specific scenarios.
There is a lot of online discourse about Debuggers vs Logs but my take is this: Do not underestimate the power of debuggers, but also don't underestimate the power of your personal taste if you like logs.
For me personally I start out with logs first and only use a debugger when the logging fails me. The reason I prefer logs is that they give me a more "hands-on" feeling, because the results can be seen very quickly, and iterated upon.
A debugger to me feels a little heavier. Whenever I use a debugger I always need to get my bearings first, not because I don't know how debuggers work, but more in the sense of: where am I in the code at this point in time.
Figure out what works best for you, but learn the other side to.This will make it easier to help colleagues on the other side of the spectrum.
Some beginner programmers are known to ask for help to quickly. It is perfectly fine to bang your head against a bug for a few hours, or even days depending on the type of bugs.
I think this stems from the idea that debugging is not being productive. Let me assure you, debugging is just a part of programming, just like making new features is!
Don't get me wrong... it perfectly fine to ask for help, but looking at a problem yourself also makes you a better programmer. There is nothing wrong with honing your debugging skills.
Each time you track down and fix a bug you become a better programmer. So do not deny yourself the experience.
Some beginner programmers are known to ask for help only after waisting days / weeks on a problem.
They either do not want to burden others, feel ashamed, or feel anxious, but some just love the thrill of finding the bug themselves.
My advice is to look at the your current context: are you solving a critical bug that needs to be in production ASAP, or are you coding for fun on a sunday afternoon. For the former you should ask help sooner rather than later.
Now a little advice on whom to ask for help: if your bug lies in syntax or small logic: ask your peers first. By peers I mean your fellow students, or other junior programmers. Most people find this less embarrassing than asking those old grizzled senior programmers.
If that does not work try stepping over your anxiety and ask you resident graybeard. Remember they started out as beginners as well!
When you do ask for help, try to make helping you as easy as possible.
My number one rule: remove as much code as possible before asking for help!
Break the code down to only the code that causes the bug.
I strongly advise either copying the entire project, or creating a git commit before breaking down your code.
Remove / comment out all extra code, all extra graphical elements, and get to the bare essence. Sometimes this process alone makes you see your mistake.
The reason this is so important is that you do not waste your fellow programmers time. The less code there is to look at the easier it is to help you!
There is another benefit, which is a social one. It shows that you made an effort before asking for help, which gives you credit!
When I get asked for help, and I see that the person made an effort, and that they can tell me the story of the bug, that they can show me the things they tried, and can point to the relevant bits of the documentation...
It alway makes feel like this person values my time. Which makes me happy to help!
The last one is a bit of a joke, but I've had numerous people over the years ask me for help finding a bug, only to realize that the file has not been saved!
If this happens do not beat yourself up over it, people make mistakes, even very silly ones!
But perhaps autosave is the feature for you!