This has been borne out by widespread adoption across the web development community.
I have the same feeling now about Elixir.
The moment I saw Elixir I knew it was the right framework for building web application backends. So much so that to a large extent I have staked my career on it.
However, when asked by other people “Why Elixir?” simply saying “it feels right” doesn’t carry much weight.
A feeling that cannot be put into words is not particularly persuasive or useful.
As I’ve worked with Elixir I’ve come to understand more the reasons that drew me to it in the first place. Erlang has some impressive concurrency performance characteristics but that’s not why I like it.
Elixir is a good language of choice because it combines the friendliness of Ruby with the production-ready reliability of Erlang.
In most languages there are tradeoffs. Erlang has impressive tools for building scalable, reliable systems but the syntax is crufty and the language lacks extensibility. Node.js is accessible to a large pool of developers but fails to deliver reliably at scale and requires tremendous discipline to keep the code maintainable. Ruby is friendly to beginners, wonderful to work with but suffers from a terrible concurrency story and poor performance. Clojure is powerful and has cutting edge concurrency but the syntax is formidable for beginners.
Elixir stands out as the only modern language I have used that has no tradeoffs. It is friendly to beginners, has a wonderful, expressive syntax, guides you towards maintainable code and has an excellent concurrency story.
And it’s getting better all the time. Just look at the original language goals:
These goals changed this year. Now they are:
It’s the little things that add up to make the language great.
- mix - like leiningen but better
mix test --stale- only runs tests that have been affected by code changes.
mix xref- compile time warnings for non-existent functions
- Compile-time warnings for unused functions, unused vars
- async stream
- iex breakpoints
- Wonderful exception messages
- Built-in testing framework - exunit
- Powerful macros
- Protocols for contracts
- Immutability and pattern matching
- Explicit vs. implicit (macros, no mutable state)
- Documentation as a first-class citizen (hexdocs)
- Malleable code due to lack of explicit typing
- Isolated processes and tasks
- Fault recovery with supervisors
- Easy distribution and clustering out of the box
We’ve been using Elixir for almost a year now in production at Nested and it has been an absolute dream to work with. Back in the days of Ruby I used to see PRs on a regular basis that were almost entirely dedicated to refactoring. I never see those any more.
I think this is because the language makes it so easy to delete and refactor code that the only time you need to do it is in the process of adding a new feature - which is really how it should be.
The soft real-time guarantees of the underlying Erlang VM are really handy too. You never need to worry about running a resource-intensive task on your cluster - it will not degrade the performance of your web requests.
Most of all, working in a language with no mutable data has been a revelation. It’s like someone was standing on your foot all these years as you had to remember that anything could be modified at any time. In Elixir that pressure is lifted from you, making the language lighter on your brain.
Elixir makes programming fun again. It handles the basics so well that you are free to focus your energy on the problem you are trying to solve, rather than working around idiosyncracies in your language or tooling.