Coding Rule #1: Always Have a Plan
The more that I code, the more I recognize the parallels between writing code and composing essays. Today I was reminded of the importance of planning and mapping out the code before writing it, just as it is essential to plan out essay ideas and components before actual composition.
For instance, when working with class relationships in Ruby, I collaborated with a small group to code a scenario with three different classes. I won’t reproduce the exact same problem here, but I will present a similar one.
Building a Recipe App with Ruby Classes
Let’s say I was building an app for finding recipes. I start out with three different classes: Baker, Recipe, and Ingredient. They have the following relationships:
- A Baker has many Recipes
- A Recipe belongs to a Baker
- A Recipe has many Ingredients
- An Ingredient can be used in many Recipes
In my notebook, I scrawled a quick web of the different relationships (one-to-many, many-to-many) and quickly dove into the problem with my group members. We began smoothly by completing basic aspects of a class (initializing a name and creating arrays that would contain all instances of that class). However, we soon found that as we started writing other methods, we were already knee-deep in a murky conundrum.
The issue was that we wanted to not only find the ingredients included in a recipe (find_all_ingredients), but also the recipes that contained a particular ingredient (find_all_recipes).
The problem with these two methods (find_all_ingredients and find_all_recipes) is that there are multiple sources of truth. If someone created a new instance of Recipe, then the recipe and corresponding ingredient would be stored in Recipe.all. Another person could create an instance of the Ingredient class and store that same recipe and ingredient in that particular Ingredient class instance. Therefore, that data would exist in two different places in memory.
At this point in coding, I realized that we would have to go back to the drawing board.
Diagramming the Relationships between Classes
I decided to turn my initial — and rather haphazard — planning into a more organized diagram of the class relationships:
Since Recipe had many Ingredients, and Ingredients had many Recipes in a many-to-many relationship, I discovered that I had to create another class, Recipe_Ingredient, in which I could store all pairs of recipes and ingredients. In this way, we could have one place to store the relationship between ingredients and recipes.
The Recipe_Ingredient class would look like this:
By creating this new class, I can now iterate through the Recipe_Ingredient class if I want to find the ingredients associated with a recipe or recipes that contain a certain ingredient.
Now, in the Recipe class, the #find_all_ingredients method would look like the following:
I iterate through all of the Recipe_Ingredient pairs and select those whose recipes are the same as that particular recipe instance. Then I map over the array of those pairs and create a new array of all ingredients associated with that recipe. By storing my data in the Recipe_Ingredient class, I am able to access my data in one location only.
Moral of the Story: Good planning can prevent missteps during the coding process.
As an English major and avid reader, I love the process of “creative inspiration.” However, what I learned throughout this particular coding problem is that there will be no bursts of inspired coding without equally inspired and thoughtful planning. Coding requires plenty of diagramming and discussion — whether it’s with oneself or others — before writing. And if problems emerge along the way, it is always helpful to return to the drawing board.