Tasting the Elixir

The problem

We wanted to integrate with an external service, they would collect various metrics about our system so that the marketing team could do analytics on them.

The service provider we chose requested us to batch the requests so we wouldn’t sobrecargar their servers.

Choosing Elixir (esto le falta mucha cindor)

We are using rails, so when you think “I need a small server” in the ruby world everybody thinks Sinatra.

But this server would get a lot of traffic, and we don’t want to have the burden of making it scale and we’ve been wanting to try out elixir because we are having serious performance problems in our main app.

So we decided to make a small but functional Elixir POC, along this post I’ll share my experiences, good and bad, using Elixir, both the tools and the programming language.

Why would I want to use Elixir

From the elixir website:

Elixir is a dynamic, functional language designed for building scalable and maintainable applications.

This sums up Elixir pretty well, except for a key concept: All data is immutable in elixir. Immutability lets you think generally and know that calling a function on a value will never modify it.

Another important point of elixir is that it’s a very flexible language, it inherits from erlang a very powerful meta model se llama asi, capaz macro system es mejor. We will see how this results while writing actual code.

Getting our feet wet in Elixir

As we all now, starting a new project in an unfamiliar environment can be challenging. But as many new languages, they have the burden to make it easy for developers to get their tooling and as expected, I had no issues installing Elixir as their website indicates.

And here is when I’d like to do rails create, but luckily the elixir devs created a tool called mix that comes bundles with many useful tasks an can be extended by installed packages.

To create a new elixir project mix new $PROJECT will create a $PROJECT directory and populate it with all that you need to start creating whatever you want. This is really useful, specially considering that the architecture of elixir applications differ from most. Just like his father, Erlang, Elixir is based on the Actor Model, where everything is a process that share no state with any other process and they can send each other messages to get things done. For example, the app I’ll build will the http process (which actually has a lot of sub-processes inside) that talk to a ~batcher~ process, this process just waits until it has accumulated enough messages to send to the remote service.

With this simple example we see some of the usefulness of the model, both processes know nothing about each other or how they do their thing.You may say, “that’s normal encapsulation that I’d get from any object oriented language” and you’d be right.

Don’t use elixir.

The end.

The actor model

This post wouldn’t suffice to explain the actor model in its entirety so here is a definition taken from Actors paper

Actors is a model of concurrent computation for developing parallel, distributed and mobile systems. Each actor is an autonomous object that operates concurrently and asynchronously, receiving and sending messages to other actors, creating new actors, and updating its own local state. An actor system consists of a collection of actors, some of whom may send messages to, or receive messages from, actors outside the system.

As you may have notice, the actor model is very similar to the object oriented paradigm with a crucial difference, it was designed to deal with concurrency by default. On an OOP language it’s easy to cause race conditions by sending a message to an object in two different threads.

To solve this in the actor model changes the guarantee when sending a message:

  • An actor can process only one message at the same time
  • There is no guarantee on how long (if ever) a message will reach its target
  • All messages are asynchronous (although most runtimes implement some primitives for synchronous messages since they are so common in practice)

Side note about elixir syntax (quizá esto debería ser una seccion a parte)

In elixir, as in erlang, all functions have their arity in their names, for example send/0 is different to send/1, the arity on a method is defined at compile time and inferred from the way we use a function.

Symbols are used extensively to declare what something is (eg. a book can be represented with a tuple like {:book, "The lord of the Rings", "JRR Tolkien"}), as well as results of actions (eg. the result of parsing JSON from a string is {:ok, json_parsed}). Since you can pattern match it’s a lot easier to deal with them than to deal with a nil from a read_file function

The syntax for making tuples is using curly braces {some_value, another_value}

Back to the real world, elixir run on top of the ErlangVM which is a proven runtime for distributed computing using the actor model. Elixir inherits from erlang a module called GenServer which sets the most common routines for any proccess, this interface consists of:

  • init/1(some_arbitrary_data): called to get the initial state of the process
  • handle_call/3(message, sender, state): called to handle a synchronous message to this process, it should return a tuple with the form {action, new_state, response}, action usually is :reply (a symbol) indicating to respond to the sender.
  • handle_cast/2(message, state): called to handle an asynchronous message, it should return a tuple with the form {action, new_state}, action is usually :noreply indicating not to reply to the sender.