A year of Elixir and Phoenix

A year’s worth of experience with Elixir. Mostly good, some bad.

A week to get proficient enough

When I first started writing Elixir (professionally, not as a hobby), I was blown away by how easy it was to get into it. It’s sufficient to say that I shipped my first production code on the second day.

Granted, I’ve been working in Ruby for a long time before that and I also played around with Elixir a bit, but still, shipping code on the second day says a lot about Elixir and Phoenix being optimised for programmer happiness.

The gift that keeps on giving

There are so many things working in favor of Elixir (on the web) that I sometimes doubt if programmers’ minds could have come up with something so simple. We programmers do tend to overcomplicate things.

First there are Phoenix and Ecto. For anyone coming from Rails, they’ll feel like home but without the messy storage basement. All neat and organised. Most of the things I didn’t like in Rails have been fixed in Phoenix — implicit view variables, lack of first-class DB constraints, non-transparent middleware, monkey patched core classes etc.

Second, there’s functional programming. While YMMV, I think it’s the best thing since sliced bread. Composing functions has much more sense to me than composing objects. Object composition results in a huge, mutable, potentially cyclic graph where any one object can pull the rug under any other object. Function composition is all about chaining functions into a pipeline and retaining the core behavior of receiving inputs and returning outputs.

Then there’s the whole actor model / concurrency thing. If you want to do an concurrent operation in Ruby or Python (like sending a sign-up email) you have to have a separate worker process and then somehow communicate between the main and the worker processes and also take care that the worker process restarts after a crash. You could of course just spin up a Thread, but then you’re just opening yourself up to a world of pain called thread safety.

In Elixir, you just spin up a Mailer module with a GenServerbehavior, put it under a supervisor and you’re done. Elixir and BEAM (Erlang’s VM) take care of messaging, process starting/restarting and everything else needed for concurrent computation.

Finally there are the already mentioned supervisors that make crashes much less painful, and make failure handling in concurrent contexts a solvable problem.

Mainstream viability

I first became interested in Functional Programming in early 2012. That year I attended several conferences where I got exposed to Elixir, Clojure and Haskell.

Shortly after, I started building toy projects in those languages to compare them and try to determine which one will take over the world of web development.

Now I think that the battle is over and the clear winner is Elixir.

Elixir is friendlier than Clojure and Haskell

It’s easy to see why.

Clojure is a dialect of Lisp, and while I don’t mind them, most people (find (parens ugly))). Clojure is also built on top of the JVM. People fall into one of two camps with regards to this topic. One camp loves the fact that there’s safety of JVM underneath it all while the other camp hates the memory consumption, the boot up time, the enterprise nature of the platform etc. — I think you can see which camp I’m in. In any case, I think the probability of Clojure ever becoming a mainstream language is low.

Haskell on the other hand, while beautiful, elegant and extremely safe is really hard to get into. Try building anything except a parser combinator library and you’ll see why. The fact that it is so hard to learn is not a bad thing per se, but it is detrimental to its adoption and its viability as a mainstream language.

Elixir obsoletes Ruby, Python and Node all in one swoop

Since then, I’ve had the chance to work in Node and Python and I think that as far as backend web development goes, no other mainstream language comes close to Elixir.

It’s not that I’m blind in love with Elixir, I just think that BEAM is the most future proof platform you could build your backend on. It already stood the test of time (it’s 30 years old after all) and its features are only now beginning to stand out — all caused by the needs and wants of real time web apps.

Ruby and Python look and feel nice but they can’t keep up with modern web development trends — mainly concurrency. Their internals are just not up to par with BEAM. I just need to mention the GIL to paint a picture of the state of concurrent computation in those languages.

Node offers similar features (async capabilities, native web-socket support), but it’s still single threaded so if you want to fully utilise your CPU, you’ll have to DIY. Not to mention that the language foundations are shaky at best and crumbling at its worst.

The toolbox

If you’re the type to shoot a Rubygems/PIP search faster than it takes me to pronounce “asynchronous computation”, you will find that Elixir doesn’t provide all the goodies you’ll find in Ruby/Python land. If not, you’ll find that you have almost anything you need in Elixir.:

  • Phoenix (web MVC),
  • Ecto (DB wrapper, query builder),
  • Guardian (auth), Ueberauth (OAuth)
  • ExUnit (tests), ExMachina (test data),
  • a lot of other libs.

In other words you have everything you need to build a production ready backend service.

Functional thinking

The only aspect of Elixir I’m not completely satisfied with is that it doesn’t force you to think functionally, not the way Haskell and Clojure do at least. You’ll find that you can mostly take your old way of thinking from Ruby or Python and use it, word-for-word, in Elixir, at least if you stay within the confines of Phoenix.

If this doesn’t sound bad to you, just remember C++ and the way it superseded C. People basically kept writing C in C++ (which is not a bad thing — just a fact).

This, of course, is not really Elixir’s fault, but give people a hammer and they’ll find a way to build a gun and then shoot themselves in the foot. To me, a well designed language should encourage you to adopt its way of thinking. It should be almost like a framework for thinking problems through.

I think that, with time, we’ll se more and more functional patterns being adopted in Elixir — such as combinator libraries, monadic (or railway oriented) APIs etc.

Hopes and dreams

Up till now, I’ve used Elixir only for building web apps. My hope is that I’ll find an interesting (non web app related) problem to solve with Elixir in the future and, by doing so, really get to explore the language and its full power in a deeper sense.