sb logoToday I Learned

Living with-out

There is a tendency in Elixir to reach for the with macro to handle control flow.

def fetch_token(type, params \\ []) do
  with params <- Keyword.merge(required_get_token_params(type), params),
       {:ok, client} <- OAuth2.Client.get_token(client(type), params) do
    {:ok, client}
  else
    err -> err
  end
end

At first glance, this code looks succinct, clean, and readable. Then you realize two refactors

With returns the unmatched value by default

def fetch_token(type, params \\ []) do
  with params <- Keyword.merge(required_get_token_params(type), params),
       {:ok, client} <- OAuth2.Client.get_token(client(type), params) do
    {:ok, client}
  end
end

If there is no else condition, you don’t need to double match on the last clause.

def fetch_token(type, params \\ []) do
  with params <- Keyword.merge(required_get_token_params(type), params) do
       OAuth2.Client.get_token(client(type), params)
  end
end

After these two refactors, you realize that you never needed with in the first place!

def fetch_token(type, params \\ []) do
  params = Keyword.merge(required_get_token_params(type), params)

  OAuth2.Client.get_token(client(type), params)
end

Now, this may seem overly pedantic, but many bugs can hang out in the plain sight of verbose code. Eliminating branching in your code is a great strategy for reducing complexity.