Simple as pie

The Ruby gem Interactor solves the problem above mentioned in a very very simple way. For each use-case, action or task, whatever you may call it, you create a class named as the purpose of the task (like ReadFile, SaveUserProfile or DeleteAccount) and invoke the method call passing the data needed (or context) for that task, like:

A basic setup example of an interactor class

Two things to setup: include the module Interactor and define a public instance method call . That’s it. This simplicity is one of the reasons I like this gem so much and we use it in many of our projects here at Guava. Besides, if we need to pre-process something before the call method, like setup or validate the arguments, we can do that with the before hook, which accepts a block as a parameter. There are also the after and around hooks.

Now let’s go back to the tasks in the first controller (the bloated one) mentioned in the beginning. Notice the create action is trying to do a list of things in order:

1. create the sale record

2. find and process the stock for the products involved

3. process and send to shipping department

4. send confirmation email

Well, to start off removing business code from our controller, we create 4 interactors: CreateSale, ProcessStock, DispatchShipping and SendConfirmationEmail. If we call each one of these interactors, it’s gonna work just fine. But there’s a caveat: if one of these operations fail, we need to rollback all the other ones already finished. Therefore, if we used this approach, we would end up with a lot of conditional code in our controller, like:

“If ifs and buts were candies and nuts we’d all have a nice code” or whatever.

Not nice. In fact, it’s called conditional hell. Enter Organizers. An Organizer is a special kind of Interactor that has one responsibility: to call other interactors in a given sequence. For the situation above, we would have:

Expressive, ain’t it? It’s like, you open the PlaceOrder class and it’s right there, in simple, defined steps, basically telling you what it does. Each interactor executed passes the context (or arguments) through to the next interactor in line. So, for instance, the organizer in the example above passes only the sale (which we suppose has a lot of data about the products and stuff) as its context to the first interactor, CreateSale. But all these interactors play like a family, they share context. Meaning that if we set a variable products in our shared context inside CreateSale, ProcessStock and the next interactors in line will all have access to products through the context object. Except if one of the interactors fail, in which case it avoids the next interactor in line of being invoked. There’s more to know in the case of a failure like the above, but I recommend reading the gem’s documentation for that.

Oh, and I did not forget about the transaction code in the bloated controller code example. I’ll talk briefly about how it can be handled in an organizer later.

In the future (probably in version 4) we may be able to pass not only interactors to the organizer to execute, but also procs and method objects! Something like:

Yeah, I think it’s cool to see organizers just receiving a Proc or Method Object and execute it while being impartial about the argument’s race, gender and nationality. We need that in the world. Also, I believe there is a use for that, for instance, if you need to create an organizer dynamically or if the task being passed is so trivial that would justify the use of a Proc (you know, because it’s a one-liner). On the other hand, I think it kinda hurts the purpose a little bit. Naming is important. Naming interactors very much so. I mean, the whole description of the task goes in the name of the class! You can read straightforward what a given interactor is all about just by reading its class name. With this idea in mind, when we read an organizer’s organize call, it becomes very clear where it’s going: CreateSale, ProcessStock, DispatchShipping, SendConfirmationEmail. Now, what if a Proc, even if it’s a one-liner, stands in the middle of the “sentence”? It’s definitely not the same as before. It’s just not as fluent, even though in more appropriate cases I guess it would still be readable. All in all, I think both arguments balance each other out, which makes me vote in favor of the change, leaving the developer responsible for the legibility of their own code.

Sharp as a tack

There are many pearls throughout its features, but one that makes a lot of sense are its hooks: before , around and after . Think about it: this allows you to do whatever you want inside an interactor without much complexity. If you need to setup any object or validate parameters previously to your main method, you can use the before hook. To set warnings, close files or connections after the interactor successfully ran, you can use the after hook. While around hooks allow you to weave your interactor call in between a block of code, so you can decide exactly when to invoke it. This is useful for so many times when we need to wrap our interactors with extra code. Take Rails’ ActiveRecord transactions for instance. Imagine we have a Rails app where, at some point, we need to save 3 records to a database, say, a Sale, a Stock and a Payment. The thing is: if one of them fails, we need to rollback the transaction in order to avoid inconsistent state in our database. Now, one way to do that would be to use an organizer and call an interactor for each of these tasks. But what if the third interactor, SavePayment, does not go through? We would end up with a sale that was made with no payment! Prison! Death! Or maybe just a slap on the wrist depending on the country where you’re reading this from… But, in other words, if we don’t process the 3 actions inside a single ActiveRecord transaction, we will be in trouble. That’s where the interactor’s around hook comes in handy, allowing us to look smarter than we really are. We can simply go with: