Hi everybody! What a hiatus, right? If you are asking yourself, what happened to you Alberto? The reality is that for a long time I wanted to included YouTube videos in my post and I promised myself that the next post I published would have a video for sure… what I did not anticipate is how hard would it be for me! Basically the problem was that this self-imposition was putting me totally out of my comfort zone, because it is embarrassing and because of my typical perfectionism which many times has the side-effect of blocking me, so, in the end, I assumed that my first videos are not going to be like the Sixtine Chapel, that they will look cheap, but I will make them better, step by step, with practice. In my situation I definitely needed to start with something, no matter how good it results being, instead of letting time go by forever. Today I am going to talk you about how the service objects I work with on a daily basis look like.

What is a service object in Rails?

If you ask yourself… “but, what is that service object thing?, I cannot find that in Rails anywhere!” Keep calm. You will not find any service objects in Rails’ default project structure, but that does not mean you cannot use them, in fact, lots of companies do… until the point service objects are even mentioned in Rails’ Autoloading guides!

Services objects, a.k.a. action objects or workflow objects, are objects whose purpose is to model your application’s business logic that typically would be spread between your models and controllers, within their methods and callbacks. Instead, you have it centralized in a single place, neat and pretty.

When to use service objects?

The answer to this question, as in many things in the software development industry, is that it depends on your taste. I have been in teams that used them always, to the extreme, that is, the controller action was a single line which instantiated the service object and sent it a message, while on the other hand, I have also been in teams that said no way to service objects, here we only use models, controllers and callbacks because that is how it works in Basecamp. I personally like to use them when there is complex business logic that I feel it does not belong to a model, when having it in callbacks could complicate other code flows, or simply when extracting it to a dedicated object would improve code legibility or reusability.


Service naming

Regarding class naming, which name shall we use? Personally I like to use names derived from a verb, like for example Orders::Builder to build an order in a store in which the process is complex.

Method naming

About this topic I like to use method names that reveal the intention of what is going to happen there. In the previous example, the most trivial thing would be to use build, but if we have different flavors or alternatives as fetch_or_build_by we will be able to express it with this convention. Many people, and maybe you are one of them, adopt the convention of naming this method call. The idea of using always this name no matter what does not seduce me. To be honest, I do not like it because, not only it somehow limits you to only have a single method per service, but you also loose expressivity and the ability to help people reading your code to understand what that method is supposed to be doing. Moreover, call is already used in Ruby for procs and lambdas, and the simple fact of using call as method name feels misleading to me as I always end thinking of procs or lambdas.

Where to put service objects in a Rails project?

In this case I follow the most accepted convention, which I have seen everywhere I have worked, with no exceptions here, which is, under app/services, which, as we saw before, it is even mentioned in Rails’ Autoloading guide.

Other alternatives to service objects

As also mentioned before, the classical alternative is to have this logic distributed in methods or callbacks inside your models and controllers, but there is also one more alternative that comes to my mind right now, process objects. We will talk about them in a future post.