12 Essential Debugging Tools for Software Engineers
Discover 12 debugging tools that can revolutionize your software development process, saving time and enhancing code quality.
Hi there! Jordan here. I hope you’re having a great day and thank you so much for being subscribed to High Growth Engineer. It’s insane to have reached nearly 6,000 subscribers in such a short time, and I have you to thank for it!
This week’s issue will be a little different from the norm.
Debugging is something every single software developer needs to know. In some cases, debugging alone can be 40%+ of the job.
Additionally, the most senior developers I’ve worked with have all shared strong debugging skills. It’s a must for growth in your career.
The way I think about debugging is that you have a set of tools in a toolbox. You can pull each one out and some have more value than others in each situation.
So today, I’ll be sharing with you 12 tools you can put in your “debugging toolbox.”
Many of them I was unfamiliar with early in my career but I use on a daily basis now.
I hope you find them valuable.
🧰 12 Debugging tools for your toolbox
Git bisect
If you can find where in the git tree the problem doesn’t exist, then you can run git bisect. It will run you through a binary search process between the “good commit” and the “bad commit” until it finds which commit the bug started happening.
In the past, I’ve been able to find what caused a 3-week-old bug by just checking 7 commits due to binary searching.
“Binary search commenting” (made up by me—I think)
I just made up this term, but essentially it involves commenting out sections of the code and replacing it with a hardcoded value to narrow in on where the problem is.
Example: I’m calling a lot of methods back-to-back. The end result of all those methods is wrong. I hardcode the result of each function to be what I expect. If the issue goes away, you know that hardcoding the value fixed it—so you can undo them in sections to see when it breaks again and narrow down on which one broke it.
Example 2: I want to narrow down the scope of the problem to just the frontend, so I mock out where I’m making the API call and return some hardcoded data. I’ve now separated that part of the system entirely. We could do the same thing for the database too if we were debugging backend code.
Minimal reproduction
As a frontend dev, I usually run “react.new” or “pen.new” in the browser to get a blank React Codesandbox or Codepen.
For backend devs, it may be creating a fresh API endpoint or Rails app using a generator and seeing if the issue persists in the blank environment. If it does, you can narrow in on it a lot easier since there’s much less to work with. If it doesn’t, you know it’s something specific to your environment.
GitHub Issues page
If it’s a problem with an external library, go to the “Issues” page for that library on GitHub and search the problem there.
Example: I was getting an error mentioning “getComputedStyle” when running Jest tests using JSDOM and I searched the GitHub issues page for both libraries. It gave me a ton more to learn and work with. Even if it doesn’t solve the issue directly, people usually mention workarounds or link off to other resources you can explore.
Sometimes you also realize that it’s an open issue for the library to solve, or that you need to upgrade to a new library version for it to get fixed.Library documentation page
Similar to the GitHub Issues page, just reading through the documentation for the library top-to-bottom helps me get my mind off the bug and understand the library I’m working with from a more fundamental level. It usually gives me additional ideas to try or understand why the library is acting the way it is.
Bonus tip: Sometimes you need to dig deeper and actually read the library code. The docs may not describe enough of the behavior, the expected errors or return types.
Read the error message. No really. Read the error message.
About 30% of the time, you’ll get lucky and there will be an error message that tells you exactly what you need to do to fix it.
Example: This is a notorious React error that tells you what you need to do. It tells you that each child you render in a list needs a “key” prop to be applied. Now, what to put in the “key” prop is a different question. But at least you know what the problem is.
Take a break. Go for a walk. Get sleep.
There have been times I’ve known that going back to the problem will just lead me nowhere. Sometimes it’s meant working on other things for 3-4 days until I feel ready to go back to it. Depending on the urgency, you can’t do this, but just know that it’s ok if you feel this way.
Ask ChatGPT
The process of writing it down will be like talking to another person or a “rubber duck.” Afterward, you’ll also get the opinion of ChatGPT so it’s a win-win.
Ask in team channels
After you’ve asked ChatGPT, you’ve likely been able to dumb down the question to where you can also ask in your team channels. See if anyone else has run into the issue before.
Pro tip: Before asking in team channels, search your question internally to see if it’s been asked before. 90% of the time, I end up finding my answer right away.
Pair with a teammate
If you work closely with a particular person, ask them to hop on a quick huddle. Explain the problem to them, but do not tell them what you’ve tried yet. Instead, say, “Before I go on, what are your thoughts so far? Do you have any ideas?” This ensures you get a fresh perspective and don’t put them in the same headspace you’re in—stuck.
Have confidence
This is easier said than done, but mindset plays a massive role in debugging. In my first couple of years as a software engineer, I never even read the error before copy-and-pasting it into Google or asking a teammate. I did this because the error scared me.
Nowadays, I look at each error as an opportunity to learn something new and become a better developer. Sometimes, I still do get demoralized but it happens a lot later than before. Having these tools to apply helps a lot. The question is usually, “I know I could solve this, but is it worth spending the time going through all possible ways of fixing it vs finding a workaround?”
Find a workaround
Building on the last point, understand it’s ok to call a bug “not worth it.” You may have tried a lot of the steps, and the next one involves digging into insanely complex open-source library code and debugging that. Many times, that just won’t be worth it. It can be better to find a workaround than to spend days attempting a fix.
That’s it! No TL;DR today since these were all pretty short on their own!
As always, thank you for reading.
- Jordan
P.S. You can reply to this email; it will get to me, and I will read it even if I can’t always reply in a timely manner.
Did you find this issue valuable? If so, there are two ways you can help:
You can also hit the like ❤️ button at the bottom of this email to help support me. It really helps!
As always, thank you for reading.
- Jordan
P.S. You can reply to this email; it will get to me, and I will read it even if I can’t always reply in a timely manner.
I like the phrase "binary search commenting", everyones done some version of that at some point haha
Debuggers are also a great tool to help you step through code and inspect program state without print statements
Love the advice!
Especially the smooth transition from tools to softer tactics :)
For me, the game changer was github issues. I was suprised how often searching the library and going deep into the discussion helped me solve some complex stuff.