Inversion thinking in Software Engineering

Photo by Sven Fischer on Unsplash

Let’s try to understand the Inversion thinking principle by starting with this common situation we would have encountered in our student life. Please try answering the below question without searching on the internet or scrolling after option d.

Which of the following animals has 3 eyes?

a) Cat

b) Dog

c) Tuatara

d) Elephant

Did you choose option c? Have you ever seen or heard about Tuatara before this? Probably, not. As we know cats, dogs, and elephants have 2 eyes, we are likely to choose Tuatara. This is an example of “Inversion Thinking” — we are thinking in reverse, we eliminated the wrong answers to find the right answer.

Many of us may have applied this mental model before we heard about this nomenclature. Let’s see if Inversion thinking is relevant beyond answering a simple multiple-choice question. Most importantly, how can we apply this in software engineering?

Inversion thinking has proven to be a great mental model over time. People have used this to solve complex problems that can’t be solved by forward-thinking alone. Some of the famous examples are

  • In the 1820s, German mathematician Carl Gustav Jacobi was reputed for solving hard mathematical problems using his principle of ‘man muss immer umkehren’ (‘invert, always invert’ or ‘one must always turn back’ ).
  • In World War II, Charlie Munger(now a billionaire investor & businessman) was working as a meteorologist. His job was to clear the pilots for take-off and get them back safely in difficult weather conditions. Charlie inverted the problem: what if he wanted to kill many pilots — he could get them into icy conditions or put them in situations where they run out of fuel and fall into the ocean. He devised safer maps by avoiding pilots getting into all the situations that would get them killed.

“It is remarkable how much long-term advantage people like us have gotten by trying to be consistently not stupid, instead of trying to be very intelligent.”
— Charlie Munger

Let’s see how this can be applied in software engineering. Also, how some of the well-known practices embody this mental model implicitly.

Imagine you have written a code for a complex problem and have come across a case where it doesn’t work as expected. Our natural instinct is to start with the question “Why is it not working?” This does help in some issues, but few tricky ones escape this way of thinking.

Have you had an experience where you are describing a nagging defect to a colleague and you find the solution before they say anything? You have the same tools and knowledge as before, what changed here?

As per my observation, when we are explaining the problem to another person, we focus on what is expected and why it should have worked. This change in thinking helps us discover the mistakes we would have overlooked earlier.

This taught me an important lesson in the early parts of my career — sometimes, we need to invert the question from “Why is it not working?” to “Why should it work?”

I believe this is one of the reasons why Pair programming helps in solving hard problems well. Even if we don’t pair on each line of code, getting a second pair of eyes on the problem helps us reach a solution faster. If you don’t have a person next to you, start explaining the problem to your pen or an imaginary colleague.

The below tweet by Kent Beck(pioneer of pair programming) hints at how pair programming embodies inversion thinking implicitly.

Bigger systems need automated tests to find issues faster and facilitate collaboration across the engineers. As these tests are also programs similar to the code it is testing, how do you know that the test code is correct and it can catch the intended issue?

Test-Driven Development (TDD) addresses the above problem by inverting the sequence of writing source code and test code. In TDD, you start with writing the test first and make sure it fails with the correct reason. Then, you write the logic in the source code to pass these tests (without altering the test’s expectations). This is a tough skill to master but confidence in the tests will be a lot higher with practice.

I think TDD is a debatable example for inversion thinking yet it isn’t too disconnected from it.

Planning large projects involve a lot of time and energy spent on thinking about “What do we need to do for the project to succeed?” — from the start of the project to the expected launch date.

One of the exercises that embody “Inversion Thinking” for project planning is Futurespective. In this exercise, we assume to be in the future date(time travel ⌛) and list down the reasons that led to the failure of the project(Risks). Identifying risks, and countermeasures helps in avoiding those mistakes. The takeaway here is not only to think from now to the future but also think backward in time and address the potential issues.

Note: Futurespective can be used to to find potential reasons for success and we make sure to act on it as well.

Inversion thinking is not about choosing one direction of thinking over the other, it is about thinking in both directions to see the bigger picture and take holistic measures.

I came to learn about Inversion Thinking after reading a hacker news post a year ago and related it to some of my learnings from the past. This post is a reflection of those thoughts and observations so far.

Note: Dependency Inversion principle might sound like it is related to Inversion Thinking. I think they are not related.

Human being running on curiosity