There are many types of bugs in the world. I’m talking about the programming kind, by the way.
You have the super simple ones that don’t even make it by the compiler. Those are easy to fix.
You have the ones that stem from little mistakes. You know, the off-by-one errors or missing catching an exception. Those are easy enough to fix, though they make it to production sometimes so it’s a harder issue.
Then you have the bugs that stem from trying to fit a round peg into a square hole. You come up with an algorithm and start to implement it. Then, as you’re testing, you find an issue. You figure out a fix by perhaps implementing some hack, maybe a global variable or something. Then you find another flaw. And you make another hack.
Then they start to interact.
You can start to chase correct by piling hack atop hack.
This is so dangerous. You not only have quickly growing complexity, you also have increasingly more interactions between the hacks — some scenarios work, but others fail, and it’s not clear why. You’ve reached a point where you are no longer debugging, but rather writing bugs.
The correct action is to take a step back and look how you’re trying to solve the problem. Debug your thought process, not the code. Instead of adding complexity, most often it’s looking for a better abstraction of the problem.
Once you get the correct abstraction you find yourself in a far better place. You’ve gotten rid of unintended interactions and you have a simpler and less interdependent system.
And those are a lot easier to show they are correct.