We are always looking for new tools that can help us to grow as developers. Lately I have been learning about functional programming and how it can impact the code I write at large. During that quest, I found out about Elixir, a functional language that leverages the Erlang virtual machine.
Erlang is used for concurrent, fault-tolerant systems. Elixir can directly use Erlang libraries, and has a syntax that helps writing clear and concise code.
Obviously, being mainly a web developer, I started looking for web frameworks. I love Django (most of it), so that is my point of comparison. In elixir, the main web framework is named Phoenix. Why is it different? In their own words:
Phoenix brings back the simplicity and joy in writing modern web applications by mixing tried and true technologies with a fresh breeze of functional ideas.
Create rich, interactive experiences across browsers, native mobile apps, and embedded devices with our real-time streaming technology called Channels.
Phoenix leverages the Erlang VM ability to handle millions of connections alongside Elixir’s beautiful syntax and productive tooling for building fault-tolerant systems.
One of the things I highly dislike in Django is the channels project. It works, and it has been of great help on several projects, but it just feels like it was forced into the framework (It was). Phoenix has a similar technology (creatively named channels too) but it has been built along with the framework. It is so promising that they created LiveView. To put it simple, realtime server side rendering using websockets.
This was the point that made me go ahead and give Phoenix a chance. A way to make channels less painful? Please, I want some of that.
Once you have Elixir in place, the Hex package manager can be installed with:
And install the elixir mix archive with:
mix archive.install hex phx_new 1.4.10
The last command will install the mix tasks required to create your application.
Creating a Phoenix application
It is as simple as running:
mix phx.new hello
This will create the new folder “hello” which contains your whole project. It will also ask you if it should fetch dependencies. This includes installing the npm dependencies. Oh, forgot to mention that it comes with webpack preconfigured.
If you are one of those that don’t like webpack or prefer to set it up manually, you can just set the
--no-webpack option when creating a project.
The command will assume that we are going to use a Postgres database, but you can, just like with webpack, use something else by passing a flag:
The initial setup assumes that you have a user with the correct permissions and password “postgres”. If you don’t, you will need to tweak the configurations to use the right credentials.
Assuming that you are done with the trivial things (that should not take longer than 2 minutes), you can create the database and start your local development server:
mix ecto.create mix phx.server
You should see the following at http://localhost:4000:
Easy, right? When you started the server, you must have noticed that webpack is also started. No more proxy npm servers to setup (which is awesome).
Creating a simple CRUD
CRUD is the single, repetitive, boring and tedious task that we have to perform every time we create a new model. It is the communication with the newly created database entity.
We will create a simple database table, and ask Phoenix to help us a little with the initial part. We will do that using contexts. Contexts are just a way to separate the logic inside of your application.
We will create a table named users, in the context Accounts. We will do that with the following command:
mix phx.gen.html Accounts User users name:string username:string:unique
As you must have noticed, we tell Phoenix which fields we want, and what constraints they must have. Phoenix will create an Ecto schema. Ecto is the library used to communicate with databases, make queries, validate data, etc. The schema is used for validating data before sending it to the database (so, it is application level validation).
The command will also create a migration, which we must run to apply the changes to the database:
We also need to add the new resource to our urls, so we can navigate there. We can do so by modifying lib/hello_web/router.ex and adding:
scope "/", HelloWeb do ... resources "/users", UserController ... end
Now, let’s see what we have ready with this 2 minutes process:
- A database schema for validation of data
- A migration to apply the changes to the database
- A resource for the urls
Wait, in fact, that should mean that there must be something in those URLs (/users) already, right?
We have a basic, functional CRUD for free. Awesome, right? But there is more. phx.gen.json can help us if we are not creating regular html views, but if we are creating an API.
And there is one more thing that we get for free: tests. That’s right, we get the CRUD tests (among the boring, repetitive tasks that a CRUD represents, tests are the most boring). You can check them by going to test/hello_web/controllers/user_controller_test.exs and run them with:
You will now probably think: there are so many things that I will do differently and that I will need to modify…the tests are not even taking into account if the user is authenticated (just a random example).
And you will be right. The framework cannot think for you. However, out of the box we got so many things, that diving in to modify the default functionality will be faster than starting from scratch. And when we need a new table or functionality, we can just repeat the same process.
In Django, using Class Based Views it can still take some time to setup all of this. In phoenix all of this is explicit, and if you don’t need it, you can just remove the bits that are not of use to you. Removing is faster than adding (at least in this case).
I am still in love with Django. I have worked with it for a lot of years. However, Phoenix and Elixir deliver some nice features that make the technology stack interesting.
The good thing about functional programming, is that you can apply the learned concepts in any language. So, even if at the end of the day I don’t end up using Phoenix and Elixir, the concepts that I will be using there can give me more insight into what I am doing in other technologies, and will help me be a better developer.