The Service Layer as the New Meme
I have read recently a bunch of articles about service-oriented architecture. Or at least that’s how I like to call it.
More on the concrete side, Nicholas J Henry has written a nice blog post about the architectural aesthetics of extracting the core logic of your application into a service layer in a Rails-based project. His post can be summarized in one of his tweet:
Rails is not your application. It might be your views and data source, but it’s not your application. Put your app in a Gem or under lib/.
Taking a slightly different perspective, Jared Carroll wrote an excellent article on when to use service objects. He recalls that Evans defined 3 types of services:
- application (for a use case necessitating non-infrastructure operations, e.g. CSV export)
- domain (for a use case requiring multiple domain objects whose responsibility is beyond a single object)
- infrastructure (for a use case encapsulating access to external system, e.g. email or message queue)
I would summarize his blog post by saying that most applications do not need a (general) service layer (living in between your controllers and your models) when every request to your app goes through your service layer. Instead, your controllers act as the interface to the outside world and should constitute the service layer. In other words:
Most apps will typically have an HTML client and a few additional clients, for example, an iPhone and a console app, but the same controllers will serve both HTML and JSON. In a way, the controllers have become the services because all clients talk to the app over HTTP.
Rails’ Natural Evolution
I spent a few years of my life crafting (web and desktop) Java applications. And in the Java world, everybody knows about service layers. That’s probably due to the fact that Java developers usually deal with relatively large code base, and if you don’t have decoupled modules with their proper API (in other words, service layers), it’s arguably impossible to maintain your codebase.
It might also due to the fact that Java has been there for quite some time, and Java-based web frameworks like Spring have seen quite a few springs by now. The goal of modularity so essential to the DataMapper’s guys at the time reminded me all the emphasis put on the inversion of control pattern back in the early days of Spring. By injecting your dependencies, you could have plenty of different modules and could pick only the ones you like (as opposed to dealing with a monolithic framework as that was the case in the early days of Spring). But more to the point, based on my experience, almost all Java-based web applications have controllers which talk to a service layer which talks to DAOs which talk to an ORM. That was 10 years ago.
And I think that’s where the Rails framework is at: it’s discovering service layers. More and more people are now using Rails for relatively large codebase, and as a result, they feel the lack of built-in support from their framework. There is a realization of the need for services. It feels like it’s a milestone in the natural evolution of a web framework.