Reaction to "An Imagined Keynote"

On Tuesday, David Copeland posted a script (with code samples) for a fictional future RailsConf Keynote reveal of Rails 6’s "new features". (If you haven’t yet, please read it; I’m going to reference it without quoting.) Copeland suggests that between a perceived lack of Rails 5 talk content at this year’s RailsConf, and Justin Searls worrying over Indeed.com job trends (it’s towards the very end), Rails might need bold new features to win back mindshare. (A note on Searls' talk before we continue: out of context, one line chart proves the existence of line charts. I’d like to see a more thorough analysis, including Rails' adoption & use data across both enterprise and startup sectors, before deciding the sky was falling.)

Whatever I think of his motives, Copeland proposed these features, and I think they’re great. I want almost all now.

Front-End 2.0

I don’t do any front-end work (that isn’t dataviz) these days, so I have no opinions on Copeland’s proposals here. I’d love to hear what designers & front-end developers think. I will mention — this has nothing to do with Copeland — the name 'OOCSS' bothers me. I’ll let Sam Phippen say why, because I wouldn’t do better:

Making the RESTful 7 Special

Copeland’s suggestion that defining UsersController#index should make it a route (without needing any config/routes.rb declarations) is compelling. The idea of adding more invisible magic to Rails concerns me, but I’m very excited for it to be effortless to do "the right thing". I do worry about losing the "glanceability" of the routes file, but all of us working on monoliths lost that long ago.

ActionResource

This would be so useful. Facades (or Presenters or Decorators) absolutely have a place in the modern web application, but the best solution I’ve found is using SimpleDelegator for single objects and Forwardable for composite facades. This is workable but not good. ActiveResource is. I like that aside from the proposed from/format DSL, you just write Ruby (which has always been Rails' greatest strength - when it gets out of the way and lets you). And the DSL is clear (the highest praise you can offer a DSL) and effort-saving (the second highest). I would start using it today if I could. (I might try to implement it.)

ActiveService::Base

I don’t like ActiveService. It isn’t (as Copeland says) "a radical change in how Rails thinks about your application’s architecture". First Controllers, then Models; now Services will be the ordained "containers of business logic". Copeland says this isn’t "overly prescriptive", but it prescribes that everything sorts nicely into a small array of buckets. We need to discard the belief that there is no finite set (of reasonable, rememberable size) that includes all forms Business Logic can take. As a community, we need to stop searching for the magic pattern that provides an easy answer to the question "where does my business logic go?". There is no such pattern! It always depends on the domain you’re modelling, and it always depends on the team. I do agree with Copeland that it’s a "good enough nudge", and I hope it will give the Rails community a new starting point for discussing where Business Logic belongs. For that alone, I celebrate the proposal.

Two minor notes:

  1. It seems better than libraries like light-service, dry-transaction, or solid_use_case, which all pretend to be OO.

  2. The proposed Dependency Injection has the ability to dramatically ease the testing of these services. It’s a very good design choice.

Smart Database Defaults

OMFG yes. Rails' approach to database features has always puzzled me. From the Migrations Rails Guide:

The Active Record way claims that intelligence belongs in your models, not in the database. As such, features such as triggers or constraints, which push some of that intelligence back into the database, are not heavily used.

Validations such as validates :foreign_key, uniqueness: true are one way in which models can enforce data integrity. […​] Like anything which operates at the application level, these cannot guarantee referential integrity and so some people augment them with foreign key constraints in the database.

This is an immature attitude towards database integrity features. Rails' users ostensibly select their databases for reasons, some of which relate to features of that database. (For example, I don’t use MySQL when I can use PostgreSQL. I prefer having check constraints and lots of column types. Also, Postgres' write-ahead log is miles better to deal with than MySQL’s abominable binary log.) The guide even recognizes that ActiveRecord can’t guarantee uniqueness with validations. I’ll say that again: using uniqueness: true guarantees nothing at high load.

Yet, Rails' defaults are to assume either:

  • You know enough about databases to write database integrity constraints yourself.

  • You won’t ever get enough load to discover your persistence layer doesn’t have your back.

That’s bullshit.

Copeland’s proposals rectify this, giving Rails smart defaults around integrity. They aren’t even a departure from Rails' philosophy, just a swapping of harmful opinions for helpful. I like all of them, but in particular would be thrilled if:

  • Columns were non-nullable by default.

  • Foreign keys had constraints by default, assuming database support.

Unit Tests Wouldn’t Hit the Database by Default

This would be wonderful. I don’t see how it would fit in with Rails' "Fuck business logic! Use callbacks!" attitude and the framework’s inability to tell Application Logic from Business Logic. It’d be great if unit tests being entirely in-memory by default provided the push for developers to move business logic out of callbacks, but that shift is unlikely to take place without movement on this topic from David Heinemeier Hansson himself. I feel the attitude is propagated more by blogs & talks by Rails' users than by it’s maintainers, and because the "callbacks are fine for business logic" is so 'baked in' to Rails developer culture, I don’t see a push from anybody but Hansson himself changing the way we approach callbacks.

A Real Reaction

I fervently hope that Copeland’s post gets a conversation started about actual failings that Rails isn’t addressing. I don’t know if these features will help Rails feel new and shiny again. Maybe so, maybe not. But they’re more exciting than ActiveRecord::Base.suppress.