With OTP, you have what we call a "supervision tree". Your software is divided into components (erlang processes) and organized in a tree where the leafs are your components, and the nodes are the "supervisors" which will catch the error, and restart/retry the operation.
What's the result? Imagine you have a component that is polling data from the database and then sending a message to another component based on that data. For a split second:
- there is a network error
- you lose the connection to the database
- the component crashes
- its supervisor notice the crash, restart the process
If the network error was temporary, everything goes back to normal, and your system did not stop for a temporary network error. And your component does not need to have "retry code" (it is delegated to the parent supervisor).If the network error was not temporary, the parent supervisor will notice that the component crashes far too often, and will decide to crash as a result. Letting the parent supervisor of the supervisor deal with the problem.
In Erlang/Elixir, processes can "monitor" other processes. They will receive a message when the target processes dies (normally, or abnormally). This allows you to delegate the error handling so yes, you write less defensive code, because that code is located in a dedicated component that will be notified automatically.
There is a limit to how defensive you can make your code. As soon as you call out to another service for data, the universe of errorinf situations they can create goes to infinity. For example they could happily send you a 200 but return mistyped JSON. What do you do in that case? Are you genuinely going to write that as a test condition to make sure the transactional chain in your system handles this and rolls back the db inserts that preceded it? I can tell you that in 99% of cases idiomatically written elixir will "do the right thing" if this happens, and that is a consequence of "let it fail" philosophy. Moreover, if you try to write error handling code in the traditional sense, you will probably get it wrong, it will be hard to understand, and it will be hard to debug if your implementation is not quite right.
Trying to continue this conversation is a waste of our time. Feel free not to use Elixir.
It is quite frustrating when someone has already decided something they don't know is dumb or makes no sense. It is more plausible the unknown unknowns are blinding your judgement, than Erlang and Elixir developers worldwide suffering a collective hallucination, is it not?
Empty your cup.
To me these phrases are more about the guarantees—if it does crash it recovers—and less about dogmatic advice that everyone follows.
But there's time and place for different levels of defensive programs. I get to pick and choose based on where I see risk, but I know the whole app isn't going to blow up if I missed something.