So, what is a well-architectured chat? Hmmm, that's the question!
The major task that we at Yellow have to solve every time that we embark on a new chat building project is how to make the chat scalable and tailored to the customer's wishes. Having engineered chats for a wide range of products, we found out that the task can be resolved at the level of chat architecture.
In this article, we’re going to share our approach to chat architecting and explain why we consider it a good chat building practice. Here we go!
First, let’s take a look at our version of chat architecture and its components.
A chat consists of two major parts:
Chat App or client part, which is a desktop, web, or smartphone chat application.
Chat Server Engine or server part, which is a pool of external servers responsible for the chat operation. This is the place where all the chat magic happens.
Both parts contain various components that communicate to each other and bring the chat into action.
Chat Server Engine is a core of the chat architecture that handles message delivery and dispatch. In our version of chat architecture, it includes the following components:
Chat REST API handles the tasks that are not connected directly to message dispatch and delivery, such as user authentication, changing of user settings, friends invitation, downloading sticker packs, etc. The Chat App (the chat client part) communicates with the Chat REST API via the Chat REST API Client Library.
Chat WebSocket Server is responsible for transmitting messages between users. The Chat App communicates with the Chat WebSocket Server via the Chat WebSocket Client Library. This connection is open two ways; that means users don’t have to make requests to the server if there are any messages for them, they just get them right away.
Chat Media Storage Server is a pool of servers responsible for storing user media files. The files are uploaded to them via the Chat Media Storage Client Library.
Chat App is the other major part of the chat architecture, the one that users directly interact with. It's split into three separate root components:
Chat Client Engine handles all of the communication with the Chat Server Engine via its internal components: Chat REST API Client Library, Chat WebSocket Client Library and Chat Media Storage Client Library. It also comprises the Chat Push Message Handler that deals with push notifications.
Chat UI displays data to users via its widgets: Chat Contact List UI, Chat Dialog UI, Chat Push Message Widget — extension for mobile apps that allow for replying to messages without opening the app and Chat Internal Notification Widget — a widget that pops up at the top of the screen while the user is chatting in a dialog and notifies about the incoming message in another dialog.
Chat Device Storage is an internal database (read: your device storage), which stores messages and files so that users can access them offline. Its internal component, Chat Media Cache, gets media files from the Chat Media Storage and stores them on the device so that the user can access them anytime without having to reach the Chat Media Storage every time.
Separation of components is at the core of our chat architecture. All the services that the architecture comprises are independent from each other. Why? It’s beneficial from many perspectives:
Reusability. When the chat components are designed separately, they can be easily reused in other projects.
Scalability. Each architecture component is a potential bottleneck when a project grows bigger and begins to serve a larger audience. The advantage of independent components is that they can be scaled separately without affecting the entire architecture.
Integration. Independent components can be easily integrated with the customer’s services upon request. For example, if the customer wants user files to be stored in their CRM, you can integrate the CRM with the Chat Media Storage without having to change the entire architecture.
Customization and migration. All the architecture components can easily be adjusted to the customer’s needs. For example, they can be powered by different services: the Chat WebSocket Server can be built on PubNub, Twilio, or Firebase, while Chat Media Storage can be powered by Cloudinary or Amazon S3. Or you can build any of the components entirely from scratch if you need them to perform specific tasks.
The same is true for migration. If you want to migrate one component to another service, you can do so without disturbing the rest of the components. We’ve seen it ourselves when we migrated one of our products, Famlicious, from one service to another.
Some of the components of the Famlicious architecture — WebSocket Server, Chat Server Engine, and Chat Client Engine — were run on QuickBlocks. One day, QuickBlocks stopped being supported, which means we couldn’t use it in the project anymore. We started thinking of the alternatives and chose PubNub.
As far as all of the components in the Famlicious architecture are fully independent from each other, we managed to migrate the three components from QuickBlocks to PubNub without involving the entire architecture. And what’s even more important, migration didn’t affect the app operation at all and went totally unnoticed by the users.
That was a brief introduction into the topic of chat architecture. In the coming articles, we’re going to go deeper into the role of every chat component and share more good practices on how to build chats. Stick around and remember to visit our LinkedIn page for other engaging topics.
Got a project in mind?
Fill in this form or send us an e-mail
Get weekly updates on the newest design stories, case studies and tips right in your mailbox.