Using Enums to Make Everything Better

Okay, maybe not everything. But definitely some of the things.

When I log in to Netflix, after scrolling past the auto-playing trailer of a Netflix original movie that I don’t want to watch right now (though I probably will eventually — I do recommend Set It Up for your rom-com needs), I’m greeted with never-ending rows of options. I could scroll through what’s popular on Netflix or “Trending Now,” find something new in one of the genres Netflix recommends for me (thank you, I do enjoy “TV Shows Featuring a Strong Female Lead”), or, most likely, continue watching a TV show that I’m currently binging. But how does Netflix know that I’ve already finished the new season of Orange Is The New Black? Or that I’m currently on Season 3, Episode 7 of The Office, even through I’ve watched the entire series at least a dozen times? What information does Netflix store that sorts these shows appropriately, and how embarrassed by this data should I be?

I can imagine how Netflix might store this type of data. Let’s say we have a table that stores all of the TV shows on Netflix. We want to have some way of telling what the status of each TV show for the user is: are they currently watching it, have they finished watching it, or have they never watched any of it? So, on our tv_shows table, along with the title of the show, we could have a status:

This would store a different string as the status for each TV show. To find all of the shows that I have watched, I would look for all of the shows where the status is “watched”:

This is do-able, and I could write methods to return the shows I want, but typing in a string for the status for every single TV show is just asking for typos in your data, and is definitely not DRY, fast, or easy to work with.

So using strings to store this information is probably not the best option. Instead, we could store those three statuses on a separate statuses table:

Then, on our tv_shows table, we could use a foreign key called status_id to identify the status of each show:

Using the information on these two tables, I would be able to appropriately sort the TV shows. I could create a row of shows to “Continue Watching” by selecting all of the shows that have a status_id of 3, and another row called “Watch Again” by selecting those with a status_id of 2. To do this, I would probably want to write class methods for the TvShow model, such as this .watched_shows method:

I could then call TvShow.watched_shows and receive a list of all the shows that I have watched.

I could create similar methods for “shows in progress” and “unwatched shows.” That seems like a lot of work.

In addition, let’s say I wanted to find out the status of Parks and Recreation. I can find the TV Show by its title, then return its status_id:

2? What does that mean? In order to actually tell what the status of Parks and Recreation is, I would then need to find what a status_id of 2 means using the statuses table:

But this returns a status object. If I just want the string “watched,” I have one more step:

And now I finally know that I’ve watched Parks and Rec.

I could make this slightly easier by creating an association between the two classes, where a status has_many TV shows and a show belongs_to a status.

Then, I could find the status of a show by calling status on it to get the status object, then status again to get the string.

This improves it a little, but it all seems very messy and confusing. We still need to write additional methods to sort the data, and it doesn’t really make sense to have an entire table to store the name of the three statuses.

Enums can make this better! They can help our data become more readable and easier to work with. Instead of a TV show having a foreign key of status_id , we can use an enum to store the name of the status directly on the tv_shows table, without using a string or compromising any of the functionality that we need.

An enum can be used when there are only a few possible values for an attribute. In this case, our status can only be “watched,” “not watched,” or “in progress.” We can create an enum for the status of a TV show, which we can store on our tv_shows table, meaning we no longer need the statuses table. The statuses will still be stored as integers, but we can use the actual name of each status to find the shows we are after. Cool, right?

Here’s how this works. First, we create the tv_shows table with columns for a title stored as a string and a status stored as an integer:

Next, we define the possible values for the status enum in the TvShow model:

The order here does matter. Each status is now associated with an integer, starting with 0, which you can see by calling TvShow.statuses:

When we look at our tv_shows table now, we can see that the status is actually stored as an integer.

This set-up gives us all of the functionality that we need, without having to write any new methods!

To find all of the shows that I have watched, we now only need to call TvShow.watched:

Woah! I didn’t have to do anything else, and it returned all of the shows with a status of “watched.” We can also see that the SQL used to retrieve these shows from our database used the integer 1 as the status. So enums are basically acting as both strings and integers at the same time. This means that we can use them in all of the ways that we used the foreign id in our previous set-up, but with simple, readable methods based on the name of each status.

Maybe I want to find out the status of The Office. That’s easy enough. I can find the TV show by its title, then return its status.

Using enums means that I now receive a string as the status, so I can easily see that The Office is in_progress.

But that’s not all! Enums give you a bunch of other built-in methods, without you having to do anything else.

Have I watched Bojack Horseman?

Sure have! Look at that again. I called .watched? on the TvShow object, and it returned true . I didn’t have to write a method anywhere. The enum did it!

What if I start watching Stranger Things? Do I have to remember the integer “in progress” is associated with to change its status? Of course not! I just need to find the show and set its status to “in_progress”. Then, I can save the change to the database, where it will update the integer in the status column.

Even easier, I can use a bang method to change the status. Let’s say I finally finish watching all of the episodes of Black Mirror:

This automatically updates the status for the show in the tv_shows table, as you can see by the UPDATE SQL. Pretty cool!

These methods can of course be used in conjunction with your other favorite methods, too. To find out how many shows I am currently watching, I could call TvShow.in_progress.count:

Looks like I’m currently watching 3 TV shows. Enums definitely seem like the best way to represent this data, providing me with simple, readable methods that I can quickly use to find the information I need. As I continue to learn and use enums, I’m sure I will discover even more benefits and interesting ways to use them.

But for now, back to Netflix.

Shout out to Justin Weiss, whose post about enums helped me tremendously: https://www.justinweiss.com/articles/creating-easy-readable-attributes-with-activerecord-enums/

Software Engineer at Vistaprint // Former Science Teacher // Graduate of Flatiron School DC https://github.com/jensnyder