The non-standard (won't work with anything else) and basically superfluous websocket protocol has bad fundamentals and has been marred by bad JavaScript code being needed for it. On top of that it's pretty bloated.
The actual channel processes could've simply followed a standard Erlang interface but someone (...) felt they needed to put their fingerprint on it, I guess, so it kind of doesn't. And yes, again everything surrounding channels is a bunch of macros until you at least get to write and use normal functions in the actual channel module.
They've had a long history of arbitrarily deciding to hide settings/configuration from dependencies they use and having no actual argument for doing so when asked to expose them.
If the part about macros being overused wasn't bad enough Phoenix also promotes this type of thinking by overusing them even in generated code, so people can follow the bad example.