Basic Debugging 101
How to Start Finding and Fixing Bugs
This is a beginner-friendly guide to help you get started with debugging and improve your skills over time.
As developers, we know encountering bugs and creating misbehaving code is inevitable, whether we like/accept that fact or not :)
By familiarising yourself with debugging you can save yourself hours of frustration and get to the root of the problem much sooner.
You can learn to do that proactively, the easy way.. OR the hard way, when everything breaks and suddenly you just have to.
In this post, I've drawn on my own experiences, a great book I'm reading called "Debug It!" by Paul Butcher, and some other cool articles linked at the bottom of this post.
I'm going to cover the core debugging process, basic techniques, and debugging tools to help you become a more effective debugger.
I’ve also created a simple GitHub Project with common bugs for you to practice with.
1. The Greatest Pitfall of Debugging
"Debug it!" highlights dangers of skipping diagnosis and jumping straight to fixing the code. Changing source code without understanding it or the problem can mask the real cause and could create to more bugs. Sometimes there can be a very simple solution to a bug and it's easy to over complicate things by not taking a step back and looking at the problem from a different angle.
For example consider the following code snippet:
python
def divide(a, b):
return a / b
If you encounter a bug where divide(10, 0)
throws a ZeroDivisionError
, you might be tempted to add a check for b == 0
and return None
instead. But this doesn't solve the root cause of the problem. The real issue is that you're trying to divide by zero, which is mathematically impossible.
2. Common Errors that help you identify bugs
- Runtime errors
- These are the harder to spot. Your code will compile or run, but it’ll crash when it hits something it can’t handle.
- Some examples are dividing by zero, trying to access a file that doesn’t exist, or calling a function with the wrong arguments.
- These errors are usually caught by the interpreter or runtime environment and are reported as exceptions. Check logs or console output for error messages.
- Logic errors
- Your code runs without crashing, but the output is wrong.
- These bugs happen when your logic is flawed for example a loop iterating one too many times or an if else conditions not accounting for all possibilities.
To help identify and defend against these bugs, write unit tests and use assertions to validate your code.
- Core Debugging Process
"Debug It!" outlines a systematic approach to debugging:
- Reproduce: Make sure you can reproduce the bug consistently in your development environment.
- Diagnose: Come up with a hypothesis about what’s causing the bug, test to confirm it, and gather more information if needed.
- Fix: Design and implement the fix, avoiding regressions (accidentally breaking other functionality) -> verifying with tests, and maintaining code quality.
- Reflect: Use this as a learning opportunity to prevent similar bugs in the future. This is an interactive process that can be repeated until the bug is fixed.
I highly recommend reading "Debug It!" for more details on the debugging process and techniques. It’s a great resource for anyone looking to improve their debugging skills.
4. Basic Debugging Techniques
- External Knowledge:
- Sometimes, the answer is just a web search away. If you’re stuck on something specific, like a library or an unfamiliar error, don’t hesitate to check the documentation, browse through and look for similar problems in forums.
- Ask others on your team or in the community if they’ve encountered similar problems and how they solved them. No need to reinvent the wheel!
- Using Print Statements:
- Adding print statements or console logs in key parts of your code can help you see what’s actually happening versus what you expect.
- Print the values of variables, function outputs, and other important data. This can also help isolate the problem.
- Reading Error Messages:
- Error messages are your friends. They might look intimidating at first, but they’re full of useful information. For example they tell you the type of error, the line of code where it occurred, and sometimes even suggestions on how to fix it.
- Pay attention to the stack trace it’s like a breadcrumb trail that points you to the line of code that caused the issue. Once you know where to look, fixing the problem becomes a lot easier.
- Commenting Out Code:
- One way to isolate the bug is to comment out sections of your code. This can help you identify which part is causing the issue.
5. Debugging Tools
Once you get the hang of using a debugger, it’ll feel like having X-ray vision for your code. Debugging tools like VSCode for Windows and GDB for Linux can make it easier to step through your code and catch bugs in action. They allow you to set breakpoints, inspect variables, and watch the flow of your program.
Step-by-Step Debugging in VSCode (Windows)
1. Set Up Your Debugger:
- Open VSCode and load the project you want to debug.
- Make sure you’ve installed the relevant language extension (e.g., Python, JavaScript, C++).
- Click the Run and Debug icon (on the left panel) or press
Ctrl + Shift + D
.
2. Set Breakpoints:
- Find the line of code you want to inspect and click to the left of the line number to set a breakpoint.
- A red dot will appear, indicating that the debugger will pause execution at that point.
3. Start Debugging:
- Go to the Run menu and select Start Debugging or press
F5
. Your program will start, and execution will pause when it hits the breakpoint.
4. Step Through Your Code:
Once the debugger pauses at your breakpoint, you can use the following commands to step through the code:
- Step Over (
F10
): Move to the next line of code without diving into functions. - Step Into (
F11
): Step into function calls to see what happens inside them. - Step Out (
Shift + F11
): Exit out of the current function and go back to the caller.
- Inspect Variables:
- Step Over (
In the Variables pane, you’ll see the values of your variables at the breakpoint. You can hover over variables in your code to see their current values as well.
6. Continue or Stop Debugging:
- Once you've identified the issue, you can either press F5 to continue running the code or stop the debugging session by pressing Shift + F5.
Step-by-Step Debugging with GDB (Linux)
1. Install GDB:
- If you don’t have GDB installed, you can install it using your package manager:
sudo apt-get install gdb # For Debian/Ubuntu sudo yum install gdb # For Red Hat/CentOS
2. Compile Your Program with Debugging Symbols:
- To use GDB, your program needs to be compiled with debugging information. Add the
-g
flag when compiling your code:gcc -g -o my_program my_program.c
3. Start GDB:
- Launch GDB by running:
gdb ./my_program
4. Set Breakpoints:
- Inside GDB, set a breakpoint at a specific line or function by using:
break main # Set a breakpoint at the start of main() break 42 # Set a breakpoint at line 42
5. Run the Program:
- Start the program using:
run
- GDB will run the program and pause execution when it hits your breakpoint.
6. Step Through Your Code:
- Once the program is paused at a breakpoint, use these commands to navigate:
- next: Step over to the next line.
- step: Step into a function.
- finish: Step out of the current function.
- continue: Resume execution until the next breakpoint.
7. Inspect Variables:
- To view the current value of a variable, use:
print variable_name
- You can also inspect memory addresses and more complex structures by printing variables directly.
8. Exit GDB:
- Once you’re done, you can exit GDB with:
quit
5. Practicing Debugging
- Debugging is a skill that improves with practice. The more bugs you fix, the better you’ll become at spotting patterns and identifying issues quickly.
- Here’s a simple GitHub project with common bugs for you to practice with. Clone the repository, read the instructions, and start debugging!
Conclusion
- By following a systematic approach, using basic techniques, and leveraging debugging tools, you can become a more effective debugger.
- The key is to understand the bug, not just fix it.
- Check out some of the other resources available to help you level up your debugging skills.
That's it for this post! I hope you found it helpful and that it helps you to tackle those bugs head-on. Happy debugging!