What started off as a silly idea is really going off the rails already, but I figured I might as well keep pushing. Today, we’ll be breaking down the first step of opening a jar: get a jar. Wish me luck!
Table of Contents
While the series is still young, I have a feeling that these regular recaps are going to become increasingly important as we descend down the rabbit hole. With that said, in the previous article, we defined a mundane task: how to open a jar. This task was inspired by that old SpongeBob meme where Patrick learns how to open a jar.
At any rate, in the process of naming the task, we also began defining the first two subtasks as explained by SpongeBob: get a jar and take off the lid:
The plan for this article is take that first subtask, “get a jar,” and try to break it down into subtasks. This is a very important step because things can get complicated quickly. As a result, we’ll be spending a lot of time discussing possible options.
What Does It Mean to “Get a Jar”?
Before we try to create subtasks, we need to think about possible things that could happen as we “get a jar.” In other words, the first thing we should do is some brainstorming. To do that, I’ll pose a question: what would you do if I asked you to get a jar?
To help you answer that question, I’ve brainstormed a few scenarios myself. Let’s take a look:
- You have a jar, and it’s close by. As a result, you reach out and pick it up. Mission accomplished.
- You have a jar, and it’s not close by. As a result, you have to go find the jar. Once you find it, you reach out and pick it up. Mission accomplished.
- You don’t already have a jar. You need to obtain one somehow (i.e., ask someone for it, buy one, make one, etc.). Once you have it, you pick it up. Mission accomplished.
There are probably dozens of scenarios, but these seemed like the three main ways things might play out. Interestingly, if you have some programming knowledge, you can probably already see how these different scenarios could be converted into code:
if has_jar: if not is_close_by: approach() else: find() pickup()
Now, this is just me toying around. Ideally, we’d want to find some way to generalize the subtasks. That way, we could provide the list of steps without any sort of conditions or loops. Unfortunately, this isn’t always possible. After all, the real world is incredibly messy.
One way to simplify things a bit is to make some assumptions. As a result, in every article in this series, we’ll make some assumptions about the task we’re trying to complete. Then later, if necessary, we can add complexity back into our algorithm. Until then, however, we’ll be following the wise words of Knuth:
Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.Pulled from Premature Optimization
Here, Knuth is talking about program efficiency. That said, I like to imagine that premature optimization includes ideas like “YAGNI” (i.e., You aren’t gonna need it) which states that you shouldn’t account for scenarios until absolutely necessary. In other words, it’s an anxiety driven behavior that focuses on how the algorithm might scale before it’s ever had a chance to work at all.
As a result, here are the following assumptions we will make for our context:
- We have a jar.
- The jar is nearby.
- We are able to approach it.
- We are able to pick the jar up.
- I am the one picking up the jar.
In future iterations of this article, we’ll need to make some additional assumptions. For now, however, these will do!
Writing the Steps
I spent a lot of time thinking about how I would define the steps for this particular problem. Initially, I wanted something generic that would account for many different scenarios—naturally, falling into the YAGNI trap. However, now that we’ve defined some basic assumptions, I think the following steps will solve our problem:
- Approach the jar
- Pick up the jar
Despite simplifying this scenario considerably, I still don’t love the idea of using language like “pick up” and “approach” for accessibility reasons. That said, the last bullet in the list of assumptions was meant to account for this. If you have different needs, feel free to modify the steps above as needed.
With all that said, I really like this pair of steps. I can definitely see how we can break down the concept of approaching the jar in future articles. Likewise, picking up the jar seems like a task that could be made up of subtasks.
In the future, we’ll probably weave in a little design by contract—though that’s implied in our list of assumptions. After all, the steps aren’t exactly atomic. They inherit state from the previous step, so we’ll need to define that state as we go forward. For example, in order for us to pick up the jar, we need to know what state the jar is in after we approach it. That said, we’ll leave that for later when the steps are a bit less generic.
Otherwise, here’s our updated tree:
As this tree grows, we’ll need to think about ways to clean up it’s appearance. That said, I think this is a great start!
Expanding Our Breadth-First Search
As promised, the approach to this article series will be to develop this tree through breadth-first traversal. As a result, the next node we’ll be expanding is the “take off the lid” step. I’m fairly excited to break that step down as there will need to be a lot of assumptions made around the type of jar we’re working with.
With that said, that’s all I have for today. If you like this article and want to know when the next one is coming, feel free to check out my list of ways to grow the site. There, you’ll find links to the newsletter as well as Patreon and Discord. Otherwise, take care!
Recently, I was giving a lecture about Java's "common" methods (i.e., all of the methods of Object), and I had epiphany about how Java only has toString() while Python has str() and repr(). So, it...
Magic numbers are numerical constants that have no clear meaning in the code and therefore make code harder to read. Anything that makes code harder to read is something we can use to obfuscate our...