The idea of having small objects that are each responsible for just one thing has grown on me gradually. In this blog I want to write about one such object that I introduced into my current application recently.
The object was a Policy Object. Here’s a simple definition —
Policy Objects encapsulate and express a single business rule .
In our applications we might have different business rules coded mostly as if-else or switch statements. These rules represent concepts in your domain like whether “a customer is eligible for a discount” or whether “an email is supposed to be sent or not” or even whether “a player should be awarded a point”. To illustrate this let me tell you how I used this in our application.
When viewers register for an event’s webcast on our application, we’ll need to send them a confirmation email provided the following conditions are met. They are —
- Viewer must be accessing the event at-least 6 hours before the start time.
- Viewer must not have already received this email.
- Viewer must have an email address.
- Confirmation email must have been enabled for the event.
In order to represent this policy, I’ve introduced the following class into our codebase.
Extracted Policy Object
As you can see, its a very simple and plain Ruby object. Instances of this class are initialized using a viewer object. And it has a single method in its public API — ‘send_confirmation?’ which returns a boolean value representing the result of the policy evaluation.
One might wonder how Policy objects differ from Service Objects — This is a difficult question for to answer as I have seen people treat Policy Objects as one type of Service Objects. But, one general distinction is that the behavior of these Policy Objects should be of Query type. Which means that you can ask it for something but never make it do some actions like data manipulation for instance. (those are of type Command). Policy Objects in essence only respond with boolean values and must not have any side-effects.
I am sure after looking at the above two pieces of code some of you might be wondering if a 34 line class is worth the effort. But that’s the kind of short time price one can pay to reap long term benefits. To elaborate more, lets go through some of the nice things about the above code.
Users of the ViewerAuthenticationConfirmationPolicy class need not worry about the business rules behind this policy and how the rules are evaluated with code.
We are using this policy currently in two places in our code and we do not want to burden those two classes with the responsibility of enforcing these business rules when doing their respective and vastly different jobs.
Also if, in future, the policy changes we would not want to make changes to a classes that have nothing to do with checking these conditions.
I’m sure when you read the code inside ‘send_confirmation?’ (line#9), you noticed how nicely it reads. It’s almost like a proper sentence in English which is what we want our Ruby code to sound like.
This is possible because of the freedom we get to write as many private methods as we want to break down the bits and pieces of the code. If we had written these four private methods inside the Authenticator class (one of the clients of this policy object) itself, it would have made it really messy.
(hours_left_until_event_start >= start_time_threshold) && viewer_has_email? && not sent_previously?
Reduced Cognitive Overhead
This is kind of related to the above point.
Cognitive Overhead — “how many logical connections or jumps your brain has to make in order to understand or contextualize the thing you’re looking at.”
This is something very important and something that I’ve seen being neglected by many developers. I always prefer code that is expressive and easy to read and comprehend over code that is short and uses clever tricks.
The reason being the widely accepted truth that we developers spend a ton of time reading code. The harder it is to understand what’s going on in the code, the longer it takes to comprehend what its doing and the longer it takes to complete the larger task that led to you read the code.
To illustrate this, imagine we had all these conditions in one place like this —
((event.starts_at — event.current_time_in_zone) / 1.hour).round > 6 &&
How hard would it be for new people in the project to pick up what’s going on while reading this code? I’m sure it should take them longer than what the code I previously showed would take.
The only exception I can think of for this is when there is a clear performance advantage and in those cases its best to document the code really well. Rest of the time your code should read well without any comments.
Testability & Reusability
These are two obvious advantages you get when you extract small objects. And as a side note, after reading the POODR book, I realized these two points are actually connected. Go read the book, especially the final chapters! :)
Object Oriented Design is something new to me and it took a while to realize even the obvious advantages of having many small objects. Having said that I am also not oblivious to the fact that there is always a trade-off for everything in software and patterns need not be applied just for the sake of doing so.
There is a very good debate on this very topic of Policy Objects on HackerNews. Although there are no definitive answers in the discussion, its worth going through to understand the various perspectives that people have.
So, dear reader, I request you to share your thoughts on the class I’ve written. Share your thoughts on other benefits and maybe problems with using Policy Objects.
Happy coding ❤.