System design archetypes — recognising the shape
Lessons 01–13 handed you mechanisms. An interview hands you a product. The senior move is to classify first: almost every prompt is, underneath, one of about eight recurring shapes — and the shape tells you the dominant force, the first bottleneck, and which mechanisms to reach for, before you draw a single box.
Here is the failure mode this lesson cures. A candidate is asked to "design Dropbox" and immediately starts sketching an API, a Postgres schema, a load balancer — generic boxes that fit any system and therefore commit to nothing. Forty minutes later there is a diagram but no argument: nothing in it follows from what Dropbox actually is. The senior candidate spends the first sixty seconds doing classification: "this is a blob/media system — large immutable objects, small hot metadata, durability-dominated — so the first decisions are object store vs metadata DB separation, chunked resumable uploads, and CDN delivery." Every box afterward is a consequence of that sentence.
The archetype is not the answer. It is a starting hypothesis that picks your default mechanisms and your default bottleneck. You then adjust with the real numbers from lesson 01 (requirements, QPS, data size) and the latency/throughput budget from lesson 02. Recognise the shape → inherit a design skeleton → tune it. That is the whole game.
One distinction to keep straight: this lesson decomposes a prompt into shapes (what kind of problem each piece is), which is not the same as decomposing it into services (a separate, deployment-level decision covered in lesson 17). A shape might end up as one module inside a larger service, or as its own deployable service — recognising the shape tells you the mechanisms; whether it earns its own service is a later call about team boundaries, scaling, and blast radius.
The eight archetypes at a glance
This is the taxonomy. Memorise the tells, not the rows — the tell is the word in the prompt that fires the classification.
| System shape | Canonical example | Core problem |
|---|---|---|
| 1 · CRUD / transactional | banking, user profile | correctness, strong consistency |
| 2 · Feed / fanout | Twitter, Instagram | read amplification, fanout, hot keys |
| 3 · Queue / async workers | image processing, email | decoupling slow work, safe retries |
| 4 · Streaming / log | metrics, clickstream | ordered high-throughput ingest |
| 5 · Search / retrieval | Google, Yelp | indexing + ranking |
| 6 · Real-time coordination | chat, multiplayer | low-latency delivery, presence |
| 7 · Analytics / OLAP | dashboards, logs | large scans, aggregation |
| 8 · Blob / media | YouTube, Dropbox | large objects + durability |
1 · CRUD / transactional
Dominant force: getting the write right. Scale is usually modest (thousands of QPS, not millions); the hard part is invariants — an account balance must never go negative, an order must not be double-charged. Read:write: mixed, often write-significant. Consistency stance: strong, CP under CAP — you reject writes during a partition rather than accept a wrong balance. Go-to mechanisms: single-leader replication (one writer = a serialization point), ACID transactions with the related rows co-located on one shard so you never need a distributed commit, shard by entity id only when one node is genuinely too small. Canonical architecture: a relational store with the leader taking writes, read replicas for scale-out reads, transactional boundaries drawn around an aggregate so the common operation is single-shard. The tell: "money", "must not double-charge", "source of truth", "audit".
2 · Feed / fanout
Dominant force: read amplification plus the celebrity hot key. One write (a tweet) is read by millions; one user (a celebrity) has tens of millions of followers, so naive fan-out-on-write explodes. Read:write: extremely read-heavy (often 100:1 or more). Consistency stance: eventual — a few seconds of timeline staleness is fine. Go-to mechanisms: heavy caching, async fanout via queue, shard by user, and the hybrid fan-out strategy (push to most followers' timelines, pull for celebrities) fully developed in lesson 19. Canonical architecture: write to a per-user post store, fan out into per-user timeline caches asynchronously, serve the home feed from cache; merge celebrity posts at read time. The tell: "timeline", "home feed", "followers", "news feed".
3 · Queue / async workers
Dominant force: moving slow or spiky work off the request path so the synchronous API stays fast. Read:write: not the framing — think in jobs/sec produced vs consumed. Consistency stance: the user gets an immediate "accepted", the work completes later; the contract is at-least-once. Go-to mechanisms: a message queue with competing consumers, idempotency keys so a retried job is harmless, a dead-letter queue for poison messages, backpressure when producers outrun consumers, and worker autoscaling on queue depth. Canonical architecture: API enqueues a job and returns 202; a pool of stateless workers pulls, processes, retries, and DLQs. The tell: "process in the background", "send the email", "generate the thumbnail", "this can be slow".
4 · Streaming / log processing
Dominant force: sustained high-throughput ordered ingest, then continuous processing. Unlike a job queue (discrete tasks, any order), a log is an ordered append-only sequence you replay. Read:write: write-dominated ingest, often millions of events/sec; reads are sequential scans by consumer groups. Consistency stance: ordering matters per partition; end-to-end you aim for exactly-once processing via idempotent writes (12), not exactly-once delivery. Go-to mechanisms: a partitioned append-only log (Kafka-style), per-partition ordering with partition keys, consumer groups, windowed aggregation, usually feeding an OLAP store downstream. The tell: "events per second", "clickstream", "real-time metrics", "ingest pipeline".
5 · Search / retrieval
Dominant force: building and serving an inverted index — a map from term → the list of documents that contain it, the structure that powers search and retrieval — and the two-stage recall → rank pipeline. Read:write: read-heavy queries against an index that updates asynchronously. Consistency stance: eventual index freshness — new documents appear after the indexing pipeline catches up (seconds to minutes). Go-to mechanisms: an inverted index partitioned local (document-based) vs global (term-based) — the choice governs whether queries scatter to all shards or hit one, covered in lesson 07; read replicas + cached popular queries; an async indexing pipeline; scatter-gather across shards then a ranking stage. The tell: "search", "query", "relevance", "ranking", "autocomplete".
6 · Real-time coordination
Dominant force: many long-lived stateful connections, sub-second delivery, and presence. This is the deliberate exception to lesson 05's "make servers stateless": a connection server holds an open WebSocket per client, so it is inherently stateful. How you still scale it: a thin stateless routing/session layer maps a user to the connection server currently holding their socket (a directory in Redis), and a pub/sub backbone fans a message to whichever servers hold subscribers for that room. The connection servers are stateful but shardable and replaceable; on disconnect the client reconnects and the directory updates. Consistency stance: per-room ordering, eventual elsewhere. Presence is ephemeral heartbeated state (TTL keys), not durable. The tell: "online status", "typing indicator", "live", "presence".
7 · Analytics / OLAP
Dominant force: scanning huge volumes for aggregates, not point lookups. The cardinal sin is running these scans on the serving OLTP database. Read:write: read-heavy big scans, batch or near-real-time loads. Consistency stance: eventual freshness is acceptable ("as of 5 minutes ago"). Go-to mechanisms: columnar storage — a columnar store keeps each column contiguous on disk, so an analytical scan reads only the columns it needs (the ones a GROUP BY touches) rather than whole rows — OLAP physically separated from OLTP, lambda/kappa batch+stream pipelines, and pre-aggregation via materialized views / rollups so dashboards read summaries not raw rows. The tell: "dashboard", "report", "group by", "over the last 30 days", "ad-hoc queries".
8 · Blob / media
Dominant force: storing and serving large immutable objects cheaply and durably, while a small hot metadata set stays queryable. Read:write: write-once, read-many; objects are MB–GB, metadata is tiny. Consistency stance: object content is immutable (no update conflicts); metadata is strongly consistent and small. Go-to mechanisms: an object store (S3-style) fronted by a CDN for delivery; a separate metadata DB (07/08) — never store the blob bytes in your relational DB; chunking + resumable + presigned uploads so bytes go client→store directly; replication or erasure coding for durability; range reads for streaming. The tell: "upload", "video", "file", "GB-sized", "download/stream".
Master table: shape → force → first bottleneck → headline mechanisms
The first table told you what each shape is. This one tells you what breaks first — the thing you should be defending in the design.
| Archetype | Dominant force | Breaks first | Headline lessons |
|---|---|---|---|
| CRUD | write correctness | write contention on the leader / lock hotspots | 12 txns, 08 repl, 09 CAP |
| Feed | read amplification | fanout fan-out cost + celebrity hot key | 06 cache, 11 queue, 07 shard |
| Queue | decoupling slow work | queue backlog / consumer lag, duplicate effects | 11 msg, 12 idemp, 05 scale |
| Streaming | ordered ingest throughput | partition throughput ceiling, consumer lag | 11 log, 07 part, 12 EOS |
| Search | index build + rank | index size/fanout, ranking CPU, freshness lag | 07 index, 06 cache, 08 repl |
| Real-time | connection count + latency | connection memory, pub/sub fanout per room | 11 pubsub, 05 LB, 09 order |
| OLAP | scan volume | scan I/O / aggregation cost, OLTP contamination | 07 part, 11 pipe, 06 rollup |
| Blob | object size + durability | storage cost, egress bandwidth, durability | 06 CDN, 13 durab, 07 meta |
How to classify in 60 seconds
Four questions pin the shape. Ask them out loud in the interview; the answers route you to a skeleton.
- Read:write ratio? Read-heavy points to Feed / Search / OLAP / Blob-read; write-heavy or balanced points to CRUD / Streaming-ingest / Queue.
- Consistency requirement — strong or eventual? Strong + correctness language → CRUD. Eventual-tolerant → almost everything else (feeds, search freshness, dashboards).
- Payload size — small rows or large blobs? Large objects (MB–GB) → Blob almost regardless of the other answers; small rows keep you in the row-shaped world.
- Interaction model — request/response, background job, continuous stream, or persistent connection? Persistent connection → Real-time; continuous high-volume stream → Streaming; fire-and-forget slow work → Queue; classic req/resp → CRUD/Feed/Search/OLAP depending on Q1–Q3.
The questions are ordered by discriminating power, which is why payload size and interaction model are asked early: they override the read:write ratio. A 4 GB video upload is a Blob system whether reads or writes dominate; a persistent-connection chat is Real-time regardless of consistency. Only after those structural signals do you let the read:write ratio and consistency requirement split the remaining request/response world (CRUD vs Feed vs Search vs OLAP). Concretely: read:write ≈ 100:1 + eventual + small + req/resp routes to Feed/Search; ≈ 1:1 + strong + small routes to CRUD; an "as of last 30 days, GROUP BY" phrasing routes to OLAP even at moderate read ratios.
And the meta-question: is it really several shapes? If the prompt names a whole product, decompose. "Design Instagram" = CRUD (accounts) + Blob (photos) + Feed (home) + Search (discover) + Queue (notifications). Pick the dominant shape to lead with and name the rest.
So this is a composite: the ingest half is Streaming (partitioned log keyed by server id, 11) and the query half is Analytics/OLAP (columnar store, pre-aggregated rollups so "p99 latency over the last 24h" reads a summary table, not 86M raw points). The link between them is a stream-processing job doing windowed rollups. Notice how naming two shapes immediately produced the architecture — log in front, OLAP behind, rollup job between — with zero box-drawing.
Decomposing a composite — a worked map
When the prompt is a whole product, do not pick one architecture; produce a shape inventory and assign each its skeleton. This is the single most senior-looking move in the first five minutes. Here is "design Instagram" decomposed:
| Sub-feature | Shape | Dominant force here | Default skeleton |
|---|---|---|---|
| Accounts, profile, settings | CRUD | write correctness | single-leader RDBMS, ACID, shard by user id |
| Photo/video storage + serving | Blob | object size, egress, durability | object store + CDN, presigned chunked upload, metadata DB |
| Home feed | Feed | read amplification, hot keys | per-user timeline cache, async hybrid fanout |
| Explore / hashtag search | Search | index build + rank | partitioned inverted index, async indexing, query cache |
| Likes/comments counters | Streaming + OLAP | high-volume events → counts | event log → windowed rollups → counter store |
| Push notifications, transcoding | Queue | slow work off the request path | message queue, idempotent workers, DLQ |
| Live / DMs (optional) | Real-time | connection count, presence | WebSocket servers + session directory + pub/sub |
Seven shapes, each with a default skeleton, derived in under a minute. You then declare the dominant one to design in depth (the feed) and treat the rest as named, defended components. The interviewer now knows you can both classify and compose.
The classification decision tree
Run the four questions top-down. The first matching rule wins, which is why blob and connection model are checked early — they dominate regardless of the read:write ratio.
From shape to a 30-second skeleton
Once the shape is fixed, you inherit a default skeleton you can recite before drawing anything. The skeleton is deliberately generic so you can then specialise it with numbers:
- CRUD → API → single-leader RDBMS (writes) + read replicas; transactions around one aggregate; shard by entity id if a single node saturates.
- Feed → write store → async fanout worker → per-user timeline cache; read path is a cache hit; hybrid push/pull for hot keys.
- Blob → presigned client upload → object store + CDN; small metadata DB beside it; erasure coding for durability.
- Streaming/OLAP → partitioned log → stream processor (windowed rollups) → columnar OLAP store; dashboards read rollups.
- Real-time → WebSocket connection servers → session directory (who's connected where) → pub/sub fanout → ephemeral presence store.
Notice each skeleton is three to five boxes and follows mechanically from the shape. The interview value is that you can produce it instantly and then spend your time on the interesting decisions — the hot-key strategy, the rollup window, the durability scheme — rather than rediscovering the obvious topology. Each shape also carries a characteristic API shape (lesson 03): CRUD is resource-oriented REST, Queue exposes an async "accept now, 202, poll/callback later" contract, Blob hands out presigned upload/download URLs, and Real-time is a persistent bidirectional channel rather than request/response — so naming the shape also defaults your interface.
The confusable pairs — where classification goes wrong
Most misclassifications are between two shapes that look alike on the surface. Knowing the discriminator for each pair is what makes your snap classification reliable.
- Queue vs Streaming. Both are "async". Discriminator: ordering and replay. A queue distributes independent tasks (send these 10k emails, order irrelevant) with competing consumers; a log is an ordered, replayable, partitioned sequence consumed by offset-tracking groups (clickstream, CDC). If you'd ever want to "rewind and reprocess from yesterday," it's streaming (11).
- CRUD vs Feed. Both store the same rows (posts). Discriminator: the dominant read. "Fetch one entity by id and mutate it under an invariant" → CRUD. "Assemble a personalized, read-amplified view from many writers" → Feed. Same table, opposite bottleneck (lock contention vs fanout).
- Search vs Feed. Both are read-heavy and eventually consistent over small records. Discriminator: query by content vs query by relationship. Ranking an inverted index over text → Search; assembling posts from people you follow → Feed.
- OLAP vs Streaming. Often two halves of one pipeline. Discriminator: ingest vs query. The write side (ordered high-volume events in) is Streaming; the read side (big GROUP-BY scans out) is OLAP. Name both and the rollup job between them.
- Blob vs CRUD. A file-sharing app has metadata that looks like CRUD. Discriminator: where the bytes live. The MB–GB payload forces the Blob skeleton (object store + CDN); the small queryable metadata is a CRUD sub-shape beside it — never inside the same store.
Try it: the archetype classifier
Set the four signals; the widget runs the same rule-based classifier as the tree above and tells you the most likely shape, its core problem, the dominant force, and the lessons to reach for. When the signals point at more than one shape it flags a composite — exactly when you should say "let me decompose this."
Interview prompts you should be ready for
- "You're given 'design Twitter' — what's the first sentence out of your mouth?" (Classify before architecting: "It's dominantly a feed/fanout shape — read-amplified, eventually consistent, hot celebrity keys — plus CRUD for accounts and blob for media; I'll lead with the timeline." Naming the shape commits you to caching + async fanout + the hybrid push/pull strategy.)
- "How do you decide CRUD vs feed/fanout when both store posts?" (The discriminator is the read pattern, not storage: if the dominant query is 'fetch one entity by id and mutate it under an invariant' it's CRUD; if it's 'assemble a personalized read-amplified view from many writers' it's feed. Same rows, opposite bottlenecks.)
- "Real-time chat seems to violate 'keep servers stateless' — reconcile that." (It's the deliberate exception: connection servers must hold the socket, so they're stateful, but you keep them shardable behind a stateless session directory and fan messages via pub/sub. State lives in the connection layer and an ephemeral presence store, not in business logic; a dropped server just forces reconnect.)
- "A prompt says 'show p95 latency by region over the last 30 days on a live serving DB' — what's wrong and what's the shape?" (That's OLAP run on OLTP — large scans will contend with serving traffic and tank p99. Separate it: stream or batch into a columnar store, pre-aggregate rollups so the dashboard reads summaries. The fix is recognizing it as analytics, not a query-tuning problem.)
- "Where does streaming differ from a job queue — aren't both 'async'?" (A queue distributes discrete tasks with no ordering guarantee and competing consumers; a log is an ordered, replayable, partitioned sequence consumed by groups that track offsets. If ordering and replay matter — clickstream, CDC — it's streaming; if independent units of slow work — it's a queue.)
- "For 'design Dropbox', why not store files in Postgres?" (Blob shape: GB objects are immutable and cheap-to-store-but-expensive-to-serve, so they belong in an object store + CDN; the relational DB holds only small queryable metadata. Mixing blobs into the OLTP DB destroys its cache locality, backup time, and replication throughput.)
- "Give me a system that is genuinely a single archetype, and one that is a composite." (Single: a URL shortener is near-pure CRUD/KV with a read cache. Composite: Instagram is CRUD + blob + feed + search + queue. The senior signal is decomposing the composite and designing the dominant shape first while naming the others.)
- "Once you've named the archetype, what stops you from over-trusting it?" (It's a hypothesis, not a verdict — I re-derive with lesson 01/02 numbers. If 'feed' turns out to have only thousands of users, fan-out-on-read with no precompute is simpler; the archetype set my defaults, the numbers set the actual design.)