...
/Evaluations of Nonfuncational Requirements of Chat Application
Evaluations of Nonfuncational Requirements of Chat Application
Evaluate nonfunctional requirements and understand the trade-offs and optimization for a real-time chat application.
After laying down the architectural foundation of a mobile chat application, it’s not enough to simply verify that the system works. We must evaluate how well it works, how it behaves under pressure, how it responds to change, and how it sustains user trust overtime. This is where nonfunctional requirements (NFRs) come into play.
In this lesson, we will explore the proven techniques used to achieve each of these NFRs in the context of a chat application. We’ll also examine the inevitable trade-offs that arise because optimizing one quality often impacts another. For instance, improving battery life may come at the cost of instant updates, or enhancing security may introduce additional processing overhead.
We begin this exploration with one of the most perceptible and impactful NFRs: low latency.
Low latency
In chat applications, users expect their messages to appear instantly after tapping send and for replies to materialize in real time. Any lag, even by a fraction of a second, can erode the sense of immediacy that defines modern messaging experiences. Achieving low latency demands a System Design that considers networking, state management, user experience, and back-end synchronization as a unified challenge.
WebSockets: As established in the design considerations lesson, we chose WebSockets (WS) to enable persistent, real-time messaging. While ideal for low latency, this comes with certain trade-offs: maintaining open connections increases server resource usage and demands robust reconnection handling on mobile clients. We can optimize WebSocket communication to further reduce latency.
To optimize WS communication for low latency:We can use binary protocols like protobuf instead of JSON to reduce payload size.
We can implement message batching to minimize overhead.
We should enable compression for smaller data transfer and use edge servers (discussed in the subsequent section) to reduce geographical delays.
Additionally, we should maintain efficient connection handling by closing idle connections, and using heartbeat messages to detect and prevent unnecessary reconnections.
Edge servers for fast routing: Even with WS, messages must still travel from the sender to the server and then to the recipient. If both users are geographically in the same region, routing messages through a central server increases latency. A better solution is to use edge servers, which are regional servers that route messages through the shortest path possible.
For example, if user A sends a message to user B, and both reside in Asia, but the central server resides in the US, instead of sending the message through the central server, it would be optimal to route it through the edge server in Asia.
If WebSocket managers know which server to send a message to, why do we still need edge servers for faster routing in a chat application?
The following illustration is a visual overview of using edge servers and WS managers:
Debouncing event spam: On mobile, frequent updates like keystrokes, online status, or read receipts can flood WebSocket connections, especially in group chats. This event spam adds latency, drains battery, and clutters the network. Debouncing solves this by delaying events until user activity pauses (e.g., 500ms after typing stops). It includes typing indicators, presence updates, or statuses in group chats.
The following is pseudocode to debounce event spam:
private var typingTimer: Timer? = nullfun onUserTyping(conversationId: String) {typingTimer?.cancel()typingTimer = Timer()typingTimer?.schedule(object : TimerTask() {override fun run() {socket.send("{\"event\": \"userTyping\", \"conversationID\": \"$conversationId\"}")}}, 500) // Wait 500ms after last input}
Optimistic UI and perceived responsiveness: ...