Problem Solving

Seven Steps for Problem Solving

  1. Understand the problem, listen for clues.
  2. Draw out the problem with broad strokes looking at the large and generic cases.
  3. Brute force the solution. Think generally about what could be done to solve the problem.
  4. Optimize the solution.
    • What insights did you glean from the brute force solution?
    • Is the solution space bounded to something?
    • What assumptions are you making and are these real or imaginary?
  5. Walk through the flow of the solution.
  6. Implement the solution
  7. Verify the solution. Walk through it again.
    • Are there nets in place for when things go wrong?
    • Logging, Monitoring, Alerting, General Observability?
    • Are there any edge cases that aren’t accounted for?
    • Does it actually solve the problem?

Phases of Problem Solving

Problem Phase

Problem formulation is the process of finding a problem to solve. After finding a problem, problem analysis is used to understand the problem. If the problem or a similar problem has been seen before then this is the point at which problem recognition occurs and can be used to fast-track a solution to the current problem. Talk to other people about the problem. You can leverage their experiences via their problem recognition if you have never dealt with a problem in the problem space before. Maybe it isn’t really a problem or maybe no one cared enough to fix it or there was more important work to be done and this problem was not urgent and so was deprioritized. Maybe there was some work done that you aren’t aware of and could use as a starting point. This phase is characterized by exploration of the problem space in order to gain understanding.

Solution Phase

Design a solution for the problem using the analysis collect at the end of the problem phase. What is known and what needs to be known? After a few designs for solutions to the problem have been created, weight the pros and cons for each solution and select the design that best suits your needs. Now, this design needs implementation to bring forth the solution to the problem. Write the solution, solve the problem. Talk to other people about the solutions. Maybe they have ideas you don’t.

Optimize Phase

Follow up on the solution. Did it actually solve the problem? Reconsider other solutions, things change and maybe this solution isn’t best suited for extension to adapt to possible future requirements. Is that an acceptable trade off? Clean up the implementation, test use cases, and validate that the solution is acceptable. Talk to other people about how the solution could be improved.

Optimizing with BUD

BUD is an abbreviation for ‘Bottlenecks, Unnecessary work, Duplicated work’ and is used as a rule of thumb for the considerations to make when preforming optimizations on a solution to a problem.

Some questions to ask:

What bottlenecks exist in the solution and how can they be alleviated? What work is being done that is unnecessary? Could we do the work while doing something else? What work is being done multiple times? Could we store past work or extract to some protocol?

Optimizing with Time and Space

For computers, a general consideration of solutions is how much time will the computer take to complete a task and how much memory or data storage will it need to perform it’s task. These are referred to as the time and space complexity of a solution. Since time is relative to the hardware, it is generally better to consider the instructions themselves that are running on the hardware or even more generally the size of the rough estimates of the number of tasks in an algorithm and the space as a rough estimation of memory or storage used in a solution.

When choosing to implement a solution as an algorithm, there are always trade-offs. There are generally trade-offs of space in order to create more efficient solutions. These come in the form of hash tables, memoization, pre-computation, tries, or some other upfront work that is done in order to save time later.

For example: You may choose to sort some some data to make it easier to find.

The work being done here is non-trivial and should be considered as a part of the solution.

The best conceivable runtime or BCR is the theoretical lower bound of a solution space (algorithm) in computing. In number theory this is know as the Big-Omega. This is useful to consider when looking for a solution to a problem because if the limit of the solution space has a lower bound that is higher than the Big-O (upper bound) of some work that would be useful in reducing the upper bound of our solution (such as hashing and storing results for a look up table), then the effects of the work on the time complexity is negligable as the size of data grows.

Optimizing with DIY

DIY or ‘do-it-yourself’ is a technique for developing optimizations by creating large and generic cases and developing intuitive solutions. Then we reverse engineering the intuitive solution to find short circuiting paths or tricks that can be done to make our solution more optimal.