Note: This focuses on my expertise within the software engineering realm, but the concepts apply equally to problems in any industry. If you happen to be in a different field, this introduction shows you how well your thought process will work in software.
Great problem solvers are made, not born. Like diamonds - they are formed over many years - full of pressure and stress. Whether they consciously realize it or not, they are refining a process for efficiently solving problems. I will explain what that process looks like and how to create and optimize your own.
the problem-solving process
Understand the problem and how to know when it’s solved
Determine all possible ways to solve the problem
Pick a solution and test if it solves the problem
These steps are deceptively concise. Attempting to master a single one of these - much less all three - can span an entire career. Each one builds on the previous, and yet many people skip the first two. Even when attempting to understand the problem, few examine knowing when to consider it solved. Solving problems purely by trial and error is even less fun than it sounds, but is a frequently used approach.
There are no shortcuts. Without the wisdom that comes from solving many problems in different ways, one won’t know how to streamline the process and still achieve excellent outcomes. These skills come naturally to some and are difficult for others. Be very wary of those selling attempts to skip these critical years of experience.
the myth of the 10x developer
A popular (but dangerous) legend tells of genius software engineers who are ten times more productive than the average engineer. Where does this order of magnitude improvement supposedly originate? There are not enough hours in a week to work 400 of them. Even the quickest fingers in the west can only move about thrice faster than the average typist. This trend extends to all other aspects of development - it’s not realistic to get there merely by putting in decuple the effort.
The only reasonable way to achieve a tenfold improvement in work output is through massive efficiency improvements. The claim would have to be that the average engineer is wasting 90% of their time. I’m going to be charitable and assume this isn’t willful laziness on their part but instead, through their wasted efforts. Cynical voices have claimed these efficiency gains are realized by not attending meetings or socializing with their coworkers. Still, I’m skeptical this accounts for any more than half of the average developer’s time.
solving the problem
It’s time to get to the heart of this content by explaining the process in greater detail and giving advice on how to improve each step. Let’s get to work.
understand the problem
Solving the wrong problem isn’t very helpful, and in fact, can be harmful. Effort wasted solving the wrong problems make up the most significant single source of inefficiency in the process, but it is the most difficult to eliminate. There’s no substitute for learning from mistakes when it comes to improving in this area. Having past mistakes (a.k.a. experience) can help facilitate this. The closer your past mistakes were to the problem at hand, the more likely they are to inform your decision. If you lack those experiences, the best option is to identify and acquire them through small iterative efforts.
know when the problem is solved
Always have an exit strategy. Few people identify success criteria before beginning a task, let alone failure criteria. Smart engineers consider how to test their work before writing a single line of code. Test-driven developers take this several steps further by writing unit tests first and ensuring they fail as expected before making them pass. TDD serves dual purposes: to verify the test is written correctly and to ensure that the software doesn’t already handle the use case we expect is missing.
determine possible ways to solve the problem
The brainstorming portion of the process is ripe for efficiency improvements. Ideas are cheap, and good problem-solvers have no problems throwing away any that don’t serve their purpose. Like a master chess player, the most productive ones will be able to think through each approach’s eventual outcome independently of exerting the effort involved. The ability to quickly analyze and rule out possible solutions based on their downstream impact is the heart and soul of software design.
pick a solution
Oracles have been in short supply since Pythia. Choosing among appropriate solutions is mostly a matter of predicting the future. Witnessing how other software requirements have changed over time can help provide a reference for how a new system might evolve. Because much of the results from this step are sheer luck, it’s best to focus on optimizing the previous steps by ruling out as many solutions as possible before picking one of them.
test if the solution solves the problem
Once a path has been chosen, it’s crucial to see it through. This part of the process is where the majority of the learning occurs. Gather data to assess the effectiveness of solutions and quickly pivot if necessary. The oft-repeated mantra here is “fail fast.” If you’re not in an environment where you feel comfortable in failure, read my previous words on that subject.
No one is perfect at this. You can continue improving your problem-solving skills throughout your entire life, a very worthy pursuit. It’s essential to trust the process while following it and wait to draw any conclusions or make modifications until one has measurable results from which to learn. For bonus meta-credit, you can even use the process to improve itself.