Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Hexagonal Rails and The Ludicrous Terminal Application

In the second “Is TDD Dead” hangout, DHH says that developers justify hexagonal architectures by arguing that it gives them the freedom to swap out the GUI for a terminal application, or to swap out the database layer with an in memory store. He finds that ludicrous. I can understand why. Although I’m currently working on an application that has moved from Sinatra to Rails, has multiple datastores, and is just embarking on a terminal UI, I admit that this has been rare in my career.

Developers that invoke the “swappable datastores and UIs” argument have likely cargo-culted that argument from someone else. There’s a much more immediate and pressing need to separate your domain from your UI framework and your persistence layer: they change for different reasons.

Consider this: do you want to have to change the objects containing your application’s business logic whenever DHH releases a new version of Rails? If you put business logic in controllers and ActiveRecord models, you run this risk. With each major release of Rails, I’ve seen applications built “the Rails Way” go through this pain.

What about this: do you want to have to change your business logic in order to improve the speed of persisting and retrieving data from your datastore? In my career, database querying has often been a performance bottleneck as application usage increases. Imagine that you’ve had to start denormalizing your data in order to improve performance, or that you’ve had to create new tables or use stored procedures, or shard your data, or start moving certain types of data into high performance key/value stores. If you built your web app “the Rails way”, then you merged your business logic and your persistence logic into the same classes. You’ve let the structure of your database dictate the locality of your business logic. Because of this, as the structure and nature of persistence starts to change in your application, your business logic will have to change with it. I’ve felt this pain too many times.

Uncle Bob defines the single responsibility principle as this: an object should have one, and only one, reason to change. If an object contains both business logic and persistence logic, then it, by definition, has two reasons to change. If an object has both business logic and presentation logic in it, then again – it, by definition, has two reasons to change. Hexagonal architectures try to separate the things that change for different reasons, and collect the things that change for the same reason. These architectures are simply an extension of the Single Responsibility Principle. (Note that I’m lumping Alistair Cockburn’s “Hexagonal” ports-and-adapters architecture in with Ivar Jacobson’s “Use Case” approach, popularized by Uncle Bob Martin).

Over the last six years, I’ve had the opportunity to work on lots of different Rails applications, with lots of different developers, for lots of different companies. Most of these Rails applications were built the “Rails way”; in other words, they largely consisted of controllers, views, ActiveRecord models, and helpers. Most of these applications reached an inflection point as our business logic became more entangled with the framework: velocity slowed, defect-rates increased, and developer happiness dropped. Turning that around took a lot of work. I’ve seen so many developers blame Rails for this.

But who should we really blame for this plague of bad Rails applications? Rails itself? DHH? No. We, the developers, are to blame. “The Rails Way” makes a lot of sense for CRUD applications. But CRUD applications don’t exist in the real world. The REAL WORLD exists in the real world. We build applications with real world business logic in them. For that, we need real world architectures. Rails provides a fantastic set of tools for us. It solves so many problems inherent in web development for us, letting us focus on our problem domain. (Don’t believe me? Watch the beginning of Yehuda’s talk, “Rails: the Next Five Years“). And, since version 3, Rails has actually made it really easy to separate out our business logic from presentation and persistence (ActiveModel + Engines). All the tools exist; we have no excuse not to try.

Hexagonal architectures are not, in any way, an insult to Rails. They are, in fact, an affirmation of what Rails exceeds at (the web), and a collective realization of what Rails isn’t (our application).

Addendum

Although the spectre of a terminal application may seem ludicrous, I’d bet large sums of money that you already have other interfaces than HTML. Have you written a JSON or XML API for your application? Have you created background workers for your application with Resque or Sidekiq? Do you use a gem like “clockwork” to run scheduled tasks for your application? You owe me money.

Comments
  1. erik says:

    Great article.

  2. Daniel Lynn says:

    Great post! In the second IsTDDDead talk, the arguments being made against terminal applications or switching out a database were just picking at the likelihood of the example instead of addressing the underlying value. This was a great explanation of that value.

  3. Sam Obukwelu says:

    Well written post, Matt. Ports-and-Adapters architecture seems to address the concerns of large Rails apps where change is painful and developer happiness has evaporated. But getting there from your nominal rails app is an extremely difficult undertaking.

  4. […] came across a friend’s post on the Pivotal Labs Blog regarding Hexagonal Rails. I agree with his conclusion. I think evolving […]

  5. Tol says:

    Repositoy pattern :) what is the acronyl DHH?

  6. Cory Wandling says:

    I am not a Rails/Ruby developer but am somewhat familiar with ActiveRecord and Controllers in Rails.

    I have always thought that it was good to separate controllers from business logic but I struggle with the persistence layer.

    Do you think that there is a difference between the marriage of domain objects with ActiveRecord and using Hibernate in Java to map the persistence data into the domain objects?

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *