You've just coded a sweet new algorithm that takes a string and some some fancy business on it, or maybe a new hashtable, controller, or SQL function...
But the function is not performing how you expected...
What do you do? Walk us through your process.
Do you use a debugger? Do you use log/print statements? Which area of the code do you look at first, second, third?
I think it will be a lot of fun to share each others' debugging tips.
For most of the problems while debugging, I mostly read my own code and try to make a sense of what I've written instead of blissfully starting to debug (which wouldn't make sense if you had written wrong code logic). The best way to ensure this is TDD. I've only realised this recently and I've started learning how to simultaneously test code before / while I write it.
If everything seems right there, I go for the call stack. But especially for lazy loaded / set values, debugger is the best bet. For example read this conversation and see the mistake I made (also tell me if you understood the last pic a guy posted there, I couldn't figure out if it was a joke, or what the joke was if it was 😅)
Good Error Handling in the code. I recently made a small automatic comment syncer component/app for an interview process. While making it, I learnt what good error handling can do for you.
For UI bugs, if I know which part of the UI the bug is happening (say it's in hashnode's comment / post markdown editor), I can specifically break on the code that is fiddling (adding a node, changing attributes, subtree modifications) with that part of the UI. It's very similar concept to what Mutation Observer API enables one to do, but for debugging purposes
Conditional Debugging — for example a use case could be – only break if an xhr request contains a specific string.
Hashnode is a friendly and inclusive dev community.
Come jump on the bandwagon!
💬 Ask programming questions without being judged
🧠 Stay in the loop and grow your knowledge
🍕 More than 500K developers share programming wisdom here
❤️ Support the growing dev community!
Depends on the environment I’m using.
First I always try to make a guess. I usually know my code enough to know why it fails. Sometimes, however, it’s not that easy, or I don’t debug my own code.
If I can attach a debugger (like in case of my programs written in C), I just do that immediately. It can show me the stack trace, variable values, and a lot more. If that’s not going to help, nothing will.
If there is no debugger available, I just add some debug log/print statements. That’s much more dirty, especially if reproduction of the bug is time consuming. Still, it’s better than nothing.
And if I can’t find anything, I simply ignore the bug and start working on a different problem. Bugs are careless, and if they see you don’t try to squash them, they will come out in the plain, so whenever you go back squashing them you will have an easy time.
Some great responses so far and all great methods many of us use or have used when needed. However, debugging goes way beyond writing code. When coding, set yourself up for success by doing the proper planning of your architecture BEFORE you start coding. Pseudo code your logic out on paper or in a the editor. Make sure your code is modular, flows logically, and clear enough so when (not if) you have to come back and read it it is easy to follow the flow and understand. If you can do that you are halfway there!
Next make sure you have a clear understanding of testing methodologies and tools for your language and utilize them. The main thing Ruby has taught me over the years is test test test!
Also, learn your debugger! EVERY modern language has one. To most developers the debugger is an after-though. Take the time to learn it inside and out so you can utilize it to it's fullest.
Learn the other tools of your language. Many language have supplemental tools that let you do things like view/monitor memory or call stacks outside the debugger. Learn and use those tools!
Finally, my personal process for debugging is as follows. First I take a hard look at the error stack to get a clue of the flow to that bit of code that blew up. Usually these are logic errors as my tests usually catch the obvious stuff. So I step through the code with the debugger watching all the variables I need to watch and that usually gives me a clue where to look. At that point it's just a matter of getting your hands dirty digging into the code.
Binary search debugging.
- Find logical check points in your program. Example: for input 20, check point 1, should have a variable x value as 30. Check out 2, should have String str value as "high" and so on.
- Run the program and go to the middle of the check points and see if expected values are coming. If yes, proceed to the second half of the check point list, else to the first half.
- Repeat the process until you have just few lines of code left to debug.
PS: Using breakpoints is a good way to debug the code but i personally find it very time consuming and use breakpoints only sometimes.
- Log everything & analyze the results
- Hardcode expected values into functions. Run each function until I find the one which isn't proving expected behavior when given hardcoded values.
- Take out half of the app at a time, look at which half is still working, and know it's the other half which is the problem. Keep doing that until I get to the lines which are causing problems. Obviously this is hard to do with larger apps.