Functional Architecture in Elixir

I did a talk about exactly that a few weeks ago at RubyConf AU (not Elixir, but it’s mostly translatable).

The code is sort of usable, but more demo code for talking through. I’ve almost got it polished up (with tests etc), and will blog about it in a bit more detail soon.

(TL;DR - you can use free monads as a solution to separate functional core / imperative shell)

If you’ve got a simple “input → pure logic → output” problem, functional core is easy - because it’s just plain old functions. However in the case where you have to go up and down through the shell/core it gets trickier.

The worked example in my talk was code that gets data from an external API, iterates over it, then for each item has to query the DB to decide on action to take - so something that doesn’t fit the simple functional approach, as you’ve got lots of side effects intermingled with business logic.

The approach I showed was turning side effects into values in the functional core to returning. The effect values have enough data to call the side effect, and a function to then call next with the result of the side effect once it is executed by the shell. This way you can build up a recursive functional data structure representing the chain of actions (with iteration/branching etc as required) without actually having to execute any side effects - this makes texting super easy to decouple side effects from your core business logic.

The functional core only builds those values, but doesn’t execute them. The shell then receives them as the return value from calling the core and actually carries them out. As it executes each one, it calls the next function for that action defined in the core. The shell then only has to be a bunch of independent service functions for executing effects and applying them to the effect values.

The shell has zero business logic, but can do side effects, while the core is nothing BUT business logic, and with no code for executing side effects at all.

3 Likes