I went through the same decision myself. I tried building the messaging feature from scratch to my application, both the backend and frontend. Here is what I learned:
- The Socket Phase
The first approach I tried was building everything myself using socket connections. The problem was that the socket-based system was too unreliable for production use. Especially on mobile app, it is very difficult to predict what kind of network environment your users will be in.
For example, a user might be on the subway, and the socket connection could drop while passing through a certain station. That could result in connection being lost or lead to a very poor user experience(such as “please rejoin your chat room”) unless you build a perfect state management system that can detect things like connected, reconnected, intentionally disconnected, short disconnected but worth the wait for reconnect, … states.
- Firebase Realtime Database Phase
At some point, debugging all those connectivity issues became more work than the actual messaging feature itself. So I moved to Firebase Realtime Database, which provided much more reliable connectivity. Things improved quite a bit. Firebase SDK handled connection loss and reconnection, and it saved my time a lot.
- Advanced Features Phase
As the service grew, another set of problems started to appear.
More advanced features are required:
- Group chats
- Unread message counts
- Tracking how many people had read a specific message
- Determining whether a newly joined user can be able to see the old messages
- …
This created a surprisingly complex set of problems.
For example, imagine someone in a group chat hasn’t opened the chat room for a long time and has 1,000 unread messages. Naturally, when he finally open the chat room, probably our server loads only the 20 most recent messages (= pagination).
But then what happens to the other 980 messages? Technically, they’re still considered as “unread”.
A simple solution might be to use the user’s last access time to the chat room as the “read/unread” boundary. Okay, that sounds fair. But now, calculating the total number of unread messages across all of his chat rooms, or determining how many people have read a specific message, the computation suddenly explode.
- Front end optimization is another problem
There were also plenty of problems on the front end. For example:
- If the user is already inside a chat room, other users’ messages should immediately be marked as read, and he shouldn’t receive notifications for those messages.
- As the number of messages grows, you eventually need local caching. Then you have to figure out how to handle the gap between locally cached messages and server side messages.
- Scroll controlling becomes surprisingly complicated. A chatting room uses reverse scrolling(old messages are above, new messages are below), if the user is scrolling through, new incoming messages shouldn’t bother the position he is currently looking at.
After experiencing all of these problems, I eventually moved to the Sendbird Service. Of course, they are not perfect either, and you still have to develop many things. But they do take care of large portion of above problems.
I also learned about the history of Sendbird: They originally ran a “moms community application” and tried adding the messaging feature. They apparently went through the same pain, learned a lot from the experience, and finally realized that solving those problems could itself become a business.
Hope this helps.