Problem Solving 101: First, Understand the Problem

The Null Solution

In my previous article, Collaborative Problem Solving, I talked about the importance of questioning assumptions and reconfirming your understanding of the problem when you hit a brick wall during design or troubleshooting of a system. In fact, one of my favorite strategies for tackling a tough design problem is take the  nihilist approach. In the words of the Zen Master…

Remember that there is no code faster than no code.

Taligent’s Guide to Designing Programs

My corrolary to this is that there is also no code simpler than no code. So when confronted with a complex design challenge or optimization problem, my first question is always “How can we get away without implementing this at all?” Granted, this only works about 20% of the time, but when we can step back and realize that a particularly pernicious problem has just vaporized it is a wonderful thing.

I’m sure that some may be  incredulous about the idea that this ever works at all. I mean, why would anyone have even started working on a problem that didn’t need to be solved? The answer is that only in rare cases does this approach reveal that the entire project was unnecessary, although I have that happen. More often it just reveals that the developer has ventured too far down a dead-end path and is working exclusively on meta-problems that can be eliminated by just backing up a few steps.

For example, this Stack Overflow Question, is a good example of a meta-problem that can be eliminated by taking a step back and reconsidering how to avoid throwing errors instead of how to ignore them as explained in this answer.

Re-evaluating the Problem

What got me started on this two day rant about problem solving approaches was this really insightful idea for solving some of the core issues with implementing an voting system. It was a really great example of how re-examining the core problem led to a solution to a seemingly intractable problem.  Here’s a quick breakdown on the dilemma.

Goals: An voting system must satisfy these criteria (among others)

  1. Voters must be able to anonymously cast their votes.
  2. Voters can cast zero or one ballot, but never more than one.
  3. Voters must not be able to prove who they voted for (to preclude vote buying).
  4. Voters should be able to confirm their vote was properly recorded for each candidate they picked.

Problem: If a voter can confirm who they voted for then they have the means to prove (and receive remuneration) for voting for a particular candidate.

The problem that has stumped many, including myself in analyzing this problem is that requirements (3) and (4) are apparently incompatible.  How can you give the person a way to confirm their vote without being able to prove their vote to another person?

The Solution: The solution that David Bismark came up with was fairly straightforward once he realized that we were looking at requirement (4) incorrectly. Consider this clarification of that requirement.

4. Voters should be able to confirm their vote was properly recorded for each candidate they picked the way they marked it.

Under this revised understanding of the problem, the solution became more straightforward. Essentially his solution involves randomizing the order of the names on the ballot, after voting the ballot is torn in half and the names part is shredded. The bubble-candidate correlation is encrypted on the ballot to prevent tampering, but allow the vote to be tabulated.

The voter then can check (perhaps online) that the bubbles they marked were counted, but no longer see which candidate corresponds with each bubble. Assuming they remember the order of the candidates, they can confirm their voted counted but not prove who they voted for. Voila! Brilliant!

Problem Solving 101: Collaborative Problem Solving

As a software development manager, I am frequently visited by developers who are spinning their wheels on a design problem or running out of ideas while troubleshooting an application.  I’ve developed a reputation as a problem solver because most of these visits end with a eureka moment that clears the logjam for the developer. Although I do like to think that I’m a reasonably good troubleshooter/architect,  I have accrued quite a bit of unearned reputation from these impromptu brainstorming sessions as a problem solver. A more fair assessment of my contribution might be that I am just a really good sounding board.

I’m sure everyone reading this can remember an instance where you went to ask someone a question and simply the act of asking it aloud made you realize the answer. Consider for a moment why this technique works, and why it often works better when the other person has little advance knowledge of  the issue. To bring that other person into the discussion you are forced to rewind your brain back to when you started working on the problem eschewing all of the clutter and complexity that you have added since you’ve been working on it. Then you must revisit each of the steps you have taken justifying each decision and restating each assumption.

So why should revisiting the history of the problem be effective? After all, having the same person answer the same intermediate questions ought to bring that person to the same conclusion, right? If this were true, then the sounding board approach would be a waste of time, which we know is not the case from anecdotal evidence. The reason you arrive at a different answer is that unlike the first time through, you now have the benefit of foresight and are far less likely to take  a path that you know will lead you through the brambles.

The longer you walk down those brambly paths the easier it is to mentally commit to pressing forward. On an intellectual level we understand the sunk cost fallacy, but are still susceptible to it and can form mental blocks that make it discomforting to backtrack for more than one or two forks in the road. This is why we need the guide to force us to rethink the whole journey and each decision along the way.

Tips for Being a Good Sounding Board

I'm Listening.

Face it, there are times when a poster of Justin Bieber would be exactly as productive as a sounding board as you or anyone else on the team. The core problem is sometimes just so obvious that saying it out loud is enough to expose the flaws in the current approach. I’m going to save the advice on how to be more like Justin for a future article and focus now on how you can be a better guide for helping out on the thornier problems.

  1. Establish yourself as a devil’s advocate – The rest of these tips taken in the wrong context can easily put the person defensive. Establish that you are going to ask a bunch of questions, some naive, some pointed, but that your goal is to help them re-verify their assumptions, not to promote an alternate idea or criticize their approach.
  2. Be Kind, Rewind – Even if you know the back-story, ask lots of “why” questions and continue pushing back towards the root problem. Help them fight the tendency to revisit only the last few decisions. “You are de-normalizing the table for performance? Why did you need to do that?”
  3. Don’t let them linger on meta-problems – When a problem seems too big to hold in your brain, it’s tempting to seek respite by focusing on manageable meta-problems. While those problems may need solving, they are distractions from the real issue that is blocking progress. When the person lingers on details or raises meta-problems, keep rewinding.
  4. Ask Probing Questions – Make them talk through each decision and ask stupid questions. Apply extra scrutiny when the developer clearly thinks a decision was easy or obvious. When we think things are obvious, we take mental shortcuts by avoiding thinking things through as thoroughly. Challenge assumptions, this is where problems hide.
  5. Use Reflective Listening – This is a communication technique where you repeat back  a summary of what the other person just said to you to confirm understanding. Another benefit in this situation is that having the person hear their own ideas in another person’s voice/words may make it easier for them to be objective.
  6. Avoid injecting your own ideas – At some point you may have a great idea for a better approach. Keep it to yourself. It will just make them defensive and will undermine their sense of ownership of the problem, and inhibit their ability to understand the solution.
  7. Lead them to the answer – If they simply aren’t making progress and you know a good answer consider  leading them to the answer with a line of questioning that directs them instead of just hand feeding the information to them. They are more likely to take ownership if they feel they reached the conclusion, and people generally retain information more readily if they arrived at it by logic on their own. If you must resort to this, tread lightly with your tone and take extra care not to come off as pedantic.

It may seem strange that my approach advocates being somewhat evasive with information or potential solutions. However, it is given in the context of a manager/mentor acting as a sounding board. In this role, your primary focus should be to create leverage by making things happen through your team. Any veteran manager will tell you that handing out answers routinely to technical problems is only going to make the line to your office longer and make you the bottleneck.  I strongly favor approaches that encourage critical thinking among developers and gives the glory to the developer instead of the esteemed leader. Trust me, it pays off in the long run.