Manoj M J
Manoj M J
Aug 29, 2018 · 3 min read
Photo by John Matychuk on Unsplash

In our previous blog post, we talked about how we started to use the Interactor paradigm for our service objects, with each service designed to have a single purpose.

Here’s an example of an Interactor in action:

Any parameter passed to the Interactor, is made accessible within the Interactor as a method on the contextobject.

We can also attach more objects to the contextobject if needed.

Here’s an example:

Going back to the AuthenticateUserinteractor, it has one purpose, to authenticate the user, and that seems to be pretty clear.

However, what’s not so easy to determine, is the list of parameters that AuthenticateUserdepends on — email, password, token, session, key, etc.

A developer would find it difficult to understand what parameters are needed for an Interactor, and what parameters are being added to the Interactor on runtime.

In a plain old Ruby object (PORO), it is relatively easier to understand the dependencies of the class by inspecting the initialize method.

Here’s an example of a PORO for the same AuthenticateUserscenario:

So, the lack of an initialize equivalent method in the Interactor will eventually turn into a big “code readability” issue when a developer opens an Interactor and has to parse every line to understand it’s dependencies.

How can a developer quickly and easily figure out what parameters the Interactor needs?

a. Documentation
The developer can document the dependencies as comments. This however, isn’t testable and requires the developer who’s writing, and the developer who’s reading the code, to be diligent.

b. Use delegate

As mentioned in our previous post, we used the delegate method to avoid the code readability issue, but this approach did not allow us to actually validate the parameters going into an interactor instance.

c. Use before hook along with a method that does validation of the context object.
Interactor allows us to define before, around and after hooks that will be executed before, around and after the callmethod.

We can define a before hook to validate the presence of parameters and raise an ArgumentError if any parameter is missing.

Here’s an example:

This will do the job. The developer who’s going through the code now has one place to look up dependencies, and it’s testable too.

But we can make it better, with the help of some Rails magic.

d. Use ActiveModel::Validations

This module gives us ways to define our validations even better, stronger, that are, out of the box easier to define, and understand.

This requires the activemodelgem, however, we think the benefits outweigh the dependency.

Here’s an example:

As an added functionality, the requiresmethod also delegates any variable mentioned in the method to the context object so that we do not have to explicitly use context.variable anymore.

This is possible even today with the ActiveSupport’s delegatemethod, but since we are mentioning the required parameters in the Interactor anyway, explicit delegation can be avoided.

Example:

Conclusion

We finally decided to go with the ActiveModel::Validations approach because of the extra flexibility it gives us in terms of custom validations (like validate :email_is_internal)

Hope you enjoyed reading about Interactors and Validators. We’re always exploring new things at Reflektive and would like to know how you perform validations for your service objects. Let us know in the comments below!

reflektive-engineering

A place for Reflektive Engineering to help share our learnings with the community.

Manoj M J

Written by

Manoj M J

Works @ GitLab. Ruby, Rails, Startups, Books & Movies.

reflektive-engineering

A place for Reflektive Engineering to help share our learnings with the community.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade