Will Elixir/Phoenix make Ruby on Rails obsolete?15 Apr 2017
In this article I want to compare Ruby vs. Elixir to see how they stack up, and explore how this new language might affect the Ruby ecosystem. But to start with, a little background on Ruby and why it’s so great.
In 2005 DHH released a video entitled “How to build a blog engine in 15 minutes”.
It showed off a little-known framework called Rails, which allowed for unheard-of speed in developing the type of CRUD web applications common throughout the 2000s.
Rails was almost magical in the how it could do so much with such a tiny amount of code, and even today Rails is still probably the best choice for fast iteration in web development.
Most of this magic was built on the back of Ruby’s extremely powerful metaprogramming abstractions. Ruby was my first love and will always occupy a special place in my heart. It is one of the most metaprogrammable languages ever designed and that shines through as it’s core strength.
This metaprogramming power allows DSLs to be constructed in a way that complex operations can be written in a way that reads almost like english:
# RSpec login_as learner visit course_path(course) find('.join').click expect(page).to have_content('Thanks for joining!')
Even in 2017 Ruby is still one of the best options as a general purpose scripting language and for many types of web application. There are a lot of developers around who are fluent in Ruby and they tend to be of high quality.
However, Ruby does have a number of shortcomings when applied to modern web developent:
Runtime speed - The Ruby runtime has never been a speed demon (although it’s slowly getting better). There are design choices in the language that make high performance difficult (ahem mutable strings) and as heroic as the efforts of Matz and his team are, they simply don’t have the developer muscle that goes into optimising something like the JVM or GoLang.
The practical upshot of this is a floor of around ~100ms for a typical web request using Rails, and test suites that can become painfully slow for large applications.
Boot speed/memory consumption - Primarily a Rails problem, as the number of gems goes up the boot speed of a Rails app gets slower and slower. It is not uncommon to see a single Rails process using 300-400MB of memory, notwithstanding any leaks - which become more and more likely as more third party gems are included in a project.
Concurrency (not parallelism!) - Ruby is pretty bad at being concurrent. The native tool for handling concurrency is the Ruby thread, which is one of the hardest concurrency primitives to reason about and requires painful messing about with mutexes and semaphores to handle safely.
Scalability (parallelism) - While it does have threads, native Ruby code is always limited by the GIL so that true parallelism within a process is not possible. The rule is, if it’s Ruby code then only one line can execute at a time within a given process. The way to scale Ruby is to throw a lot of processes at it, and a lot of servers. But processes are costly and this is an expensive way to scale.
Despite these issues, Ruby has remained popular for the primary reason that it is beautiful to work with, and is so malleable that it allows for fast iteration especially for startups who don’t quite know what they are building yet.
There are many languages that solve the performance problems listed above, but none so far have matched the beauty and expressiveness of Ruby. Elixir promises to change that.
Elixir promises to deliver the elegance and power of Ruby, built on the reliability, speed and scalability of the Erlang virtual machine. The stated design goals are compatibility (with Erlang), productivity and extensibility.
As it’s designers are keen to point out, Elixir is not Ruby for the EVM. The syntax may appear to have a passing familiarity, but many core concepts in the language are quite different.
At its core, Elixir is secretly a LISP pretending to be something else. This allows for a particularly powerful form of metaprogramming via macros, that allows you to rewrite the AST before it is evaluated. It is also a functional language with no mutable state. This promises to greatly improve long term maintainability as compared to OO languages like Ruby where data structures are mutable by default.
Many of Elixir’s features are not strictly part of the language, but rather are built using the same macro system that is also available to you as a developer. It is highly extensible in a similar way to Clojure.
Elixir’s greatest strength is the Erlang Virtual Machine, which along with Erlang’s OTP framework provides a base for building systems that run forever, self-heal and scale as large as you need them.
Among other things the Erlang platform also promises:
And I suppose this article wouldn’t be complete without some arbitrary benchmark numbers comparing Elixir/Phoenix to Ruby/Rails:
Phoenix - 43,063 req/s, 2.82ms avg latency Rails - 3,274 req/s, 17.25ms avg latency
That’s a 13.5x performance increase, which means you need 13.5x LESS machines to do the same job, and everybody gets faster page loading to boot.
So will Elixir make Ruby obsolete?
Yes, and no.
Ruby isn’t going anywhere and I will continue to use it myself for many client projects. I worked on a small ecommerce store recently handling a couple of hundred users a day. Ruby/Rails was a great choice for this, the established ecosystem allowed me to leverage existing libraries to get up and running really fast. It will never need to run on more than one server and will be easy to maintain for other developers.
Ruby is great for projects that don’t need to scale or handle realtime updates and for hacking on prototypes to get something up really fast. It has a vibrant community and a fantastic ecosystem of tools. Even the UK government is using Ruby for it’s projects which just goes to show how mainstream it has become.
However, for apps requiring high scalability and reliability as well as malleability that allows for fast iteration, I think we will start to see many successful startups and some of the more adventurous Rubyists switching to Elixir as their secret weapon.
Perhaps a better question would be, what is the best framework for a scalable app allowing for fast iteration, receiving high traffic and sending realtime updates?
As of 2017, that looks like Elixir/Phoenix.