Elixir can be a beautiful language, it has Ruby’s syntactic elegance, Lisp’s metaprogramming, and many functional features of languages like F#. The user has license to use many idioms and features: pattern matching, macros, behaviours, protocols, GenServers, ETS, etc. Working successfully in Elixir means choosing when to leverage a particular language feature for its ergonomics at the cost of grokking its complexity.
Typically, beginners are advised to organize their Elixir/Phoenix codebases into modules and functions. Write well named functions, and group functions with related concerns into modules. In a functional language like Elixir, writing functions that operate on raw data takes you far. Phoenix 1.3 even
A developer can think of modules and functions as the simplest tools in their Elixir tool belt. When working on larger projects or designing a library, patterns may start to emerge that be solved more ergonomically or efficiently utilizing more powerful language features. In this post, I’ll explore a source of complexity we encountered at The Outline
and how we reduced the complexity by going beyond modules and functions.