The promises of Ruby and Rails

When I started using Rails, somewhere around version 1.2 in autumn 2006, I was attracted by many promises it made. Web development was supposed to be easier, faster and more fun - something a young Java & PHP developer like me instantly desired.

The thing Ruby on Rails evangelists did not tell us, however, was that with those promises comes a trade-off in form of very opinionated, and largely inflexible programming model - on both: language and framework layers.

The impedance mismatch between the design of framework, and design of our applications became clear soon. Rails made writing web applications fast and painless - provided they were awfully similar to Basecamp. CRUD-like applications fit the use case perfectly. Custom business process management apps not so much.

Ruby made a promise, that it will be fun writing code. But no one ever told us about fun of running the code in production or maintaining the highly coupled parts ten years later.

It took years for our community to come up with reliable solutions to above problems. They usually involve moving away from the Rails way of doing things. DDD, event sourcing, decoupling business logic from the framework - this all helps but increases the effort - breaking the fast development and ease of development promises alike.

The fun of writing smart code was also taken too far. Developers worldwide - having good intentions - released tone of acts_as_* libraries that were supposed to help us solve particular problems. Including one line into your model would make it handle versioning, become a state machine, or handle image uploads. This resulted in both - insanely large dependency trees for fairly simple applications - and having a code that none of developers really fully understood.

The pattern reappears

The same pattern of promising easier or faster or more fun way of writing software has been a recurring theme. Microservices were supposed to deliver simple service-oriented architecture - usually with no good way of interacting with each other and handling complicated use cases. NoSQL databases were to deliver great performance and reduce complexity of having to design your database schema - an obvious lie if you ever tried doing just that in evolving system. Isomorphic JavaScript web applications promised less code and faster development time, leaving us with poorly designed, poorly performing examples of spaghetti code architecture.

At this point, a red light flashes in my brain when I read another promise of faster or easier way of writing code.

Elixir - different set of promises

Elixir and Phoenix, in contrast to examples above, do not promise you significant reduction of effort you need to invest to build web applications. In fact, in many cases, you’ll need to write and maintain more code yourself than with Ruby on Rails.

Originally, Elixir promised one thing: access to Erlang/OTP with slightly more familiar programming language as interface. Any Ruby programmer can easily understand what Elixir code does just by looking at it - the similarities are striking.

Instead of being handed ready to use solutions, you are given building blocks. They either come in form of Erlang’s OTP modules, or Elixir-specific implementations such as GenStage. These are, however, the blocks you have to put together yourself - making it fit your particular use case.

There were some initial Ruby/Rails influences as well. Early versions of Phoenix framework did not exactly impress me. It turns out, after couple of years of being exposed to concepts coming from Erlang, the mindset of a programmer shifts significantly. The recent versions of Phoenix Framework are moving in very different direction than Rails does. There’s more decoupling, more flexibility in organizing your code. The original creator of Phoenix gave really good talk about the changes - and reasoning behind those recently.

Elixir does not promise you that your code will scale horizontally. It promises to give you tools that you can employ to make it happen. Elixir does not promise you fault tolerant systems with no effort. It gives you design patterns and building blocks of reliability instead.

We run a Ruby and Elixir consultancy and I also observe different kind of clients asking about Elixir work than those, who come seeking help with Ruby. The Elixir clients tend to be more experienced, having a production application (possibly in Ruby), seeking help with solving technical problems Ruby can’t solve. Many Ruby clients still come to us as a result of Ruby on Rails hype from the late 2000s, hoping to build their start ups faster and cheaper.

One could say the hype on Elixir is not as high as it was on Ruby/Rails. I think the statement is true - it’s not comparable. This is a result of different promises each environment makes. I hope, however, that this will result in less disappointments - as Elixir does not promises easy miracles.