Currently working on a mobile application that we are building with Xamarin, I was considering different available platforms for building and operating the application’s back-end.
Normally, I would jump straight to a .NET based back-end except this time the back-end services that will support the mobile application are highly concurrent in nature and needs to maintain a full duplex connection via websockets with each device.
We (my business partner and I) finally chose to use the Elixir/Erlang platform for our back-end, in this post I am going to layout briefly what motivated this choice.
open telecom platform
OTP (open telecom platform) sounds like it is some switched telephone standard specification, actually it is a framework for building scalable and resilient distributed software systems.
Scalable means that we can distribute behavior across multiple nodes (physical or virtual machines) to acquire more capacity, resilient means that the system is up and running when failure events happen (power outages, software crashes…).
OTP is usually packed by default in the erlang basic installations and since elixir code compiles to the erlang’s vm bytecode it is effectively possible to use OTP from elixir.
real oo and concurrency model
Joe Armstrong, one of the creators of erlang, claims that erlang is the most object oriented language available thanks to its message passing mechanism.
Erlang’s concurrency model applies the shared nothing principle, in order to launch multiple behaviors concurrently you typically create an erlang process. Erlang Processes have some interesting characteristics:
- They are identified by a
- They do not share state between each other
- They can pass immutable state between each other via messaging
- They are very lightweight, it is possible to create a large number of processes in single erlang VM. (here very large is relative to the number of OS threads and processes that an Operating system can manage)
The GenServers OTP behavior, allows to create a generic server that asynchronously replies to requests defined by the programmer, GenServers typically wrap vanilla processes to add life-cycle management functions such as
GenServers are able as well to maintain state, this characteristic allows us to treat them as active objects to which we send messages defined via
handle_cast. Even if Elixir and Erlang are functional programming languages they do support OO encapsulation and data/behavior consolidation.
“let it crash”
Erlang’s excellent fault tolerance attributes stems from the “let is crash” principle, it is actually considered good practice to avoid coding defensively by not handling exceptions and by avoiding to anticipate failures in the software’s implementation.
The recommended approach is to assign a monitoring process for each running process when the running process crashes it gets restarted right away by the monitoring process. In OTP terms, you assign an OTP Supervisor to one or many OTP behaviors (GenServers for example), the Supervisor monitors the activity of the GenServer, when the Genserver crashes for some reason, the Supervisor executes a restart strategy that will typically restart the GenServer.
This principle allows us to build behaviors that are resilient to nearly any failure condition without requiring developers to anticipate most of them.
Highly disciplined developers will reap large benefits from this approach, which will allow them to address “next level shit” failure conditions.
hot code replacement
OTP defines a mechanism to deploy new versions of OTP behaviors without downtime, this allows us to basically avoid techniques such as blue/green deployment that requires failing over to replicated deployment in order to ensure availability when updating running services.
Why using Elixir instead of plain erlang? A couple of reasons:
- Elixir as a programming language seemed more approachable that erlang
- Elixir has a growing an healthy open source ecosystem with a seemingly state of the art web framework(Phoenix)
for loops and
But we are looking forward to master pattern matching and recursion.
The erlang runtime has been notoriously slow in number intensive CPU bound computations, but we are also looking forward to out-source intensive number crunching to golang code when needed.