The most significant thing I have learned is to understand the concurrent flow of data through your system – a common mistake is to throw GenThingies at every piece of data; Elixir is not an OOP environment.
So, for example, data flows into your system from HTTP request, or from some database call. At this point, your DB layer or HTTP server will probably have a function invocation per request.
Ensure that each request can be processed through as many functions as possible – not processes as possible. Each move of data between processes, and possibly GenServers, is another opportunity for copying data, moving things into mailboxes (a singleton queue), and slows you down.
Make sure you know what each function is doing, for example ConCache is excellent, but you need to be aware that it is using ETS tables behind the scenes. ETS requires copying data in & out of the heap. Other modules will have GenServers with a functional interface - usually for good reason, but again, another opportunity to block things in mailboxes/queues if that GenServer is handling multiple user requests itself.
If all your data flows smoothly through functions, minimising process changes, then this allows the BEAM to maximise its performance without needing to shuffle data around in memory.
Make it work, then make it beautiful, then if you really, really have to, make it fast. 90% of the time, if you make it beautiful, it will already be fast. So really, just make it beautiful!
—Joe Armstrong
Wiser words than that are harder to find around here.






















