> The application that assumes that key "foo" is in the map, and crashes if it's not, is just as brittle
And the program that assumes that foo is a string when it's an integer yadda yadda yadda.
What's better, that code containing erroneous baseline assumptions about the data it's handling stays live, or that it safely aborts before it corrupts any of that data? All software must deal with errors at some point or another.
Take a web endpoint. If it is expecting a foo, and it instead gets bar, what is it intelligently supposed to do with that bar? We're squarely in the realm of a fatal error (to that request), the only question is how much boilerplate is going to be required to abort.
In most languages, the answer is endless validation and error handling at boundaries. In Erlang, on the other hand, such a function would simply crash. All Erlang code runs in green threads, usually overseen by supervisor trees. The supervisor tree organises the quick return of an appropriate error to the request, while it safely restarts the worker thread.
This kind of architecture requires no boilerplate or external libraries in Erlang or Elixir. It's built in. The VM is optimised for remaining robust under load even while orchestrating millions of workers. Immutability prevents any data races between all these threads, or any need for locks at all, ever. The end result is that all business logic remains short and focussed on the happy path. The DX is out of this world.
Read up on the BEAM sometime, you might find it interesting. There's much more to FP than endless typing.