Some people, when confronted with a problem, think, “I know, I’ll use regular expressions.” Now they have two problems.
Every once in a while, a really tough bug surfaces. After hours of troubleshooting, you still haven’t managed to pin down the cause. These bugs tend to have something in common: they’re actually two problems (or more), not just one.
Having two problems at once breaks the traditional form of the scientific method. Even if you find one of the problems, you might change something related to it, notice the whole bug isn’t gone, conclude that wasn’t the issue and put it back. Or worse, as in Zawinski’s quip, you might even cause one or more additional problems while trying to fix the first set of problems. That means it’s easy to go around in circles for hours working on the same aspects of the problem over and over again without realizing that if you put all the pieces you’ve tried together, you’d have it solved.
Effectively solving two problems at once requires some specific techniques. First of all, just as the hardest part of debugging is finding the bug, simply being able to recognize that you’re dealing with multiple problems can be the hardest part. A Minimal Working Example is indispensable here. Using an MWE makes it far more likely you can separate the problems from each other. If you solve the first problem in a minimal test case, then return to the full system and find it still doesn’t work, it’s much easier to conclude there’s a second problem to pin down (especially if you end up with a different error message – a well-loved sign of progress in IT!). Solving two problems in sequence isn’t hard – it’s solving them at the same time that’s hard.
To come back to the Zawinski quote, attempts to solve a problem can easily create new problems, or mask the source of a problem, even if there was only one problem before. An infuriating class of bugs, often called Heisenbugs after their tendency to change their behavior when studied, disappear as soon as someone starts trying to debug them. Heisenbugs occur when inserting test code or starting the program in debug mode happens to touch the buggy portions of the code and indirectly fix the bug. There’s not often much to be done to avoid true Heisenbugs, but pseudo-Heisenbugs can occur when a programmer semi-randomly changes code in the hopes that it might fix the problem. So, don’t do that – in software or elsewhere! If you don’t know why you’re making a change, figure that out first.
A final important skill is knowing when you shouldn’t change something back after discovering it’s not the single source of the problem. The scientific method would typically have you make one change, test it, and then revert the change unless it was the cause of the bug. But when we have two problems, we’ll have to make at least two changes together before the bug gets resolved!
Software version-control tools help immensely with this kind of experimentation: they allow you to make as many distinct changes as you want and manipulate them to test different combinations of the changes, without touching the main version of the software and while retaining the ability to easily throw out any of the changes. (These version-control tools work for any data that can be represented as text files, not just software code; for instance, I use one to maintain this blog. If you work a lot with web pages, documentation, or other prose, you should seriously consider learning one. I recommend Git.) But tools only go so far: ultimately, the technique comes down to trial and error and experience. The more you do it, though, the better your intuition gets and the more likely you are to recognize a path you should start along and the steps you might need to take in addition to your first experiment.
One of the clearest examples of the multiple-problem predicament outside of software comes in medicine. Many confusing health problems that no doctor can seem to pin down turn out to be multiple problems – or we have to believe they are in the end, because we never can quite figure out a single cause. This situation has even been codified in a pithy maxim called “Hiccum’s Dictum,” which says, “Patients can have as many diseases as they damn well please.”
Gathering information can help identify multiple existing problems and avoid creating new problems. When you have more information about a problem you’re facing, you may be able to study all the information together and spot multiple problems at once. In real life this often takes the form of writing down everything you know about a problem. What do you know? What’s working? What isn’t working? Why are you unhappy with your present situation? What are the advantages and disadvantages of taking some action you’re considering? When you get around to writing all this down, you’ll often find you think of entirely new facets. Further, once it’s all written down, you can examine everything all together, without being limited by your memory, and you can share your notes with someone else if you think they might be able to help.
Tip: When I have a large number of loosely connected facts or ideas and I’m not sure how they fit together or how I should categorize them, I like to write each of them on a three-by-five card, then clear off my desk and sit down with them. As I think about the ideas and move the cards around, I find categories and organizing principles and outright answers to difficult problems often seemingly magically appear on the tabletop. If you’ve ever mixed your tiles around on your rack in Scrabble and suddenly spotted a satisfying move that was invisible before, you know the feeling.
Most of us are so used to trying to pin down one cause at a time that we find it challenging to zoom out and see multiple issues. For instance, we like to react to accidents or embarrassing situations by blaming someone or something (usually someone other than ourselves!) but in reality there’s usually a collection of meaningful causes, and we’ll get a lot further towards preventing recurrences if we consider all of them. It’s this tunnel vision that has such ugly effects in software as well: it always seems to take longer to realize there must be two problems than it should, at which point everyone involved is already tired and frustrated. So perhaps the best way we can help ourselves out is to bear in mind that many problems, even seemingly simple ones like software bugs, have multiple causes. This doesn’t invalidate the scientific method, but it means we need to be ready to take a broader approach when the scientific method in its base form doesn’t seem to be working. Ultimately, more so in real life than in software, we’re unlikely to solve any of our problems with a single action; the sooner we can start thinking of problems as a collection of related, smaller problems, the sooner we can get to improving them.