A recent post “Rails is Not Your Application” caught my attention. It was fundamentally right, but the suggested implementation was misguided.
"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/."
When your application is a gem or a lib the design is answering the following question: “How do I create a solid model based on my problem domain?”. That’s what domain driven design teaches you. But it fails to answer subsequent issues of: “How do I create a solid and usable domain model?” and “How do I define a clear externally visible and testable boundary?”.
The answer to all these questions is a proper external API. But when it comes to an implementation with Rails one usually fails to express the API with the suggested MVC layout. I see several issues.
- Controllers don’t express RESTful intent. Rails controllers are designed to serve views. Calling JSON a format or a view is misguided because the format and the contents of the JSON belongs with the model, not with its presentation.
- Rails routes don’t coherently express RESTfulness and the separation of routes and controllers creates an unnecessary level of indirection. Therefore it’s difficult to know where the API begins and where it ends by looking at the controller code.
- Versioning is very hard and the changes in an API are difficult to trace. It’s particularly hard to take an existing Rails application and turn it into an API.
- Testing a controller allows reaching into the guts of the implementation to test assignment, therefore discouraging testing from the user’s perspective via the HTTP protocol. Furthermore mocking, heavily encouraged in testing controllers, serves no purpose in testing an API whatsoever.