Magic Functions and Problem Solving

Running Into Problems

When programming to solve a problem for the first time, odds are you won’t have a 100% correct algorithm your first try. In fact, if you’re anything like me you probably won’t even have a 100% understanding of the problem by the time you start coding. Often, we start to program far before we have a deep understanding of the issue and the context surrounding the issue. Writing code is cheap and just feels so productive.

Taking this approach makes your programs prone to bugs (unfortunately). And so the common problem solving techniques usually involve the following:

  • Break down the problem into smaller steps
  • Explain the problem out loud (rubber duck debugging)
  • Take a walk and let your brain process the problem in the background
  • Work on something else and come back to it after sleeping

These approaches work phenomenally, and I recommend employing them frequently as you go about solving problems.

Magic Functions

Adding to the list of previous technique are “magic functions.”

There are two fundamental things that we should understand when getting to a solution: the inputs and outputs. If we don’t know what data we’re getting and what data we need to spit out, then we have no hope of solving the problem.

Often, the issue isn’t around understanding what we’re receiving and what’s expected as an output. In fact, LeetCode and HackerRank type problems generally provide sample output (and if you’re working in industry, you’ll be given output specs by clients/business that’ll hopefully define what’s desired). The issue, then, is usually around the implementation and the exact method you’ll need to use to get the desired output.

Queue magic functions…

Magic functions are placeholders for the algorithms when you can’t quite nail down the logic and implementation. And they’re a great tool to use when you’re stuck on a specific portion of the code, but have an idea of what to do afterwards.

Project Example

For a systems programming class I’m currently taking, we needed to write a program that would scale down an image file with the requirements of: reading from stdin, using pointer arithmetic to do the scaling, and then writing to stdout.1 If all of this seems confusing – good, it is. And so before I even started implementing the code I took a day to think about the steps I needed to take. I came up with this:

int main() {
    loadfile();
    scaleimg();
    writefile();
}

And this is a great start! Now that we have a framework for the program we can focus on implementing the steps we already have an idea for without having to worry about the other functions. If we run into more bugs, we know precisely where we’re having trouble and what questions we might want to ask to resolve them.

Interview Example

Magic functions are also wonderful in a whiteboard interview situation (especially because we’re on a strict time limit). Say that you run into a rut when implementing a solution to a problem. Use a magic function and describe the input and output of that function – and then implement the rest of the solution. It shows that you know exactly where you’re having difficulties and that you can work around them until you get help from peers and mentors.

def solution:
    # do some stuff

    # oh no! i'm stuck!
    magic_func(input)
    
    # after the magic i expect X as an output

    # rest of the solution

Summary

  • Lots of techniques you can use as you’re solving difficult problems (analyze and break down the problem, talk it out, take a break, sleep on it)
  • Add magic functions to your list of techniques
    • Useful for larger projects where you can modularize your code and work on portions of the solution independently
    • Useful in whiteboard/time sensitive situations where you can work around the issue until you get help from someone else

  1. Don’t worry if you have no idea what any of this means. For quite a while, I didn’t either.