skip to content

Client-Server Style

The two-role request-response model that underpins most of what you build, including HTTP and REST. You will cover stateless versus stateful servers, thin versus fat clients, and how multi-tier variants extend the basic split.

part ofSoftware design & architectureoverview, primer and where to startread it →
on this pageshow

questions

6

What is the client-server architectural style, and what does it mean for a client to send a 'request' and a server to send back a 'response'?

level: juniorimportance: must knowfreq 85%

answer

  1. client initiates, server owns resource
  2. asymmetric request-response
  3. server never pushes unprompted
  4. shared logic vs duplicated logic
  5. SPOF risk from centralization

basics

~20 s

The client-server style splits an app into two roles: a client that asks for something (a request), and a server that has the data or logic and answers back (a response). The client initiates; the server waits and replies.

solid answer

~40 s

Client-server is a structural architectural style where two logically distinct roles talk over a network using a request-response protocol: the client initiates communication by sending a request, and the server, which owns shared resources like data or business logic, processes it and sends back a response. The relationship is asymmetric: the client knows how to reach the server, but the server doesn't initiate contact with clients on its own. This separation lets you evolve, scale, and secure the two sides independently — many clients (browsers, mobile apps, CLI tools) can share one server's logic and data without duplicating it, and the server can be hardened, load-balanced, or replaced without touching client code, as long as the contract stays stable.

go deeper

for a junior

Should describe the basic request/response flow and identify which side initiates.

for a middle

Should explain why the separation exists (shared resource, decoupled evolution) and name at least one real protocol example.

for a senior

Should discuss trade-offs (latency, SPOF, coupling to a contract) and know common mitigations like load balancing and caching.

for a principal

Should reason about when the style breaks down (offline needs, extreme scale, real-time push) and how layered/hybrid architectures address those gaps without abandoning the core model.

## What the style is The client-server style is one of the oldest and most common **structural patterns** in software architecture: a system is decomposed into two kinds of participants with different responsibilities, connected by a **request-response protocol** over a network (or, in degenerate cases, over IPC on one machine). | Participant | Its job | |---|---| | **Client** | The initiator — it holds the user-facing responsibility, gathers input, and sends a request describing what it wants. | | **Server** | The responder — it owns a shared resource (a database, a set of business rules, a piece of hardware) and processes incoming requests, returning a response that the client then interprets and presents. | ## How one exchange runs Mechanically, the interaction follows a strict turn-taking sequence: 1. The client opens a connection (or reuses one), serializes a request according to an agreed-upon protocol (an HTTP method + path + body, an RPC call, a SQL query over a wire protocol), and sends it. 2. The server, which has been listening on a known address, accepts the request, parses it, executes whatever logic or query it implies, and serializes a response back down the same channel. 3. The client is passive between sending and receiving: it does not do anything else meaningful with that request until the response arrives. Crucially, the server does not initiate contact with a client on its own — it cannot "push" unprompted work to a client to whom it hasn't been asked to. ## Why the separation exists The style exists to solve a **resource-and-responsibility separation problem**. Data and business logic are often expensive, sensitive, or need to be shared across many consumers — a product catalog, a customer database, an authentication check — so it doesn't make sense to duplicate that logic into every client. - By centralizing it behind a server, you get a **single place** to enforce validation rules, apply security controls, and keep data consistent, while clients stay focused on presentation and user interaction. - This also lets the two sides **evolve independently**: a mobile app team and a web team can both talk to the same backend without knowing about each other, and the backend team can change its internal implementation as long as the request/response contract is preserved. ## The trade-offs The trade-offs are real on both sides. - **Shared dependency.** Centralizing logic on the server means the server becomes a shared dependency: if it's down, every client is affected — the classic single-point-of-failure risk, mitigated in practice by replication and load balancing, but that mitigation is extra operational cost the style itself doesn't provide for free. - **Latency.** Network round-trips introduce latency that a purely local, single-process design wouldn't have; a chatty protocol (many small requests) can be dramatically slower than a design that batches work. - **Concurrency.** The server must also handle concurrency: many clients hitting it at once means it needs threading, connection pooling, or async I/O, and a naive implementation can be overwhelmed. - **Connectivity.** On the client side, if the client does little beyond rendering, it becomes fully dependent on connectivity — a poor fit for offline or high-latency environments. ## Failure modes in production Failure modes in production typically show up as **timeouts and partial failures** rather than clean errors: a client sends a request, the server is slow or unreachable, and the client has to decide whether to - retry, - show a stale cached value, or - surface an error to the user. Because the server is shared, a bug or overload in the server's logic affects every client simultaneously — unlike a bug in one client's local logic, which affects only that user. **Debugging** also becomes distributed: a failure might originate in the network, the client's serialization, or the server's processing, and correlating logs across the two sides is a real operational skill. ## Where you have already seen it - **A concrete example:** a web browser (client) requesting a page from a web server is the canonical instance — the browser sends an HTTP `GET`, the server queries a database and renders HTML, and the browser displays it. - **Another everyday instance** is a mobile banking app talking to a REST API: the app never touches the bank's database directly — it goes through the server, which enforces authentication, business rules, and audit logging, none of which the client is trusted to enforce itself.

  • If the client never initiates contact and always waits passively, how do servers deliver real-time updates like a chat message arriving instantly?
    Pure client-server request-response can't push, so real systems layer something on top: long polling (client re-requests quickly), WebSockets (client opens a persistent bidirectional connection so the server can then write to it), or Server-Sent Events. These techniques keep the client-initiated connection open or repeated so the server has a channel to use, without breaking the underlying model where the client made the first move.
  • Why is centralizing business logic on the server considered a security benefit rather than just a convenience?
    A client runs on hardware the attacker fully controls, so any validation or authorization check placed only in client code can be bypassed by calling the server's API directly with a modified request. Putting the enforcement on the server means every request is checked regardless of which client (or a hand-crafted HTTP call) produced it.
  • What happens to the client-server model when you introduce a caching layer or CDN in front of the server?
    The cache becomes a second server from the client's point of view: the client still sends a request and gets a response, but the request may be satisfied without reaching the origin server. It's still client-server at each hop, just chained — the cache is a server to the client and a client to the origin.

Like a restaurant: the diner (client) orders from a menu, the kitchen (server) holds the ingredients and recipes and prepares the dish, and the diner never walks into the kitchen to cook it themselves.

saying these in an interview costs you the question

  • Says the client and server can call each other symmetrically at will
  • Thinks statelessness is a property of every client-server system, not a design choice
  • Can't explain why putting validation only in the client is unsafe
  • Confuses client-server with peer-to-peer
  • Assumes the server must always be a single machine

context

open as a page

What's the difference between a stateless server and a stateful server in a client-server system, and why does it matter for scaling and failover?

level: middleimportance: must knowfreq 80%

basics

~20 s

A stateless server treats every request independently and remembers nothing about the client between requests; the client must resend any context each time. A stateful server keeps track of a client's session (like being logged in) across multiple requests.

open as a page

A two-tier client-server app (a client with embedded database queries talking directly to a database) is evolving into a three-tier architecture. What gets added in the middle, and why?

level: seniorimportance: must knowfreq 70%

basics

~20 s

Multi-tier splits the server side further: instead of a client talking straight to a database, you add a middle layer (an application server) between them, so presentation, business logic, and data each live in their own layer.

open as a page

In a client-server design, what's the difference between a thin client and a fat (thick) client, and what trade-offs push a team toward one or the other?

level: middleimportance: should knowfreq 55%

basics

~20 s

A thin client does almost no work itself — it just displays what the server sends and forwards user input back. A fat (thick) client does a lot locally — business logic, validation, rendering — and only talks to the server for shared data or authoritative operations.

open as a page

How does REST, as an architectural style layered on HTTP, encode client-server request-response mechanics plus its statelessness constraint, and what does that constraint forbid a server from doing between requests?

level: seniorimportance: should knowfreq 65%

basics

~20 s

HTTP is built as a request-response protocol: a browser or app (client) sends an HTTP request to a URL, and a web server responds with data or a status. REST is a set of design rules on top of HTTP saying, among other things, each request must be self-contained (stateless) and resources should be handled through a uniform set of methods like GET/POST/PUT/DELETE.

open as a page

You're designing a system where thousands of IoT sensors at a remote site must keep functioning and buffering data during hours-long internet outages, then sync when connectivity returns. Why is a naive client-server design a poor fit here, and what architectural adjustments address it?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

Plain client-server needs the client to reach the server for almost everything, so if the network is down for hours, a naive client-server design just stops working. The fix is to let the client keep a local copy of data and logic so it can operate offline, then sync with the server once the connection comes back.

open as a page