paint-brush
Quick & Easy Elixir Refactorings — Part 4by@efexen
639 reads
639 reads

Quick & Easy Elixir Refactorings — Part 4

by Ville HellmanDecember 2nd, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In the previous part we looked at how to refactor away conditionals in the middle of your functions by passing in a function instead. Before that we looked at <a href="https://hackernoon.com/tagged/refactoring" target="_blank">refactoring</a> away conditionals at the beginning and end of your functions.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Quick & Easy Elixir Refactorings — Part 4
Ville Hellman HackerNoon profile picture

Nested conditionals

In the previous part we looked at how to refactor away conditionals in the middle of your functions by passing in a function instead. Before that we looked at refactoring away conditionals at the beginning and end of your functions.

If you’ve not read through the series yet I recommend you start from the beginning



Part 1 — Functions starting with a conditionalPart 2 — Functions ending with a conditionalPart 3 — Conditionals in the middle

In this post we will look at a way to deal with nested conditionals. One could be forgiven for thinking I don’t like conditionals by this point 😉

Nested conditionals

Nested conditionals are a far bigger problem in other languages and usually tend to be caused by having functions that are just too long and should already be split up but there are times when these come up and it’d be nice to have a concise way of dealing with them.

An example could be something like this

defmodule Example do













def authorised?(user) docase UserAuthenticator.authorised?(user) do{:ok, _user} ->true{:error, _user} ->case LegacyUserAuthenticator.authorised?(user) do{:ok, _user} ->true{:error, _user} ->falseendendend

end

Not terribly elegant piece of code and slightly tricky to read as well. Imagine if instead of returning simple boolean we’d execute some longer piece of logic instead 😓

We could split up the authorised?/1 function to get rid of the nesting by doing something like this








def authorised?(user) docase UserAuthenticator.authorised?(user) do{:ok, _user} ->true{:error, _} ->legacy_authorized?(user)endend








defp legacy_authorized?(user) docase LegacyAuthenticator.authorised?(user) do{:ok, _user} ->true{:error, _} ->falseendend

Hooray no more nesting 🙌 And by using the techniques from earlier on in this series we could eliminate the conditionals altogether to get something like this





def authorised?(user) douser|> UserAuthenticator.authorised?()|> check_authorised()end






def check_authorised({:ok, _}), do: truedef check_authorised({:error, user}) douser|> LegacyAuthenticator.authorised?()|> check_legacy()end


def check_legacy({:ok, _}), do: truedef check_legacy(_), do: false

This is nice when you have nesting in both branches of the initial conditional as it allows you to split all of that up across lot of little functions.

Fortunately with our example we only have a nested conditional in one of the branches which allows us to look at an alternative using the the with statement








def authorised?(user) dowith {:error, _} <- UserAuthenticator.authorised?(user),{:error, _} <- LegacyAuthenticator.authorised?(user) dofalseelse{:ok, _} -> trueendend

😮 😍

What we’ve ended up with is technically still a conditional but compared to our alternatives above I think it’s a very elegant solution to the initial problem.

If you’re not familiar with the with statement I urge you to play around with it as it can make code that is expected to follow a certain happy path really easy to reason about and certainly clearer than bunch of nested conditionals.

Please click the applause icon 👏 if you liked this post and follow me here or on Twitter @efexen to find short actionable posts where we’ll look at more simple tricks for leveling up your Elixir code 👍