3 Aug, 2025
Hello World! In this article, we will learn how about some of the communication design patterns/concepts that are used in backend and you may have even heard about them. You will explore how there are multiple ways a client can communicate with the server and vise versa.
We will start from some very basic and well known foundational concepts like “Request-Response” and move to some architectural concepts like “Stateful vs Stateless”. I will try to keep everything to the point and simple without loosing any meaning, I hope you learn something from this article.
(The Classic Conversation)
This is perhaps one of the most fundamental and widely used communication model in backend systems, or in web in general. It works like an interaction between parties (i.e. the client & the server), where one party sends request and other responds/serves that particular request. Think of it like a conversation between you and your friend, you ask the question, and your friend responds to that with an answer.
200 OK
, 404 Not Found
, 500 Internal Server Error
).The request and response structure is predefined by both parties. It is defined by a specific protocol and format that will be used.
Example:
HTTP Request:
GET /index.html HTTP/1.1 Host: www.example.com User-Agent: Mozilla/5.0 Accept: text/html (empty line indicating end of headers)
HTTP Response:
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 1234 (empty line indicating end of headers) <!DOCTYPE html> <html> <head><title>Example Page</title></head> <body><h1>Hello World!</h1></body> </html>
(Wait or Don't Wait)
While Request-Response is about how two parties interact, Synchronous vs Asynchronous is about how they interact and how they handle the “waiting”.
In Synchronous, the client sends a request and waits for the response, the server may process and respond in this timeframe the client is essentially frozen and cannot proceed till it gets the response back. Its like you calling someone on phone, you cannot start speaking or acting until they pick up and respond.
Now this is obviously opposite of the Synchronous communication, in Asynchronous communication the client sends request and does not wait/freeze. The client can do other work while the request is processed by server and served to it. Once server is done processing the request and sends a response, the client is notified (via a callback, a promise, or a message queue event). Think of this like you sending an email to your friend, you can send email and do other work without relying on their response.
NOTE: In Traditional Request-Response (like HTTP), “client” has the Synchronicity property, as client need to wait. Of course modern clients are asynchronous and can do other work as Modern client-side development heavily relies on asynchronous HTTP requests.
(Server Speaks)
If a client wants real time notification from backend without needing to initiate requests time to time, a architecture where server sends data directly without any request. In Push, the client is not the initiator, as soon as bidirectional connection is established the server can directly send data. Its like when mailman delivers your mail on doorstep as soon as it arrives at the post office without needing your intervention.
(Are We There Yet?)
After understanding “Push” mechanism, it is important to understand its counterpart Polling, which is client initiated.
In Polling (also known as Short Polling), the client periodically sends request to server to check for new data or updates. The server immediately processes the requests and sends back response even if no update is ready yet. The client waits for fixed interval again before sending next request, regardless of whether updates are expected or not. Think of it like this, when someone with less patience in a restaurant keeps asking if his food is ready or not to the waiters, and if its not ready they will respond with “no”, then he asks again after 5 minutes for updates.
(Short Polling but patient one)
Having understood the inefficiencies of Short Polling (where its too chatty of a mechanism), Long Polling solves those things. This pattern is an optimized version of polling where client sends request to the server just like polling, but instead of immediately responding with a “no” message if update is not ready, the server waits and DOES NOT reply unless update is ready. Server replies only when response if ready, so this makes the mechanism less chatty, and provide a near real-time experience. If we try to put previous example here too, here the person now has patience and when he asks a waiter if his food ready or not, the waiter says “I will bring the food as soon as its ready”, and the person does not ask again.
NOTE: This is kind of similar to the simple “Request Response” mechanism, but this is kind of different as the client can disconnect if request “handle id” is involved and the Connection Lifetime is also extended. You can say long polling is “better” version of request response.
(The Server's Live Broadcast)
This is a design pattern that provides a simple, efficient, and standardized way for a server to send a continuous stream of text-based updates to a client over a single, long-lived HTTP connection. Unlike the "client-pull" model of polling, SSE is a native "server-push" technology. It's designed specifically for one-way communication: from the server to the client. This makes it ideal for scenarios where the client primarily needs to receive updates without sending much data back.
Content-Type: text/event-stream
header. This tells the client's browser that the response body is not a single file, but a continuous stream of events.(The Bulletin Board)
Moving beyond the polling-based patterns, we arrive at Publish/Subscribe (Pub/Sub), a powerful and highly decoupled messaging pattern. Unlike polling, where clients have to constantly ask for updates, Pub/Sub is a true event-driven, asynchronous mechanism that allows for one-to-many communication.
In Pub/Sub, clients don’t directly communicate. Instead, they they interact with a central messaging service, often called a “Message broker”. This broker acts as an intermediary, managing the flow of information.
This pattern consists of two major roles:
Think of it like a public email newsletter. The publisher writes a new post and sends it to the newsletter service (the broker). The service then distributes it to every single person who has subscribed, without the publisher having to know or care about who those subscribers are.
(Remember or Forget)
When designing backend communication, one of the most fundamental architectural decisions you must make is whether your system will be stateful or stateless. This distinction determines how a server handles a client's requests and whether it remembers any context from previous interactions. The "state" in this context refers to any data that a server needs to remember about a client's session to handle subsequent requests.
Stateful: In a stateful system, the server retains information or "state" about a client's session across multiple requests. The server remembers previous interactions and uses that stored context to process subsequent requests. This means a client often only needs to provide a small identifier (like a session ID or connection ID) in subsequent requests, and the server retrieves the rest of the context from its memory or a persistent store.
Stateless: In a stateless system, the server treats every single request as an independent and isolated transaction. The server does not store or remember any information from previous requests. Here the client must include all the necessary information (e.g., authentication tokens, session IDs, data payloads) within each request itself. As each request is a self-contained unit.
TCP → Stateful
UDP → Stateless
Can you restart the backend during idle time and the client’s workflow should continue to work? → Stateless
Should client’s information/state be stored for further subsequent requests? → Stateful
Following are two illustrations showing how same scenario can be achieved via both stateful & stateless:
illustration 1:
illustration 2:
Technically here in illustration 2 backend is stateless, but the entire system is still stateful. (because if database dies, state dies)
So we went through some cool and majorly used design patterns.From the simple, yet powerful, Request-Response model to the highly decoupled Pub/Sub and the real-time efficiency of Server-Sent Events, each pattern is a specialized tool.
The art of backend communication design lies not in mastering one pattern, but in understanding the trade-offs and knowing which tool to use for the job. Choosing between a stateful or stateless architecture, or deciding whether polling is "good enough" versus investing in a push mechanism, fundamentally shapes your application's performance, scalability, and resilience.
I will try to keep updating this article as new stuff comes in my mind, you can also suggest me some topics or if you wish to contribute to this article, feel free to do so through this repository:
>https://github.com/ProgrammerPratik/ProgrammerPratik.github.io/tree/master/articles
Hope you found this article helpful! Thanks for reading have a great day <3