“How the in the name can this piece of code do what it is supposed to do?! What if I change this line, that must be related to this $#!&^* bug I’m solving…” We all have been in that situation. You are just changing, no, fiddling with the details of several obscure lines of code, that magically seem to work. Just to find that segmentation fault that occurs when you press enter twice, put your mouse in the upper left corner of the screen, scratch your nose, get coffee and then try to open a new file. It happens only in those rare circumstances. You can’t make sense of a thing that is happening, you can do no more than moving around code. Adding printf or std::cout statements until you find that one magic change. You can’t even remember what you at all did, but suddenly, after an arbitrary number of mindless changes the crash disappeared. Wow! You must have fixed it! Phew. Quickly check in those changes, close the issue, get another cup of coffee, and do some real work.
It started out quite right. You were debugging to find that crash occurring only in rare circumstances. You are able to reproduce it, and (although sick of all the coffee) you managed to locate those lines of code responsible for the crash.
As obscure as these lines are, you can’t even understand they would work in normal circumstances. There you are, needing a fix for one of the least common situations. “Maybe it is in there,” you think. You change that line. No result. “Let’s try this.” No result. “Hmmm, what will happen if I move…” More crashes. After an hour or so, you think you comprehend at least some of it, because some changes give the results you’d expect.
After a few more hours (and a lot more coffee), you try yet another change, and whew, finally, the crash is gone. That last change didn’t even affect the normal circumstances. “Huh? How could that last change make the crash disappear?”.
The difference is in the last question you asked yourself. Using trial and error to find a solution for an issue in a system is not a bad thing at all, as long as you find out why and how the solution works, before committing to it. Otherwise, you will leave behind yet a worse mess than the developer(s) before you. Sad to say, I have encountered countless examples.
Every so often, you simply need the solution first, to decipher a fragment of code, and to figure out every inch of what is going wrong. And to get to that, trial and error is a proven method. The moment you know the trick that solves your problem, nine times out of ten it is relatively easy to continue experimenting to truly find out why the trick works. Perhaps you’ll even unravel how the code functioned in the first place, being able to replace those lines with an elegant and consistent solution.
After all, programming isn’t magic.