Recently, I gave a talk on Problem Solving where I shared some techniques that I use to solve problems at a high level as a software engineer. In this article, I’m hoping to summarise some of the aspects that I highlighted during my presentation, but feel free to watch the video below:
We use problem solving skills on a daily basis, but luckily for us, once we solve the problem a couple of times, it usually becomes second nature to implement that solution.
For example, imagine you move to a new home in a new town. When you start work again, one of the first problems that you will be presented with is to determine the route to travel to work. In order to solve this problem, you’ll probably use a tool, like Google Maps, and then perhaps you may do some research by asking the people that you know how safe the route outlined is. You may also want to amend the route in order to pass a coffee shop, and finally you’ll try it the first day and then tweak it. After you’ve found a solution to this problem, it becomes second nature to get to work, and you no longer need to give it any thought, thus freeing your mental capacity for other problems.
In the same manner that we’ve solved this problem, we can apply similar techniques to solve software engineering problems.
I’ve often found myself going around in circles because I’ve started typing out a solution without taking the time to go through a process. If I have a daunting task, I am in one of two modes; either I have just not mustered up the courage to start the task or I jump into a solution without taking the time to understand the context and problem. Hence, I started using the following process to help me problem solve. It mostly increases the initial time, but the long term payoffs have been really beneficial.
The first step in the process is to set some focussed time. During this time I make sure I understand what I want to achieve.
Thereafter, I begin to learn more about my problem in order to understand it. I’ve been in so many meetings over my career where someone is talking to a boardroom of people about a solution, but it turns out that nobody actually understood the initial problem in the first place. Therefore, they’re not really contributing towards a practical solution.
In order to ensure that I have clarity on the problem I like to use the following techniques:
- I ask questions. When you’re new to a team, company or industry this can be a bit daunting, but over the years I’ve come to realise that most of the time others have similar questions to the ones I have, and they’ve led to fruitful discussions.
- Once I think that I’ve understood the problem, I like to reiterate my understanding of the problem to someone more knowledgeable. I usually say something to the effect of “Ah I see what you mean, do you mind if I explain it back to you to ensure I have clarity on the problem”. The result is that it shows the other person that you have been listening attentively and trying to understand the problem. It will definitely make you feel vulnerable as it will expose the gaps in your knowledge, but once you’ve had this conversation your knowledge then becomes stronger and more solidified than ever.
- Visualising a problem can also be key. Rather than merely using words to describe, analyze and solve the problem, using images is useful. I once read somewhere that "Images help the brain clarify ideas, identify underlying patterns of logic, and create meaning. A good visual invites the eyes to dart around and engage the entire brain to create a visual logic and make sense of the information to which it is being exposed. The more fully the brain is engaged in the act of analyzing and creating meaning, the richer the outcome of the problem solving activities will be. " “Taking problems to the drawing board or whiteboard” is a common term for that reason :)
- Finally, I spend some time gathering information. This can often be done through talking to people who have solved something similar. They are also called ‘domain experts’. In the context of my example at the start of the article, this would be the equivalent of asking people in the neighborhood about the safety of routes. Gathering information often arms me with knowledge to see the situation more clearly, and look at the problem in a new or different way, as well as identify options that may have not occurred to me previously. I also gather information by browsing around the net for articles and insights on how people have solved similar problems before.
The more clarity that I have understood the problem, the easier the process becomes. Implementing a solution halfway to realise that you didn't actually fully understand the problem, or that you’re solving for the wrong problem can often lead to economic loss or delays in release.
Often, when I finally have a full understanding of the magnanimity of the problem, I tend to go blind panic mode, whereby I feel like the problem can't entirely fit in my head. I feel overwhelmed. This is when I take a deep breath and remember that everything can be broken down into bite-sized pieces.
Big problems are nothing more than a collection of little problems. The faster I can break those big problems down into solvable component problems, the faster I can generate ideas that will resolve my issues. I take my big problem and I ask, “what is this big problem composed of ?”, “what are the smaller issues that seem to be driving the big problem”. I break them down and then continue breaking them down into smaller and smaller issues until I can find a solution to the smallest component. Breaking up the complex problems into smaller ones that are in their simplest form allows one to rationalise about them more easily.
Now that we’ve broken down the problem, we can start planning a solution. When planning a solution,, I use visual tools, like process flow diagrams which provide good ways to determine the flow of a solution and the different paths; or in the case of application flows, a UI sketch plays a part in forming a holistic solution thereby eliminating missing steps.
Once I have all the building blocks in place, I’m ready to move to the implementation stage. When working on big software problems, writing pseudocode is a must for me. I think of pseudocode as a sketch, or a blueprint, that allows me to first focus on the essentials before diving into the specifics.
One important benefit of writing pseudocode before programming is to catch potential mistakes from the get-go. It’s far cheaper to fix mistakes before the development process begins. I tend to write my pseudo code as comments in the appropriate files.
Thereafter, we just use our programming language to implement our solution to the problem. We translate the pseudo code into actual code.
Once the solution is packaged up in code, I am usually caught up in a whirlwind of activities on whatever the next priority is. However, I’ve been trying to get better at reflecting on the problem and the way that I’ve solved it. The few times that I have done this, I’ve found that I was always able to tweak or optimise my solution in some way.
Reflections for me have sometimes taken the form of a blog post, a talk or even a chat with a colleague. It's to help me to put my thoughts in perspective, to help future me when I stumble across a similar problem and also just to share my learnings. And hey, I always feel proud of myself when I reflect upon the process, it builds up my confidence for the next problem I’m about to solve.
All in all the reflection process is the best part of the process to get to because it feels like the calm after the storm and it's time to bathe in the glory of your hard work.
Let’s keep solving problems 😊