How to build multiple web apps with Elixir thanks to umbrella — part 1: Why Elixir ?

A (wannabe) guide to learn how to create web apps with Elixir 1.9, Phoenix 1.4, Docker (for development), Git (including submodules) to version each app, PostgresQL, Redis, API calls and deployment.

Cédric Paumard
7 min readApr 3, 2018

--

This guide is addressed to developers who have a few projects behind them and are willing to give a try to Elixir. This first part will be about my theoretical vision. I may be wrong on some points, so don’t hesitate to read other articles.

Summary

New! You can now find the sources here: https://github.com/aridjar-umbrella-guide/medium_umbrella! I’ll upgrade them at the same time I upgrade the guide!

In this first chapter, you will read about Elixir, but won’t have any code to write. The purpose of this chapter is to help you make a decision about using it or not, either for a project or just by curiosity.

Why Elixir ?

The first version of Elixir as been around since 2011. It is part of the three new languages I heard a lot about since 2016, with Clojure (early 2009) and Go (late 2009). Each of theses languages came with advantages in comparison to other existing one, from Java to Python, and passing by PHP, JavaScript or even C/C++.

Before diving into the reason to choose Elixir for most of your new web projects, let me introduce myself: I am a young developer from a French school called Epitech. I worked as a web freelancer for almost 4 years now, and was developer evangelist at Mailjet for some month, working on a lot of different languages: PHP, JS, Ruby, Go, Java, Python…

I worked for many months on a web app based on Elixir to create my startup. Stopped a little, then got back in it, which is why I modified this tutorial.

The project is about news, so it involves two things:

  • Important scalability (lot of news to get and process for a lot of people)
  • Real time (as news aren’t so new after few hours)

Both are important focus in today’s web development, and that since a few years. That’s an important reason why Javascript (with node) got so popular: it was, during a long time, the only language which was providing both without a lot of work to do, unlike unlike C++ or Java.

But today, things have changed. Elixir, which is based on Erlang, provides real time and scalability. It also keeps a code readable and simple thanks to the ruby syntax it use as inspiration. But don’t get me wrong here: it stays a functional programming language, which means you need a different mindset in comparison to class or imperative programming, usually used for web development. But it definitely has some advantages.

Functional programming languages: a word about it

From Wikipedia:

In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data

So, there are a few key words in this definition: the mathematical aspect, the importance of function, and the immutability of data. So far, with Elixir, my lack of mathematical knowledge wasn’t a problem (I am not particularly good at math and didn’t have any lesson since my last day in high school). Which lead us to the function oriented aspect.

Function oriented

In most languages paradigm, you work with function. They may take some arguments, they process them with conditions and loop, and then they may return a variable.

In a functional language, you generally don’t process the data inside the function, as you can create multiple function with the same name (kinda like in C++). It is what we call multimethods.

The different aspect is that you generally can use the notion of pattern matching (which allow you to deconstruct your structures/arrays, assigns variable name to specific data and compare specific data). Based on this, having just a true or a false inside the definition of the function’s argument allows you to have two different functions.

Pure functions

From Wikipedia:

A pure function is a function where the return value is only determined by its input values, without observable side effects

As the definition says, it’ll always return the same value for the same arguments. Which means it can’t interact with databases, API or even take the date as the data you get from them may change over time.

A pure functions as many advantages:

  • it is easy to test and debug (as it’ll always return the same result)
  • it allows you to save computation time, thanks to memoization (not a typo ! Saving the result of the function so you don’t process it twice with the same arguments)
  • it is easy to combine, to parallelize and to reason with as you already know the result depending on the data (like multiplications)

Because pure functions are easy to combine, to parallelize and to reason with, they should do only one thing (for example, the addition of two int numbers) and should be named properly (add_two_int(nb1, nb2)), making the code which use them easy to read as the function name is enough to understand what it does.

We can’t make 100% of our function pure, but the more, the better.

Immutability

In most functional languages, variable are immutable. That means you can’t change a variable’s data once it is set. They are sort of constant variables.

Said like that, it doesn’t look so sexy. For example, how can you increment in a loop ? Well… The only loop you can naturally use are recursive function.

The way you increment/decrement a counter in a recursive function is by calling the same function it is in, with a different argument. This call must be under a condition, and where the argument doesn’t met the condition, there is no more call made, making the loop terminate. Here is an example:

Once you get used to immutable data, they are easy to reason with, as they don’t change. There is no fear to have about external modification (for globals), or having your variable changed because of a pointer in an obscure, not pure function.

They also are thread-safe, can be shared easily by reference, and are really easy to debug as their is only one state to take care off.

Don’t get me wrong. Mutability as it’s own advantages. They just doesn’t help to focus on functional approach.

Erlang: what is it ?

Erlang is a battle tested language, made by Joe Armstrong and Ericsson, and used for some technology, such as phone communication, RabbitMQ, WhatsApp, Amazon (for EC2)…

From Wikipedia:

Erlang is a general-purpose, concurrent, functional programming language, as well as a garbage-collected runtime system.

As Erlang was designed with the aim of improving the development of telephony applications, it is oriented to handle a high concurrency and high availability. And it kind of rules it, as it handles the nine “9”s of downtime per year, which is 31.56 milliseconds of downtime.

Beam (Erlang VM)

Beam is the Erlang’s virtual machine. It as many strengths, but the one I like the most is the process manager. Almost everything in Erlang is a process, but not an expensive to launch, high usage memory process.

Erlang’s processes are really lightweight, easy to start and to stop. Each of them can communicate with each other through messages. These processes allow high concurrency as each process can handle a specific task. It’s not uncommon to find tens, even hundred of thousands process running simultaneously.

Having so much process create the need for an unusual garbage collector. And it kinda is because the garbage collection is per process:

Each Erlang process has its own stack and heap

Note: unfortunatly, I don’t know enough the garbage collector to explain you in one short paragraph why it is good or how it achieve that. But I found some stuff if you want to read about it: the official documentation and a good article from Hamidreza Soleimani’s blog.

Finally, and more importantly, Beam is fault tolerant: if a process as an unhandled error, it just stops and may relaunch itself, without interrupting the entire program.

Elixir: how does it looks ?

Elixir’s syntax is inspired from Ruby. You’ll have lots of common elements, from the function declaration to the Enumerable module, with the “do end” principle and a similar way to tests. You already saw a few lines in this article, so, here are two of the really good features coming with Elixir:

Pipe

The pipe is like the Unix pipe. It allow to take the variable place before the pipe and pass it as the first argument to the function after the pipe. As you can imagine, because functions always return data, you can pipe them like you chain setters function in some object languages.

Which is the easier to read? I personally go for pipes.

Pattern matching

From Wikipedia:

In computer science, pattern matching is the act of checking a given sequence of tokens for the presence of the constituents of some pattern

In Elixir, this allows us to separate the comportment of a condition in different function (1), to access easily some data in a map or a keyword list (2), to check the return of a function with keywords (3), etc.

As we can see, the pattern matching allows to do diligent things. There is also multiple type (such as :string) which is a string saved in memory and called an atom. They allow the comparison of the address directly, saving memory space and computation time. There is also the string concatenation with the “#{var}”, a struct, and other nice elements.

I hope this first tutorial pleased you and helped you figure out what are the main advantages of Elixir.

In the next guide, we will set up an umbrella project, which is an app managing multiple apps. It is basically oriented for micro services. We also will create a docker-compose to store our databases and host the elixir server. Finally, we will manage every version with Git submodules.

Let’s dive in!

Edit 18/03/2019: Change Elixir version from 1.6 to 1.8 and Phoenix version from 1.3 to 1.4, and add two paragraphs and minors changes.

Edit 03/08/2019: Change Elixir version from 1.8 to 1.9

--

--

Cédric Paumard

Elixir developer, bass player and probably too curious.