Complaints on Rails

I frequently recommend that people avoid using Ruby on Rails. Every time I do this, I get blowback from people who are using Rails professionally, and who have various reasons that they justify their continued used of Rails.

Since it comes up so often, I’ve decided to distill all the various reasons not to use Rails on one page. Feel free to add more in the comments and I’ll try to integrate them as I have time1.

The Myth of Development Velocity

First, let’s touch on the primary justification everyone gives for using Rails: Everyone talks about how fast development is. And yet, when I’ve worked with Rails developers, their velocity was nothing at all to write home about, and I’ve heard report after report about how, as a Rails-based project progresses, the development velocity slows more and more.

Yes, you can get a basic API up and running really quickly. You can add a few endpoints, an admin panel, and authentication in minutes. And that’s honestly great. But it’s not enough. And as Fred Brooks said way back in 1975, There Is No Silver Bullet.

Ruby on Rails, in my experience, and in the experience of the many professional Rails developers I’ve spoken with, does nothing to reduce the overall project duration, and because of several serious flaws (detailed below), can actually be seriously detrimental to both the time it takes to create your MVP and the flexibility and long-term health of the overall project.

Dangerous Code

Ruby has no static type system or compile-time type analysis available. At all. Static types are important. Not only can static types catch many bugs, they can improve development velocity, make it easy to reduce technical debt, and make it easier for other developers to understand code.

Ruby has a strong culture of metaprogramming and monkey-patching. Metaprogramming can be dangerous, especially with no static type support or static analysis. Monkey-patching means a new module you import can break something completely unrelated. Even worse, as any application increases in complexity, it can be very difficult to understand what’s happening during any particular operation. When accessing a field might mean calling a series of a half dozen different functions distributed among thousands of source files, it can be nearly impossible to know deterministically what will happen.

There are apps that will never need to scale in any significant way. That’s fine. They will still likely need to be maintained over the long term, however, and so even for those apps I recommend against using Rails. I’ve seen very simplistic Rails apps absolutely fail to perform even for a single user: Granted I’m sure there was some kind of “silly mistake” that made a trivial query that the database would return in 1ms actually take 750ms to come out of the Rails app, but in no other API ecosystem I’ve used would that be a likely mistake to make.

Scaling Issues

The mantra of the Rails community is that “Server time is cheap and programmer time is expensive.” Given that I’ve already asserted that Rails doesn’t reduce overall project time in any significant manner, let me talk a bit more about why I think scaling should be considered up front.

Another common quote is, “Scaling problems are good problems to have!” Tell that to the guys running Friendster. Or, oops, they completely lost their US user base (which was once the dominant social platform in the United States) in large part because their site had poor response times for nearly a year.

People often bring up Twitter as a success story. I remember the frequent “blue whale” pages when Twitter kept falling down, and they ended up porting the entire backend to Rails and the frontend to in-browser rendering (away from Rails templates).2 I also remember a year of Twitter losing momentum as people were annoyed by its poor web performance; Twitter did survive, yes, but how many sites out there are so popular that they can annoy users for a year and still succeed? Sure, you can be lucky and end up with a Twitter or Facebook despite a poor user experience, or you could instead be one of the thousands of failed startups that your customers abandoned the first time a page took three seconds to load.

So how much slower is Rails than Node.js? Depends on the specific framework you use in Node, but if you choose one of the faster Node frameworks, you can get a more than 20x speed improvement for a typical API operation. That speed difference will affect both the latency of any Rails-based site and the number of servers that are required to host a Rails site at a particular volume. So if you do need to scale, a 20x factor can mean the difference between $10k/month and $200k/month in server costs.

Which is why I laugh at the “server time is cheap” quote above; if you need to scale to that degree that’s the cost of a dozen developers’ salaries easy.

The Wrong Paradigm

Rails is designed to server-render HTML pages on demand. As the world moves toward JAMstack and Single Page Applications (SPAs), being able to write your server code in the same language and tools as you write your client code becomes more and more important. A fully server-driven model like Rails was designed for is simply no longer a best practice approach.

Can you use server-rendered pages for admin pages? Certainly you could. But if the rest of your web site is written in React with TypeScript, why change out your page architecture for Rails when the rest of your technology stack is based on a very different language?

And what does an SPA need on the server? An API. The best tools for creating an API are coming from the Node.js universe, not the Ruby sphere: Feathers, LoopBack, TypeORM, Prisma, and a plethora of GraphQL tools designed to allow you to create complex but extremely flexible APIs with fine-grained security and 100% type safety between the server and the client code using TypeScript (see Dangerous Code above for why static types are important).

Where Rails Gets it Right

Rails makes it easy to just sit down and get started with a new project. In the Node.js universe, you frequently have to build up a new stack at the beginning. And the idea of “conventions over configuration,” where the defaults are set up in a sane way so that you don’t need to configure anything, is something that most developers should appreciate. Because Rails relies on conventions, it can be easier to onboard a new developer to a project.

Node.js is getting generators (create-react-app, yeoman) that can help you scaffold your new project. Tools like TypeORM use decorators to build your SQL schema. create-react-app relies on defaults that you may never need to adjust. And the entire ecosystem is maturing; as that continues, I expect to see the best designs and conventions becoming new standards.

And because of the Node.js philosophy, I expect everything to still be configurable. In Rails, if you don’t like ActiveRecord, you’re mostly out of luck. In Node.js, if you don’t like TypeORM (which actually supports both ActiveRecord and DataMapper access patterns!), you can use Sequelize or Prisma or or PostGraphile or Objection or one of many other options, depending on your precise needs.

So I strongly feel that the “project start” advantage of Rails is not a long term benefit. At most it may save you a few weeks at they beginning, while the power of a flexible and fully configurable stack that can be customized to your exact needs. And while a new developer may take a bit longer to integrate into a Node.js project, in my experience the difference can be measured in days. It’s just not a worthwhile tradeoff.

  1. Thanks to Peter Klipfel, a friend and long time Ruby on Rails developer, for some of these insights and directions. [return]
  2. [return]


comments powered by Disqus