I'll just pick one. Matrix is resource-heavy, even in the best of times. There is a confluence of smaller contributing factors, and several effects on both its usability and developer/platform friendliness. Consider this anecdote of the overhead of sending the message "hi" as a baseline: in Matrix, this takes about 1KiB on average after all is said and done in JSON (and varies, unfavorably). So to over-simplify, that's 1K to the disk, 1K to each server in the chatroom, for which there could be several hundred, and 1K read on query from clients and other servers -- all for a 2 byte payload.
Before I'm accused of being unfair because there's always going to be a ridiculous ratio for something like a "hi" message, consider some alternatives for both the format and payloads of the fundamental protocol primitives. Most of the messages contain cryptographic metadata which has a succinct binary representation, but JSON requires base64; when represented naturally with CBOR the overhead can be reduced ~40%, and without encoding/decoding either. Consider that virtually all of the overhead in "hi" is either cryptographic hashes or signatures or integers (depth/ts) which would benefit from compact formats.
Does representation actually matter though? Why can't I just store Matrix in my format and federate with your format? I guess this is an example of where theory and reality collide. One cannot write a server which handles messages as abstractly as possible (leveraging these JSON/CBOR extensible formats) while at the same time knowing which fields have a more efficient binary representation and transforming that. In reality that just looks like a CBOR message with a bunch of base64 plaintext strings. It doesn't achieve that 40%.
All of this is important because of Matrix's (superior) design over its event abstraction. When the whole protocol is hinged on fundamental primitives (a good thing) attention to detail and focus must be given to those primitives. The more optimized they are, the more everything built with them is also optimized. When the foundation is efficient, developers can do more with matrix and enrich the user experience. For another example, matrix has been reluctant to give developers the power to store shared-program (i.e bot) state efficiently in a chat room. This is because there's no mechanism to delete state_keys, or even discard overwritten state itself. That's an important cornerstone that's missing while the rest of the tower is being piled on.
It might be possible to confuse any of these issues as trivialities, and their solutions as bike-shedding. I contest their importance is evident in how they emerge to shape the character of the entire system. Consider: does matrix require the entire DAG to be acquired like a bitcoin block-chain? Then I better be careful and conservative about messages. Does matrix allow gaps in the DAG and have a smaller chain for auth? Then I can be liberal about messages and delete stuff later. When I go to build an application which communicates over Matrix those qualities emerge as fundamental limitations or liberations of what users can experience.