Flavius Popan

REPL Driven Development in Elixir

My neovim dev setup with iex auto_reload

When I save a source file (left), a file watcher (bottom right) recompiles my project and auto-reloads my iex session (top right) so I can instantly use new functions with existing variables. It's a blissful experience and helps keep me locked in flow.

Here's how to replicate my setup:

1. Enable auto_reload

Run-in-app's-root-dir (1) After running mix new to spin up a new project directory, I have the following snippet saved in my clipboard manager to quickly create a new iex config file in the root directory:

echo "IEx.configure(auto_reload: true)" > .iex.exs

This enables the feature permanently in a given project. If you'd like to set it temporarily for testing, run it directly in iex:

iex> IEx.configure(auto_reload: true)

2. Set a filesystem watcher

Run-in-app's-root-dir (1) Next you'll need a program to watch for file changes and then retrigger mix compile. For this, I use fswatch (installed via brew install fswatch) with the following args to look for changes in lib/:

fswatch -o lib/ | xargs -n1 -I{} mix compile

This will run the process until you cancel with ctrl+c, so I have a dedicated pane open to watch the watcher.

You can set yourself up for success by aliasing this in your .bashrc/.zshrc file via:

alias iexr='fswatch -o lib/ | xargs -n1 -I{} mix compile'

3. Fire up iex!

Run-in-app's-root-dir Lastly, run iex -S mix in another window to load your entire app and start calling modules & functions! I've been using this to great effect with "Elixir in Action" to learn about Structs.

BONUS: Works for mix test too!

I'm a fan of Test-Driven Development (TDD) so I have the following alias for watching for test file changes and rerunning them as I'm writing new tests:

alias iext='fswatch -o test/ | xargs -n1 -I{} mix test

It's not perfect, sometimes they run twice because of temporary file writes in vim but for small tests it's fine. The more robust solution is to use the mix-test.watch package, but the alias above saves you from installing & configuring a new package every time you start a new project.

Which happens often when you're learning.

Inspired by Clojure

After coming across a great article about why someone would choose Clojure, I was captivated by the idea of interactive development, aka REPL driven development:

"At the heart of Clojure development however lies the practice of interactive development. Before a single letter is written, the Clojure programmer starts up the Clojure runtime, which is connected to their editor. From here a program is "grown" by writing/running small pieces of it, and seeing the result (or error), directly and immediately, without leaving the editor."

That sounds like a dream come true but I'm not forking my elixir rabbit hole to go chasing brackets. Hopefully one day the elixir compiler is fast enough to support such a blessed workflow.

My Setup

For the curious, I'm using Warp as my main terminal and have so many great things to say about it, which I likely will with a later post. Use the link above to take it for a spin using my referral code so we can both get exclusive themes and goodies.

I'm also using neovim as my editor in the screenshot above, but usually I'm in VS Code. For simple tutorials, neovim is more than enough and this setup is very compact with all 3 terminals on a single pane. I have yet to integrate an LSP for neovim. Stay tuned.

Credits

This post was heavily inspired by Arrowsmith Lab's post on the auto_reload feature. Give it a read for more in-depth details. My guide differs in the way filesystem changes are detected, with theirs using:

Run-in-app's-root-dir (1)

Both entr and fswatch are similar, but I prefer fswatch because it saves you from having to init a new git repo and manually add files when you're writing a ton of disposable tutorial code.

Thanks for your attention & happy hacking!

#elixir