This is not true. The endpoint and router are macro based, but once it is routed, it is all functions. Your controller actions are functions, calling the view/template is a function, your channel is functions, the model/context layer are functions.
When it comes to behaviors, we do our best to follow Erlang/OTP conventions, but deviate where it makes sense. For example, channel has “join” instead of “init” because you can refuse a join but you can’t refuse an init. They have different return types and augmenting init could be confusing if later you were to write a plain GenServer.
It is easy to look from outside and say “someone wanted to put their fingerprints on it” but actual discussions were had in pretty much all of these topics. I suggest asking around. If you asked for something and we had no actual arguments, then please point me to such occurrences. I will be eager to clarify (and as a rule we generally do).