Being a developer for over 20 years I realized that when a started I saw debugging not as a craft on which I could improve but as a tedious factory job that sadly you need to do when you're a developer. And nobody wants to do dull work, so as many before me I started looking for ways to improve my debugging skills so I could be more efficient at it. Nowadays I see debugging as an art which takes ongoing efforts to master. But can be really fun when you get better at it.
The value of debugging
Fact: Nobody writes perfect code, and errors are an inevitable part of developing software. Being able to locate and fix errors is an important and underestimated part of learning to code. It's also the hardest skill to teach. To be honest, learning to step through your code with a debugger isn't very complicated, but it only will get you so far. Learning how to use scientific, methodical logic, creative problem solving and being able to understand what you're actually seeing is much more complicated.
This is why I decided to create a list with tips to help you get a head start on becoming better at debugging. The list is based on my personal best practices and years and years of frustrating error-solving. Looking back, it would have helped a lot if I've had a couple of the tips from the start. Hopefully, you'll pick up some new ideas.
Mindset: They're errors not bugs
Before you continue it's important to have the right mindset. Remember: every error is an opportunity to learn, almost always about yourself (because only beginners blame the computer). And yes, they're errors, not bugs! As Dijkstra stated: the term bugs support the idea that something sneaked in our code while we weren't looking, instead of being there by our own creation (http://www.cs.utexas.edu/users/EWD/transcriptions/EWD10xx/EWD1036.html)
1. Learn to use a step-by-step debugger:
(or print/echo/console.log a lot if you don't have a debugger).
Use the debugger by:
a. Adding watches to validate values of variables
b. Setting breakpoints on relevant parts of your code
c. Go through your code step by step and validate the input/output of each and every step
2. Assumptions are the m*therf*cker of all f*ck-ups
Assumptions are wonderful: these quick conclusions are what makes you a real expert, but sometimes they are just plain wrong. How many times did you spend hours and hours staring at lines of code and saying: "This should work!" Blinded by your assumptions, unable to see the obvious flaw right under your nose. When you finally found the error, you decide to quit your job, because of how stupid you were not seeing your mistake right away.
Should you not make assumptions then?
You should make a lot of assumptions on what caused the error. Give yourself some time (max. 15 minutes), make drawings, write your assumptions down. Which one does your intuition tell you is the correct assumption? Which ones are easiest to validate? And start validating your assumptions. Making those assumptions and validating them first, helps you reason about the structure of your code.
If you don't know for sure how something is working, and assume that it must be correct, you're making assumptions. So figure out how it's working first, read the code or ask someone to explain.
If you just randomly assume and change your code, you're not a developer, you're a vlorker (which is what we at GHG Tech call someone who does that). Read http://us.talentlens.com/dr-judy/how-to-recognize-your-assumptions about recognizing assumptions
3. Binary search to the rescue
Don't start at the beginning of your executed code, start halfway the steps of the code. The idea behind binary-search is to quickly identify/isolate a small region which contains the error. Developers are often not aware that they save a lot of time with this. How often was the error right at the start of your code?
A simple example
If you don't know which line in a 100-line program has an error, you set a breakpoint at 50 lines. Do the variables have the expected value, is this code even reached? If not, you know this first segment contains the error. You next try to split this and run the first 25 lines and see if the problem is there and so on until you have figured out a short enough piece to look at.
Other approaches are commenting out code till it works and then adding pieces back'or more modern approaches like git bisect. My problem with tools like that is that you don't learn to debug code, learn from it and thus will make the same mistakes in the future.
4. RTFE (where E = Error message)
Error messages are scary things you must avoid at all cost! Especially when you just started developing, they can be quite overwhelming. One important thing to understand about error messages, although an error message will tell you where it was detected it will not tell where it occurred. Read the message and try to understand that.
Learn about the stack trace.
If you have a run-time stack trace, start at the top and trace your variable assignments and function calls backwards. If you have a compiler error, the cause is often in a line before the one cited by the error message.
Google for the error message and add context to your search query, if you're debugging Boto in regards to an S3 problem, combine the error message adding Boto and s3 to your search query. And if you get a result, don't just copy/solutions, understand what the solution is and validate if it's indeed a fix for your error.
Run your code every time you make a significant change. Don't randomly tweak code; follow the code's execution process and validate your assumptions. Ask yourself the question: "If I change this part of the code will it result in the expected behavior?" Yes, continue with the next change. It's maybe stating the obvious but be honest are you always applying this principle?
6. Rubber ducking
The term comes from a story in the book The Pragmatic Programmer in which a programmer carries around a rubber duck and debugs his code by forcing himself to explain it, line by line, to the duck. Have you had the experience when explaining a programming problem to someone else, even to someone who doesn't know anything about coding, and in a sudden realization, finding a solution? You can use actual rubber duckies or use the modern day version created by my colleague Erik Driessen directly.
7. Take a break and walk away.
Remember those late nights, up till 3 a.m. working on that nasty error, going to bed completely defeated, waking up the next morning with a new brilliant solution.
When you are stuck your mind tends to get even more stuck and you don't see the actual problem anymore. Just let it rest for a while, go out for a walk, drink a cup of coffee, attend to another piece of code or pay a visit to your grandma (chance to apply your rubber ducking skills). You will probably notice that taking a step back might actually reset your brain and you will see another way to tackle the error
8. Ask for help
Asking a colleague for help should not be seen a weakness it's actually a strength. How wonderful it is to be able to help out a colleague with a problem and solving it together. Giving each other a high five and talk about that nasty error even years later is really good bonding mechanism. But don't do it before you've at least tried to tackle it yourself with the first 7 tips.
I wrote down my personal approach to debugging, but since it's a creative process and you learn every day, it's in no way a definitive list. I'm curious to hear your anecdotes and best practices. And keep in mind: Everyone knows that debugging is twice as hard as writing code in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? So for now happy debugging...uh...de-erroring!!