No human can solve a hard problem. In fact, it may be impossible for any entity to solve a hard problem. However, anyone can solve a simple problem. Even a computer, which is capable of only the most basic forms of logical processing, can solve a simple problem.

Solving any problem is therefore a matter of identifying simple problems that, put together, constitute hard ones. People who are great at problem-solving have mastered the ability to see hard problems as a series of smaller ones, and can solve simple problems rapidly. Here’s my approach to this key problem-solving skill, and I suggest that it might be a good place to start your own.

1. Stop trying to solve the hard problem

Let’s say you run a command from the command-line. It fails.

$: npm run protractor
-bash: webdriver-manager: command not found

Welcome: you have your first hard problem. To solve it, you need to break it down.

One wonderful thing about modern computer programs is their rich error output. If something has failed, computers have been programmed to give you a very good indication of why. You’d be crazy to ignore this indication, and just rush in.

The majority of people, when faced with a problem, start trying things they believe will solve it. In some cases, they’ll get lucky. In most, they won’t. So the novice problem solver will try to resolve their command-line error by tapping away at different commands, in the hope that something will work. This rapidly leads to frustration. The number one complaint I hear from students is this:

“I’ve tried everything and it doesn’t work.”

But push them to explain the problem itself, and I get only the vaguest of indications as to what went wrong.

So this is your first step: express the problem. It may be that you need some time to do this. Later on, I give some advice about thinking systematically (chunk-by-chunk) and systemically (from a contextualised, higher level). You can use this advice to help you express the problem. Let’s do that for our command-line error:

$: npm run protractor
-bash: webdriver-manager: command not found
  • Systematically (word-by-word): My problem is: I asked node package manager (npm) to run the protractor end-to-end testing tool (protractor). The Terminal (bash) told me that it could not find a command called webdriver-manager.
  • Systemically (from a higher level): I tried to run my tests. My problem is that they wouldn’t run.

Here’s your second step: break the systematic statement down into smaller, hypothetical problems. Once you’ve broken them down, you might have to do it again (recursively). So, let’s break the problem down recursively.

Problem-solving loop 1

I asked node package manager to run the protractor end-to-end testing tool. The Terminal told me that it could not find a command called webdriver-manager.

Here are the smaller problems that could be a part of this:

  • Problem: node package manager doesn’t know how to do that.
  • Problem: I don’t actually know how to run protractor.
  • Problem: webdriver-manager cannot be run as a command.
  • Problem: My Terminal is broken.

These smaller problems constitute hypotheses about what might be causing the larger hard problem. Some hypotheses are expressed as hard problems still, so we can’t solve them. Some of them are smaller ones we can test immediately.

Our next step is to eliminate hypotheses. Let’s eliminate ones we can easily look up or test ourselves:

  • Problem: node package manager doesn’t know how to do that.

The error doesn’t indicate anything about either npm or protractor. Something else in the system is being called.

  • Problem: I don’t actually know how to run protractor.

A quick Google verifies that this is the right way to run protractor.

  • Problem: webdriver-manager cannot be run as a command.

When I type webdriver-manager into the Terminal, it gives me the same error. Promising.

  • Problem: My Terminal is broken.

I need to break this problem down.

Great! We had four possible hypotheses and have eliminated two. Now we start the cycle again, with our remaining problems. But which do we choose?

Start solving from the most likely hypothesis. If you can’t figure out which hypotheses is most likely, it’s usually the simplest one.

Much of problem-solving is about eliminating hypotheses. You should eliminate the simplest hypotheses first.

  • Problem: webdriver-manager cannot be run as a command.

This problem needs breaking down, but we can verify that it is a valid hypothesis. It seems quite likely.

  • Problem: My Terminal is broken.

This problem needs breaking down, and we have no real way to verify it. Sure, we have solutions: uninstall, reinstall, try a new Terminal – but these are solutions. We mustn’t try anything until we understand the problem.

The simplest, and most likely hypothesis is this: webdriver-manager cannot be run as a command. It’s no coincidence that this is what our error message told us, and should give us extra confidence that this is the right problem to solve. Let’s assume our Terminal is working, and break this problem down.

Problem-solving Loop 2

  • Systematically (word-by-word): Typing webdriver-manager into the Terminal is something the Terminal does not understand.
  • Systemically (from a higher level): The command webdriver-manager cannot be executed on the command line without throwing an error.

See how our systematic and systemic views of the problem are starting to converge (say the same thing). This is a good indication that we are getting ready to try solving the problem. Let’s break the problem statements above into problems that may be their cause.

Here are the smaller problems that could be a part of this:
– Problem: The system is receiving webdriver-manager wrong (e.g. internal typo or system-wide interpreter problem). – Problem: webdriver-manager is not installed.

Let’s eliminate hypotheses:

  • Problem: The system is receiving webdriver-manager wrong (e.g. internal typo or system-wide interpreter problem).

Possible, but intensive to verify. Reserve for now.

  • Problem: webdriver-manager is not installed.

Easily testable, and a simple statement.

The simplest, most likely hypothesis is this: webdriver-manager is not installed. We can add extra weight to this hypothesis very easily. For example, let’s play with other commands that aren’t installed:

$: randomwords
-bash:  randomwords:  command not found

Hey! That’s the same error we got! OK, this is now a very likely hypothesis. So we have super-defined, very easy problem:

How do I install webdriver-manager ?

Google for ‘install webdriver-manager’, and the first link gives us the answer: on the command-line, execute npm i webdriver-manager. Let’s think systemically, because that doesn’t seem related to our primary context of trying to run npm run protractor. So, we’ll check the other top few links: the second one pertains directly to protractor, which was our systemic context for the first problem. So that looks like a much more helpful link. Let’s try what it suggests:

$: npm install -g protractor

Let’s run npm test again: it works. We solved our problem, systematically. And we only tried one thing.

Wasn’t this a trivial example, though? I don’t believe so.

2. Every first problem is a hard problem

The command-line example above might not seem like a hard problem, if you’ve faced similar problems before. In fact, it might seem like a trivial problem. This is because problems do not exist in some absolute, immutable form.

Large problems are systems of smaller problems, which are themselves systems of smaller ones. All problems are made of smaller ‘problem trees’. At the root of these trees lie very simple logical problems. This is how computer programs can be built to solve hard problems: by using the hundreds of years of technological evolution that has led to nanoscale logic gates to solve basic logic problems, which are subproblems of larger, slightly tougher problems, and so on – until the problem at the ‘top of the tree’ is solved.

It so happens that some unique aspect of our ability to think allows us to remember the ‘shape’ of problem trees in their entirety, and rapidly solve problems that sit atop problem trees which are similarly-‘shaped’ to ones we have already solved. That’s why ‘fixing a command line error’ might seem trivial to an experienced developer: because they’ve already mapped the problem tree, and so can easily spot when one set of solutions is likely to work. If you’re facing a problem for the first time, you don’t have that liberty. You have to map the problem from the beginning. Every first problem is a hard one.

3. Be Systematic

At points in this article I have called for you to be systematic. This approach can be summed up easily:

“When I was studying engineering as an undergraduate, we were taught to break down problems into their component parts. This approach is so deeply entrenched in western culture it seems natural and obvious to anyone brought up or educated in this culture that this is the way to tackle complex problems.”

Excerpt From: The Open University. “Managing complexity: a systems approach – introduction.” iBooks.

This entire article demonstrates a systematic approach to problem-solving. But don’t ignore the value of systemic thinking: it is possible to get so lost in the woods of systematic thinking that you cannot see the trees.

4. Be Systemic

At some points in this article I have called for you to think systemically. This means to think about your approach in the context of what you are trying to achieve.

Why is systemic thinking important? Because novice problem-solvers fall into a secondary trap: forgetting the problem they were trying to solve. If we had taken a few steps from our problem-solving loops above, we could have wound up reading the Angular docs for Protractor, or trying to set up a sample side project to play with webdriver-manager. Doing these things is fine: so long as you remember the first problem you are trying to solve. So, maintaining a systemic approach to problem solving, while taking systematic steps, can stop you from straying too far from the path.

There’s a second value to systemic problem-solving: the closer your systemic expression of the problem to your systematic expression of the problem, the more likely you are to be at the right point to try solving the problem. If you have broken the problem down such that your context and your immediate problem are virutally the same thing, you have a very clearly-defined problem and can stop breaking it down further.

5. Celebrate

Once you’ve solved a problem, take a break. You got something working – recognise that. Programming is absolutely nothing but solving a never-ending series of problems. That might sound unpleasant: sometimes it is. But there’s nothing like solving a problem: it feels great.

So you’ve got to let yourself feel that great feeling, revel in it, high-five teammates, take five to decompress from that problem-solving mindset, and ready yourself for the next problem. Trust me: these things have a huge impact on your ongoing motivation. Perhaps most importantly, they keep some distance between you and the problems you’ll face.

Humans are inclined to over-empathise with the things they create: even when those things are problems. Remember that you are not your problems or your ability to solve them, and that problem-solving is simply a tool in your arsenal.

By Sam Morgan from Makers Academy

lj-makers-academy-footer


Read Next:
Thinking like an app designer with Javier Cuello
How to write a great application letter