Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save chanlito/9f144c82f55d550c79a80fa08c100132 to your computer and use it in GitHub Desktop.

Select an option

Save chanlito/9f144c82f55d550c79a80fa08c100132 to your computer and use it in GitHub Desktop.
5 Elixir patterns I wish every language had

5 Elixir Patterns I Wish Every Language Had

Some languages make you feel clever. Elixir makes you feel like the codebase might survive you.

1. Pattern matching as a normal control-flow tool

case result do
  {:ok, user} -> {:ok, user.email}
  {:error, :not_found} -> {:error, "user missing"}
  {:error, reason} -> {:error, reason}
end

In Elixir, the shape of the data is the logic.

Why this is unfair:

  • branches are explicit
  • less defensive noise
  • failures become part of the design, not an afterthought

2. The pipe operator turning transformations into a story

user
|> normalize()
|> validate()
|> persist()
|> broadcast_created()

You read it once and know what the code is trying to do.

Why this is unfair:

  • encourages small focused functions
  • flow stays visible
  • complex logic becomes easier to scan than nested calls

3. Tagged tuples for boring, sane error handling

def create_user(params) do
  with {:ok, attrs} <- validate(params),
       {:ok, user} <- insert_user(attrs),
       {:ok, _job} <- enqueue_welcome_email(user) do
    {:ok, user}
  end
end

{:ok, value} / {:error, reason} is one of those ideas that looks simple until you realize how much chaos it prevents.

Why this is unfair:

  • success and failure are both visible
  • no exception-driven guessing
  • the convention scales across a whole codebase

4. Function heads that branch by shape, not by drama

def access_level(%{role: :admin}), do: :full
def access_level(%{role: :editor}), do: :limited
def access_level(_), do: :read_only

Instead of burying logic inside conditionals, Elixir lets you put it right on the surface.

Why this is unfair:

  • intent is obvious immediately
  • less branching noise
  • related behavior stays grouped together cleanly

5. Lightweight processes that make isolation the default

spawn(fn -> loop(%{count: 0}) end)

Elixir does something rare: it makes concurrency feel architectural instead of terrifying.

Why this is unfair:

  • isolated state instead of shared-state drama
  • failure can stay local
  • systems are easier to reason about under load

Final thought

Elixir's real flex is not that it can do powerful things.

It's that it makes the correct, maintainable version of the code feel like the natural one to write.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment