TLDR - summary
During the last year I liked functional programming, the Elixir language, the community, parallel tests, the fast workflow, the dependency management and the powerful platform. I had troubles with Erlangs cryptic error messages, IDE support, code density and deployments. My excitement for Elixir is still as high!
What I did in 2017
Before reflecting on how I liked things in Elixir land, I like to summarize what I actually did.
After watching screencast series and doing exercises mentioned in the blog post one year ago I have read the following books:
- Elixir in Action by Saša Jurić
- Functional Web Development with Elixir, OTP, and Phoenix by Lance Halvorsen
- Learn Functional Programming with Elixir by Ulisses Almeida
- Craft GraphQL APIs in Elixir with Absinthe (beta) by Bruce Williams and Ben Wilson
- Adopting Elixir (beta) by Ben Marx, José Valim, Bruce Tate
Out of these books I found Elixir in Action the most challenging (in a good way) and inspiring. In a way that’s also because it was one of the first books I’ve read. Which means that some content was repeated in other books. For GraphQL specifically I really liked what’s already available in “Craft GraphQL APIs in Elixir with Absinthe (beta)”.
Playlists of Elixir conference talks I watched:
My preferred way to learn new technologies is to solve problems that I see.
This brings two things: having a solution to a problem and learning about different aspects of a technology. These aspects are for me: development speed, testability, maintainability, reliability and observability in production, community support, tooling support and performance.
The first side-project was about solving a problem I saw at work. I saw a need for a Planning Poker tool that integrates with Jira. The tool called Estimator is used since June regularly, about every 1-2 weeks by two teams. Here is a demo:
What I did during this side-project:
- Soft realtime synchronisation of data via websockets
- Authentication via Github
- Deploying to Heroku
- Database usage via Ecto: schemas, migrations, queries
- Using external APIs (Jira)
- Caching data across requests
- Continuous integration setup
- A little bit about automated testing
The second side-project is a tool to make it easier to order ingredients at a home delivery supermarket. Picape holds a mapping of recipes and their ingredients to products from a supermarket. For the last 3 months, we are using the tool twice a week. Here is a demo:
What I did during this side-project:
- Building a GraphQL API in Elixir
- Automated parallel testing of GraphQL, databases and websockets
- Structuring an application using Phoenix Contexts
- Deploying on a VPS (virtual private server) with git push
- Integrating Sentry for error tracking and Timber for logs
- Code coverage with Codecov
What I liked
There are many small details that I liked. When looking at the whole year I would mention these points in particular:
Once I was used to the pipeline operator
|>, pattern matching and the
with statement I started to miss it in other languages.
with statement I find particularly nice because it simplifies error handling in a sequence of function calls. There is a great explanation and example on StackOverflow.
I was hanging out in Slack channels, read blog posts and some forums. What I consistently noticed is how friendly, helpful and open the community is. I’m not saying that other communities are less good. Just that Elixirs community is at least as good.
My phone has 6 CPU cores. Looking at the increase of cores in devices over the last years makes parallelism in programming more important. One area where leveraging parallelism is great, is running automated tests in Elixir. Especially integration tests with databases.
As projects grow, their automated tests get slower. It takes a constant effort to keep the test times low, to be able to move fast. This is still the case with Elixir, but using all available resources without having developers caring about it can minimize this effort.
Developing in Elixir using the web framework Phoenix feels very similar to using PHP. Code changes don’t need a server restart like in NodeJS. I like how live reloading on code changes comes out of the box, making the developer experience even better.
Using Mix with hex to install and update library dependencies is a pleasure. It is fast, customizable, reliable and gives helpful instructions in case of conflicts. Especially compared to Composer, a PHP dependency manager, I found this a much better experience. Don’t get me wrong, I still think Composer is a great software and transformed the PHP world a few years ago.
I’m repeating a bit what I mentioned last year but I still want to stress the importance of running Erlang under the hood. The following comparison shows what I mean:
All components are solid. Apart from a PostgreSQL database I had no infrastructure setup. This is great for development and production simplicity. Note that you can still use software like Redis, Memcached, Cron etc if needed. Some examples:
- Adding a “cronjob”
- Adding a reverse proxy
- Adding caching across requests (using ETS under the hood):
ConCache.get_or_store(:bucket, key, fn() -> compute(key) end)
What I didn’t like
Like with everything, there are some cons. Or I didn’t understand it well enough yet.
Erlang’s cryptic error messages
Searching for this reveals some error messages like
(ArithmeticError) bad argument in arithmetic expression. Those I find hard to make sense of. I like that Elixir core developers are contributing to Erlang to improve this: example.
Elixir is a very nice language and it is very expressive. This expressiveness means that code can get dense. Especially when pattern matching is new to someone.
To not step on anyones toes, let’s look at some code I wrote last year. It’s an exercise on exercism.io. A function that returns whether the first list is a sublist or a superlist of a second list, and if not whether it is equal or unequal to the second list. Here my solution using pattern matching on function definitions and recursion. This is performant but I find it also hard to see what’s happening.
I felt it was too hard to read for my future self and picked up an idea from another solution for this problem not using recursion. This is much slower but in my opinion easier to read.
My point here is: I like the expressiveness of Elixir. When trying to pack too much information in a piece of code it can become too dense though.
Deployments could be better supported out of the box. The best experience was deploying to Heroku, this works great.
For Picape I could not use Heroku however because I wanted to separate the frontend (running on NodeJS, using next.js) and backend (Elixir/Erlang process) but keep the simplicity of one repository. I ended up with starting a NodeJS process when starting Elixir/Erlang. On Heroku I had issues opening multiple ports and get the forwarding working.
Deploying to my VPS was easy but I had to do some scripting and find out how to restart the Elixir process. This is by no means a zero downtime deployment. I would love to learn a way how to do this properly.
I’m very happy to have learned Elixir and I’m planning to learn more. I think it helps me to become a better developer. It’s awesome to see that so many great people are working on Elixir and improving it.