The topic

A Service Object is the most popular buzzword among Ruby and Rails programmers these days. Similarly to ECMAScript 6 generators in JavaScript world, Service Objects are widely described and strongly discussed across the Ruby and Rails community. There are tons of articles written about Service Objects, hundreds of implementations and a multiple examples, which, despite sharing a common idea, are sometimes inconsistent or at least vary from each other in one way or another.

Why is that so?

How come this is happening? Because there are many programmers and, therefore, many minds. Each one has a different point of view even when discussing common and widely-known topics. We don’t listen to the opinions of others, we stick to our beliefs, and don’t even try to change them. We don’t talk to each other. This is also why the English language in the US and in England is a little bit different — surely the origin was the same! Every one of us interprets the topic in a very different way; there is no standard definition describing Service Objects.

Rationale

I wouldn’t be trendy if I didn’t write about Service Objects as well, but I wouldn’t be a hipster if I wrote yet another article about “What is a Service Object?”.

So let me begin by describing what a Service Object definitely is not, because it’s simpler to reject some opinions rather than to create yet another one, which we already have a lot.

Disclaimer

This article is highly opinionated and present solely my point of view, which is not based on any theoretical principles. You may love it or hate it, but you should definitely leave a comment to show how you understand and use Service Objects on a daily basics.

What Service Objects are not

1. Everything other than MVC

Sometimes I see the tendency people have to call a Service Object everything what is not a Model, View or Controller. They’ve just jumped into the topic, read some stuff and make a quick assumption:

I already have models, views and controllers so I’ll just create another directory called “services” where I’ll put all my code which doesn’t fit into the other three categories.

This approach has two sides. On the one hand it may be considered as correct — definitely Service Object is neither Model nor View or Controller, however on the other hand that doesn’t mean Service Objects are everything else!

2. Methods

In OOP world we are used to representing “beings” as objects and “doings” as methods. It’s kind of a natural approach and usually the easiest way to model our domain. With Service Object, we are introducing a behavior that isn’t definitely an object’s method. It is not a part of some class either. It’s a stand-alone action represented by a class. We have to change our habits a little bit, because even though we want to create an action, it cannot be tied to any object’s method and has to be an independent object on its own.

3. Queries

Service Objects must not have a return value. They are not queries, they do not fetch any data. They performs actions with side effects and they don’t respond to anything. They can send an event, execute a callback, but still only perform a particular command. They have to be completely separated from queries.

What if we want to check the result of service’s invocation? Some claim that services can return a boolean value or even ActiveRecord(!) object, but that violates tell-don’t-ask principle. We don’t want to ask each time if an operation was success or if object was saved. We only want to be notified if something went wrong. Here is the simplest pattern that I use to prevent common problems:

One may say that handling exceptions is a costly process. I have two thoughts about that:

What do you expect when executing some service — a success or an error? How often do you get a positive result rather than a failure? Does your flow expect to be completed rather than interrupted?

Let’s think about that together. I believe you designed your system to complete the intended flow. (Ideally) failures are only very rare manner among many requests. In that case pitfalls will happen relatively rarely, and the cost of handing exceptions won’t be high either.

If I didn’t convince you, you may always use some kind of notifications with event bus. You can either pass an explicit success/error callback to your service or depend on some messaging (event) system in your application like wisper gem.

4. Patterns

A Service Object is not a pattern. It is an implementation. When you want to see what pattern it should follow, the most similar will be a command pattern, some say that it also fits into a strategy pattern, but it does not convince me whatsoever. This is an example how Service Objects could be designed:

5. Use cases

Although many say that Service Objects can compose and encapsulate other services, I personally believe that should not be a responsibility of a Service Object. In my opinion, either controllers, or even better Use Cases should be the moment when we are orchestrating both Service Objects and Queries workflow.

What are the rules?

I gathered many interesting statements from various blogposts that I find are well suited to describe Service Objects.

Service Objects show what an application does. They are easy and fast to test since they are small objects with one entry point. They use dependency injection heavily so they are loosely coupled with the rest of the application Service Objects encapsulates a single process of our business. They are Rails independent and don’t know the surrounding application context. They can model domain behavior. Service Objects have no state, they are identified by their actions.

Abstraction

Service Objects introduce an additional level of abstraction, not only encapsulates some behavior. I believe this is a topic for another blogpost. To find more please read http://blog.8thlight.com/kevin-buchanan/2014/11/04/mistaking-encapsulation-for-abstraction.html.

Resources

(Ones worth reading)

Off-topic: When I was reading good or bard Service Objects oriented articles I noticed that most of the better one are written by Polish developers. I don’t exactly know why, but it’s good to know that we have a lot of awesome programmers here ☺.