> And I remember seeing a lot of forum posts around the dangers of using GenServers (unless you know what you're doing).
The danger is using a single process of the GenServer instead of multiple, so you can get single process bottleneck that won’t use multiple cores. You don’t have to know any intricacies of BEAM or OTP to know and design around using multiple process instances of the GenServer.
> I know you can do distributed state in Elixir too, but it doesn't seem as easy as it is in other languages.
You can use Redis in Elixir as well. Saying that Elixir is worse at distribution than Python/Ruby because ETS isn’t distributed is a bit like saying Python is bad at distribution because objects are not distributed. It’s especially strange since Elixir ships with a distribution system (so you can access ETS from other machines) while your other example languages do not.
> As a simple example, I think Plug.Parser is wrong to raise an exception when invalid json is given to it (shitty user data is hardly "exceptional" and I don't need error logs with poor signal to noise).
Plug sets the status code for parser errors to 400: https://github.com/elixir-plug/plug/blob/v1.10.4/lib/plug/pa...
You should check the `:plug_status` field of the exception and only log/report the error if it's in the 5xx range.
Elixir hasn’t done away with behaviours. They exist in the language and are used to implement features in the standard library itself and many libraries in the ecosystem.
You don’t have to go to Erlang documentation to learn about them since they are documented in Elixir as well [1] [2].