Last weekend I attended the wroc_love.rb conference in the beautiful city of Wrocław. I got a chance to be a member of the “Ruby vs Elixir” panel session and spent hours discussing related topics during the afterparties.
I love Ruby, I’m a “Ruby native” - it was the first language I really learned, and the first one I used to make money as a programmer. But for the time being, I decided to stick with Elixir. In this article I share some of my reasoning that I expressed during the panel, the discussions, and some other thoughts that I had since. I’ll also include links to other resources that explain the points I’m making probably better and to a greater extent.
Different use case
First thing, I’d like to state is that, I don’t think you have to choose one of Elixir or Ruby and completely condemn the other. They are both useful languages, and while there’s a significant overlap in the use cases, I’m convinced there’s a place for both of them.
Talking with people during various conferences and on the Elixir’s Slack channel or IRC, I see a lot of people leveraging the power of Elixir in new and exciting use cases, far beyond the regular web development - something that remains mostly inaccessible for the mainstream Ruby community. And that’s probably the reason more and more people are looking somewhere else, to languages like Elixir or Go. Because more and more applications are not “just” business web apps, more and more applications require processing a lot of data, providing some level of real-time features and require massive parallelism. Additionally, projects like Nerves open completely new areas to developers - I’m pretty sure we’re going to see more of those in the coming years.
Performance & scalability
Whenever Elixir and Ruby are mentioned in the same sentence, the next one almost certainly includes performance claims and comparisons. That’s true - in many cases, Elixir is widely faster (within one or even several orders of magnitude), but I don’t think it’s that important.
It’s an easy thing to include in a blog post, or mention in 140 characters of a tweet. Everybody loves a good benchmark. But performance is why people come to Elixir, not why they stay. It’s just the icing on the cake.
At this point I also need to mention the Elixir - different kind of promises article by Hubert Łępicki, where he explains his view on how Elixir and Ruby differ and why it might be a good idea to stay with Elixir.
Fault tolerance and isolation
The biggest advantage of the entire BEAM platform is the isolation and fault tolerance guarantees it provides. It’s the only technology, that I know of, that truly allows separating different parts of the system, so that they don’t influence one another. This happens on, at least two, levels:
- limited error propagation - the supervision system allows for isolating failure and collectively managing the unexpected failure scenarios without excessive code. A bug in one part of the system does not affect other parts;
- progress guarantee - the preemptive scheduling of processes is a true life changer. With it, we never have to worry, we’re going to “block” our thread pool (which is a major concern in other actor system implementations), we never have to be concerned about starving some part of the system. This is where the soft-realtime guarantees of the platform come from.
To learn more about the fault tolerance and isolation of the Erlang ecosystem, I recommend reading the excellent The Zen of Erlang essay by Fred Hebert.
Ruby and Rails are praised for the “developer happiness”. And that’s true - starting an application with Rails is a breeze, allows you to deliver features fast and solve problems quickly. It’s extremely enjoyable and satisfying to see a complex system arise from nothing in such a short time. Unfortunately, I feel like the whole regard for developer happiness goes completely out the window, when we start considering longer projects. The defaults promoted by the language and framework, make it easy to create code that is hard to maintain and makes you want to cry - and those are not tears of happiness. It’s true you can use your own patterns that make this a non-issue, but for a majority of projects, the sad truth is, the defaults are what is used.
The “developer happiness” is equally a goal for the Elixir community. But the notion is regarded much more widely - not just in the initial phase of the project, but also in the long term. Various libraries are willing to sacrifice some of the initial “velocity” for the long-term maintainability. The changes introduced in Ecto 2.0 (focused primarily on the removal of the features that are known to create maintenance burdens - e.g. callbacks), and recent changes in code organisation philosophy from Phoenix 1.3, are all a testament to that.
One thing about the Phoenix 1.3 changes to note, is that those changes are not sudden or unexpected - various discussions about the structure of a Phoenix application were happening in the blog articles, forum posts, and conference talks for at least a year. The leaders of the community are not afraid of listening to others, admitting to errors when necessary, and correcting them.
A common worry for new platforms is the lack of tooling. But Elixir is not a new platform - the tooling for the Erlang ecosystem was constructed over the last 20 years into an impressive set of debugging and diagnostic facilities. The most profound - tracing, sometimes seems like a true superpower. The language and the platform cooperate nicely providing basic low-level facilities, which make it easy to build extremely useful tools on top of them - Recon, Redbug and observer just to name a few. And there’s more coming (!) with projects like wobserver and Erlang Performance Lab putting the bar even higher.
That said, on the front of editor tooling we have a long way to go to match other languages. Hopefully, we’ll get a student to implement the Language Server Protocol for Elixir during the Google Summer of Code, which has the potential to improve the support quickly across various editors (if you’re a student, please consider applying for GSoC!).
It’s all about simplicity
If I were to pick one thing about Elixir, that makes me like it so much, it would be simplicity. In the excellent talk Simple Made Easy, Rich Hickey - the creator of Clojure, defines the difference between those two, at first glance similar terms. In short, something is easy when it is short, concise and familiar, but something is simple when it is not complex when it is easy to understand and decompose.
I feel like many libraries and solutions in the Ruby community, overly focus on making it easy - “just include this one line and you can launch rockets to the moon” is such a common claim in READMEs of many gems. The mainstream Ruby community focuses on building solutions to problems and only then trying to make them reusable in some way.
On the other hand, most of the core Elixir libraries - Plug, Phoenix, Ecto, and countless other ones are primarily tools for building solutions. They are more low-level, which means you need to write some of the code yourself, but it’s much easier to switch parts or customise their behaviour. They allow you to spend time solving your problem, instead of trying to make a solution to somebody else’s problem solve yours as well.
With all of that out of the way, I love one thing about both Elixir & Ruby - the people. You rarely find such open and welcoming souls as amongst people attending conferences for either language. The honest love for learning, simple human kindness, and willingness to discuss are otherwise unheard of. Even when having arguments on such emotional subjects as the choice of the language, the discussion is respectful and factual. I thank very much my co-panelist for a great discussion Hubert, Andrzej, Robert and Maciej during the panel, and all the other people that spoke to me on the subject during the afterparties. Thank you.