Admittedly, debugging sometimes makes you nuts. You can’t figure out the problem. Even more annoyingly you wonder why the problem exists when everything looks good on the code side.
Like hunting, you are out to make a catch but you are uncertain where the game is.
Let’s talk about more tips:
- Find a pattern: Some high impact bugs are so tricky that you need to find a pattern to track them down. These kinds of bugs could result in an incident.
Finding a pattern could be checking your logs (mentioned below) around the time the bug was first noticed or checking your monitoring systems. It might be recognizing when you had a surge in response or query times. It might be answering questions like: Was there a release around the time? Did a promo start on the day? Was anything scheduled to run around the time?
- Logging: Sometimes you cannot reproduce a bug because the code behaves inconsistently — a typical heisenbug. Logging cannot be over-emphasized in cases like this. With that, you’re able to visualize the state at runtime. It feels weird to raise a pull (or merge) request that contains only loggers? Well, in the case of a heisenbug that might be your first step towards a fix.
You would not get to do this often but it could come in handy. Remember to remove unnecessary loggers when you’ve fixed the bug.
- Remove exception handlers: You try to follow the flow in your local environment and you don’t seem to be able to replicate the behavior described by the bug reporter. The user sees a blank screen or a spinner that never stops, but you don't.
There might be generic exception handling somewhere. If you handle an exception, all exceptions that inherit from that exception get handled. This is why it is ideal to handle exceptions specifically not generically unless you have a good reason. Temporarily comment out your exception handlers and try again. Voila!
- Test other cases: You fixed the reported bug but there are other ways you think it could affect other customers with different sets of permissions or roles. You should add tests for those cases. Save your team another cycle of bug reporting -> triaging -> fixing -> QA.
- Look out for regression: Does it feel frustrating to fix a bug only to break something else? This is why it is imperative to have specs for your code. If your new code breaks something, there’s a big chance that one of the specs in your test suite would now fail, thanks to continuous integration.
Assuming your newly introduced bug is so discreet that it wasn’t caught by existing specs (unlikely but possible), you should check out any part of the codebase that you suspect might suffer regression.
- Avoid scope creep: While fixing a bug, you might discover that there’s some related tech debt — which is not the cause of the bug. You should resist the temptation to address it while fixing the bug. Remember, the reason why you are working on that bug ticket is because someone filed it. Deliver value to that person before doing some housekeeping. Focus only on the bug. If you feel so strongly about the tech debt, create a ticket for it and discuss prioritization with your team.
I recently published a precursor to this article. You may check it out here.
Debugging can be on a case-by-case basis but there are some general tips and I have touched on a number of them. I hope you found this useful. See you next time! 👋