weeeBox / mobile-system-design

A simple framework for mobile system design interviews
Other
4.05k stars 427 forks source link

Chat App Discussions #13

Open matzuk opened 2 years ago

matzuk commented 2 years ago

@weeeBox Hi! Here, there are some points about Chat Design based on my experience.

The main distinguishing feature of any Chat application is a very big number of states inside the App. Use A sent you a message, your message that was sent to a User B is delivered, the status of User C changed, Used D changed the name of Group AA and etc. How it affects the Application.

The first one is Architecture (close to the Presentation layer). MVC, MVP, MVVM may work at the beginning but these solutions are absolutely non-scalable due to a big number of events and states that may affect each other and the absence of a State handling approach. That's why MVI approach does matter because MVI tries to set rules on how to handle a state. There are different implementations that you can consider as an example. My favorite one now is MVIKotlin.

The second consequence is CQRS and a Single source of True. Let me show a diagram: image

  1. All requests are divided into two groups: Commands (change state but doesn't return) and Queries (doesn't change a state but return a state). This separation is visible in MessageFeature. It's CQRS.
  2. All updates are coming from a special object called UpdateChannel. It's a source of queries in terms of CQRS and the single source of True (source of updates). Under the hood, UpdateChannel may subscribe to updates from DB, transform data and deliver it further.
  3. UpdateDispatcher. The responsibility: listening to UpdateChannel in a separate Thread (because the number of events is so big), distributing events to relative handlers (handlers are working in separate ThreadPool to avoid pauses in UpdateChannel thread).
rakeshh91 commented 2 years ago

@weeeBox Hi. Thanks for all your contribution to this repo.

I would be interested to deep dive into data flow (end to end) and how we can keep data as single source of truth for presentation layer with different use cases:

  1. Send message use case: (if two users are in a chat session and User A sends a message)

    • Do we store the sent message with its status (about delivery) to the DB first and then pass it on to dispatcher to actually send to backend? Or we can do both in parallel? What issues we might see if we do in parallel ?
    • When can we update the UI (Chat pagination list) with this new message (sent message)? Or can we simultaneously update UI as well as DB? Or the list should always come from DB and we should not be adding new message directly to UI?
  2. Receive message use case: either via notification or during active chat session (data flow end to end in this use case as well)

  3. Sent message status when user is on offline mode (sending/failed to deliver/delivered/read).
    Offline mode -> User sends multiple messages -> initially messages will be in sending state -> Once network is available -> Messages gets delivered (if successful) How would storing the messages and tracking its status and updating the appropriate status on the UI can be achieved? (Some of the concepts might be covered in the Offline support links that you attached. But, still adding this design in case, if you think anything else we can think of, apart from information provided in those links)

  4. Do we need to update our DB frequently from backend to keep data in sync with Backend? (Asking because users might send messages from different devices - Mobile/Tablet/etc). If yes, When is the best time to refetch data from backend or do we need update in regular intervals?

weeeBox commented 2 years ago

Send message use case: (if two users are in a chat session and User A sends a message)

The actual implementation depends on the target platform but the idea is simple:

My point - you only update the database and other components "react" to that.

Receive message use case: either via notification or during active chat session (data flow end to end in this use case as well)

Same idea - you receive the message - you write it to the database, UI-component react to the changes.

Sent message status when user is on offline mode (sending/failed to deliver/delivered/read).

You keep adding messages to the database but the network client ignores them while there's no connection. Once the connection is back - the network client send everything in a batch.

Do we need to update our DB frequently from backend to keep data in sync with Backend?

You update messages in 2 different ways:

You generally don't pull any data on an interval basis - that does scale as the number of the clients go up

weeeBox commented 2 years ago

@matzuk, I think it could be too much detail for the interview - it's really hard to explain in such a short time. I would start simple and only add details if needed. Nobody expects you to build a robust solution - it's more about the process and communications. If you bring MVx patterns - don't forget non-technical trade-offs: how easy it is to teach junior engineers to use a specific architecture. When you bring a 3rd-party library - you need to have a good understanding of the updates, support, and deprecation. There's always a trade-off - you need to clearly communicate this to the interviewer.

rakeshh91 commented 2 years ago

@weeeBox , If we come across a feature like Chat Backup to cloud. What are your thoughts on this? Do you see anything else to consider apart from below items?

Also, Any use case you can think of, where we use these backed up data in our app apart from just restoring it when user reinstalls the app?

weeeBox commented 2 years ago

@rakeshh91, this WhatsApp screenshot should answer all your questions 🙂 Screenshot_20211210-191822

chipbk10 commented 2 years ago

Hi @weeeBox

chipbk10 commented 2 years ago

probably we can explain what is end-to-end encryption to the readers: Wiki: End-To-End Encryption

mathiastck commented 1 year ago

Great discussion. I found the complexity goes up greatly if you have to support multiple devices and/or message deletion. Both are possible with xmpp, for example, but hard to add to an app that wasn't designed from the start with both in mind.

https://en.m.wikipedia.org/wiki/XMPP