Skip to content

Enums aren’t evil. Conditional statements everywhere are

Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.

Learn more about Software Architecture & Design.
Join thousands of developers getting weekly updates to increase your understanding of software architecture and design concepts.


Are you seeing the same conditional statements (if/switch) against enums littered everywhere? There are different ways of handling that, but a lot of it comes down to your context. Conditionals around type checking, extension methods, Inheritance, and Polymorphism are all options.

YouTube

Check out my YouTube channel, where I post all kinds of content accompanying my posts, including this video showing everything in this post.

Enums

The original examples of this problem come from a video by Nick Cosentino, which he tagged me in. The gist is that there are a lot of conditional, in this case “if statements,” throughout a codebase and enums being passed around deeper through the call stack.

In the example below, the OfferrngType of a Product is used to determine whether it should have a downloadable URL and filename. However, since only templates, ebooks, and offline courses support this, other types, such as books or courses, will return null.

As mentioned, The OfferingType is passed along as an argument to other methods, which ultimately end up doing the exact same conditional check.

A solution in Nick’s video is not to have the conditionals but instead query a database for that information. If there are no records, then return null.

Runtime

The solution from Nick’s video above is moving the conditional from in-code at design time (programming) to runtime. The potential problem with this is unnecessary database calls (I/O). It depends on our context. If we have 1000s of products, but only a handful have a download URL, then we’re making many useless DB calls.

Types, Inheritance, Polymorphism, Extensions

Another option is using different types to represent a specific product type rather than an enum. So we have an abstract Product class and other classes that inherit it, such as Template, Ebook, and OfflineCourse.

The problem I have with this is that it’s really not much different from enums, as we still have to do a conditional check, just not on the enum but rather on type checking.

We can take this a bit further and instead define a base class that has a few virtual methods that we can override. More importantly, we can use an option type as the return value or none.

We’ve removed the conditionals and are handling the Option type when there is a value with calling Match(). While not the same, at all, you could make the return type a nullable string and deal with a nullable.

We can keep taking this further and make an abstract class of a product as we did before, but we don’t need to override anything; instead, we explicitly have a type that implements using a downloadable product.

We aren’t handling a base type; we’re explicitly handling a DownloadableProduct. We would have other handlers, or any other code would have different code paths for different offerings.

Or we can go back with our initial conditionals but instead just use an extension method on our enum to group all of the valid offering types to simply our conditional checks.

Conditional Statements

You don’t have to have the same repetitive conditions statements against enums. There are many different ways of dealing with them as an alternative. Which solution works best is dependent on your situation. Could you delegate it to runtime and are fine with the additional I/O DB call? Maybe that will work. Maybe that will be terrible system performance.

Maybe you’d rather define explicit types and handle them on their own path rather than try to deal with them all together. If you were to make a Venn diagram, how similar are the two concepts, an offering in this example? Sometimes what we think are the same thing aren’t at all and should be explicitly modeled as unique things based on what the capabilities are around them.

Join CodeOpinon!
Developer-level members of my Patreon or YouTube channel get access to a private Discord server to chat with other developers about Software Architecture and Design and access to source code for any working demo application I post on my blog or YouTube. Check out my Patreon or YouTube Membership for more info.

Leave a Reply

Your email address will not be published. Required fields are marked *