Elixir Makes You Make Good Decisions
Kevin Barrett on 2025-03-14
A month ago my cofounder and I launched screen.garden, a sync and multiplayer collaboration backend for Obsidian that also allows access to your vault from the web. It was a nights-and-weekends thing for us, the kind of project that steals sleep from the pure joy of working on it. We chose Elixir and Phoenix as the language/framework for building it, and now that we’re a month out I’m convinced that Elixir (and Phoenix, and Ecto, and…) makes you make make good decisions.
I am a programmer. I’m in the business of making bad coding decisions, it’s sort of our whole thing. Staring at code written six months ago and saying out loud what idiot wrote this? only to discover the idiot was you is, I’m pretty sure, a required credit in every CS program worldwide. But it’s eerie how solid our early architectural and structural decisions have been, how every dependency has been, well, dependable, and how easy shipping new features is.
let_me show you an example
Here‘s an example. In the early days of building screen.garden
we had a pretty standard Phoenix LiveView app—contexts, views,
Ecto schemas, etc.—and we realized that we needed some way to
authorize user actions at the boundary between views and
contexts. Say you’re a user on a team that has some notes and
you want to load one of those notes and start editing it. We
needed a simple, replicable way to answer the question, “should
actor
have verb
access to
noun
? Sure, you can get there with lots of little
database selects littered around your codebase, but there must
be a way to cleanly abstract that, right?
I searched around a bit and found let_me, an excellent authorization library that transforms your ad-hoc authz checks into a DSL:
object :note do
action :read do
allow :is_member
allow password: [:edit, :read], note_access: :password
allow note_access: :public
end
end
Given that policy, here’s how we check if
current_user
can read a note:
with :ok <- Policy.authorize(:note_read, current_user, note) do
# Go ahead and load the note
end
The brilliant thing about let_me is that it delegates the actual authorization checks to a module of functions that you can alter at will. This meant, for us, that when we decided to radically rewrite our access model our contexts did not change. We’re currently testing out a private collections feature internally, and building it was as simple as adding some Ecto schemas and let_me checks—again, no spaghetti code.
The power of the community
A common criticism of Elixir is that there is no waiting buffet of out-of-the-box deps; that because its community is small there are less options for tooling, dependencies, frontend components—the “TypeScript and React” argument.
I would like to counter this with another example. Our highest priority after launching screen.garden was adding support for file sync: we had fine-grained, realtime Markdown with multiple cursors, but the instant you dropped an image into your note you’d have to sync it elsewhere. So a couple of weeks after launch, once the initial flurry of talking about we’d built subsided, my cofounder Sloane started designing an architecture to support file sync. She wanted to leverage as much of AWS’ native eventing as we could, and then found that Broadway had an SQS adapter, and of course Oban Web is now free…and suddenly in a week we had end-to-end file sync with retries, backpressure, and sequencing that we could watch move through our backend in realtime:

It’s hard to overstate just how powerful you feel with the toolbox Elixir and the BEAM give you.
Real nice SaaS platform you got there,,,would be a shame if someone,,,,,,,tested it
I love writing tests in Elixir.
Let me reiterate what I said up top: I am pretty much your bog-standard programmer. I am the statistical mode of software engineers. If you say “estimate this ticket,” I say “between one week and two months.” If you say “jump,” I say “I’d really rather not.” I cannot recall a single time in my entire career prior to Elixir—across Java, Objective-C, Swift, Ruby, TypeScript, Go, to pick a few at random—that I was eager to write unit tests. And yet the instant I finish wiring up my Ecto schemas to a context I am thrilled to write ExUnit tests.
The entire test framework is biased toward making testing as
fast to author and as easy to design as possible. The mix
generators scaffold tests for you. setup
hooks and
fixtures make it trivial to test against your actual schemas.
assert
and refute
do what you mean, which sounds like a baseline testing
requirement but I promise you is really not how much of the
testing world works. It just feels good, and is a good decision
to make, and Elixir makes me make it.
(Korok sound)
My kid and I recently played through both The Legend of Zelda: Breath of the Wild and its sequel, Tears of the Kingdom. In these games there are little leafchildren, Koroks, playing hide and seek throughout the world, often requiring you to solve little puzzles to discover them. These are the sidest of sidequests: completely optional. Tiny dopamine hits. For me, unlocking problems via Elixir feels a lot like finding Koroks—a puzzle piece slots into place, a little trill of horn plays (at least in my head as I stare at my editor), and the world is very slightly repaired.
If you’re a screen.garden user, this is why we’ve been able to ship a steady drumbeat of features and fixes since launch. And if you’re not, please check it out—I’m so proud of what we built, both in terms of the service itself and what you can’t see, running on our servers, in happy and helpful world of Elixir.