To elaborate with an example of my own, this I consider noisy code that over-compensates for something we can avoid:
defmodule Accept.List do
def work(nil), do: {:error, :invalid}
def work([]), do: {:ok, :nothing_to_do}
def work([first | rest]), do: {:ok, :we_have_done_stuff}
end
This introduces two problems:
- We have to think of a return value (or a logging event, APM notification etc.) for when stuff is
nil
when it should not benil
. Mind you, this might be desirable for some projects and Iāve been part of them. When this is something you are interested in then yes the above code is good. Has been a rarity in my practice but I recognize that it does happen. - We pollute this (and likely other) module with
nil
clauses for functions when itās very likely we can protect againstnil
(or convert it to a default empty value e.g.[]
for lists) at the call-site e.g.list_or_nil |> List.wrap() |> Accept.List.work()
.
Whereas, if we remove the nil
clause above weāll make our caller blow up with an error, thus making it very clear that weāve made a mistake (vs. logging stuff or putting a non-fatal message in an APM system might not draw the programmerās attention). Whether that mistake can be worked around with a default value or thatās truly an error depends on the project but Iād still prefer to āhearā about an invalid input to my function(s).
Of course this is all bike-shedding, more or less. Iām still defaulting to things blowing up vs. doing too much defensive programming and ending up with code that has no idea what to do with the hot potato when it lands on its lap.