With/1 design patterns

instead of Map.fetch(params, :shoes)

design patterns

Following Scott Wlaschin’s guidance - use functions!

def fetch_item(map, key) do
  case Map.fetch(map, key) do
    :error ->
      {:error, key}
    result ->
      result
  end
end

  ...

  with(  
    {:ok, shoes} <- fetch_item(outfit, :shoes),
    {:ok, shirt} <- fetch_item(outfit, :shirt),
    {true, _} <- {shoes_match_shirt?(shoes, shirt), :matching}
  ) do
    {:ok, "service allowed"}
  else
    {:error, :shoes} ->
      {:error, "you forgot your shoes!"}
    _ ->
      :error
  end

  ...

or

def fetch_item(map, key, msg) when is_binary(msg) do
  case Map.fetch(map, key) do
    :error ->
      {:error, msg}
    result ->
      result
  end
end

  ...

  with(  
    {:ok, shoes} <- fetch_item(outfit, :shoes, "you forgot your shoes!"),
    {:ok, shirt} <- fetch_item(outfit, :shirt, "you forgot your shirt!"),
    {true, _} <- {shoes_match_shirt?(shoes, shirt), :matching}
  ) do
    {:ok, "service allowed"}
  else
    {:error, msg} = msg_error when is_binary(msg) ->
      msg_error
    _ ->
      :error
  end

  ...