Quick & Easy Elixir Refactorings — Part 2

Functions ending with a conditional

Ville
3 min readNov 25, 2017

Last time we looked at using pattern matching instead of starting our functions with conditionals. If you haven’t checked it out yet you can find it here: Quick & Easy Elixir Refactorings — Part 1

This time we’ll look at a super simple technique you can use to remove the conditional from the end of your functions by extracting a function and next time we’ll deal with conditionals in the middle of your function.

All of these techniques by themselves may seem hardly worth it and not making a big difference but stay with me; I’m hoping in couple of posts time when we bring all these techniques together to move from an imperative style to a functional style it will all make sense.

Functions ending with a conditional

These functions as the title states finish up with a conditional statement, quite often these are found in a create or update action of a controller in a framework like Phoenix or wherever we are performing an operation and branching our logic with the result.

A typical example would be something like this

defmodule ExampleWeb.ExampleController do
use ExampleWeb, :controller
alias Example.Things
alias Example.ThingUpdater
def update(conn, %{"id" => id, "wibble" => wibble}) do
thing = Things.get(id)
case ThingUpdater.set_wibble(thing, wibble) do
{:ok, thing} ->
conn
|> put_flash("Huzzah!")
|> redirect to: thing_path(conn, :index)
{:error, message} ->
conn
|> put_flash(message)
|> render "edit.html"
end
end
end

We get a thing and attempt to update it and want to do something different depending on whether it succeeded or not.

Quite a bit happening for one function. What we could do is extract the conditional to a separate private function or two.

...
def update(conn, %{"id" => id, "wibble" => wibble}) do
thing = Things.get(id)
result = ThingUpdater.set_wibble(thing, wibble)
respond(conn, result)
end
defp respond(conn, {:ok, thing}) do
conn
|> put_flash("Huzzah!")
|> redirect to: thing_path(conn, :index)
end
defp respond(conn, {:error, message}) do
conn
|> put_flash(message)
|> render "edit.html"
end
...

I’ve omitted the beginning and end of the module which have not changed. Just by capturing the result and pattern matching it in the function signatures this already feels a bit neater to me.

If we swap around the arguments for our new respond/2 function however we can get rid of the unnecessary assigning and use the pipeline operator to tidy this up even further

def update(conn, %{"id" => id, "wibble" => wibble}) do
Things.get(id)
|> ThingUpdater.set_wibble(wibble)
|> respond(conn)
end
def respond({:ok, thing}, conn) do
conn
|> put_flash("Huzzah!")
|> redirect to: thing_path(conn, :index)
end
def respond({:error, message}, conn) do
conn
|> put_flash(message)
|> render "edit.html", thing: thing
end

If your functions are ending with conditionals try the technique above and see if you can split your function that deals with many things to smaller more focused chunks and use pattern matching to eliminate the conditional altogether.

Bonus of doing this is that it also makes it easier and neater to use pipelines to describe the flow 😍

Please do click the 👏 icon below if you liked this post and follow me here or on Twitter @efexen to be notified of the next part where we’ll look at more simple tricks for leveling up your Elixir code 👍

Next: Quick & Easy Elixir Refactorings — Part 3

--

--

Ville

Freelance Developer • Founder of @CodeHalf • Rubyist • Elixir Alchemist • Wannabe Data Scientist • Dad