One of the great things about the Elixir ecosystem is that, in so many cases, the libraries you’re using make the appropriate use of supervision trees so you don’t have to.

Obviously it depends on what you’re building and you can craft your own supervision structures if you want to. But most of the time you can get the benefits of BEAM resiliency without having to drop down into the details.

The one thing I dislike about Elixir is the confusion caused by how some libraries execute their functionality in-process and others spawn a supervision tree and message pass - putting your work in a possible queue that can get overloaded.

Its a common pitfall for more inexperienced devs and I think its just a symptom of the language conventions.

Everyone is taught genservers with a client-side API existing inside the same module as handle_ functions and it blurs the distiction some.

I think if the convention was to create a separate module to implement the client-side convenience functions then the client-server split would be more obvious.

When you say 'execute their functionality in-process', what exactly do you mean? In the context of the current process? Are there any good resources explaining when it is more appropriate to do one over the other?

One example is HTTP libraries.

For instance, take Mint (https://github.com/elixir-mint/mint):

> Mint is different from most Erlang and Elixir HTTP clients because it provides a process-less architecture.

Mint is a low-level library which doesn't make attempt to manage processes (including HTTP pooling).

In contrast, Finch (which builds on top of Mint) includes pool management:

https://github.com/elixir-mint/mint#connection-management-an...

It can take someone a bit off guard when they realise that the library they use provide a "default pool" they were not aware of, and that it can become a bottleneck etc.