Filter concepts by levelShowing all levels.

System Design · Section 100

High-Level Design Checklist

Level
intermediate
Read
12 min
Concepts
1

Fifteen items, held as a list because a design is rarely wrong in the part someone thought about — it is incomplete in the part nobody mentioned. They fall into five groups: what is being built (requirements, constraints, capacity), who talks to it (clients, APIs), what it is made of (services, data stores, cache, queues), what it leans on (external dependencies, deployment topology), and how it behaves (observability, security, failure handling, scaling strategy). Constraints are distinct from requirements — a requirement is what the system must do, a constraint is what you are not free to change — and capacity sits near the top because its numbers decide most of the later items rather than validating them. External dependencies deserve their own attention, since they are the parts you cannot fix during an incident and therefore set the real availability ceiling. But the behaviour group is where reviews find the most, because those four items are precisely the ones a design can omit while still looking finished: a diagram with every component drawn and no answer for "how would we know this is broken" reads as complete and is not. The list is run near the end, against a design that already exists, and each item gets one of three answers — handled in this specific way, deliberately not handled because of a stated reason, or not yet considered. The third answer is the entire point of the exercise. And each "handled" has to name a signal, a rule or a mechanism specific enough that a reviewer could disagree with it, because an answer like "the usual authn/authz" records a category rather than a decision and passes review without carrying any information.

System Design overview

What is true here

  1. Run the list near the end against a real design; a checklist tests a design and cannot generate one.
  2. Three permitted answers per item, and "not yet considered" is the one the exercise exists to surface.
  3. The behaviour group — observability, security, failure handling, scaling — is what a complete-looking diagram omits.
  4. External dependencies set the real availability ceiling, because they are what you cannot fix mid-incident.
  5. A "handled" answer must name something specific enough to disagree with, or it launders the gap instead of finding it.

What you will be able to do

  • Run the fifteen items against an existing design and produce a list of real gaps
  • Distinguish a requirement from a constraint, and place capacity early enough for its numbers to be useful
  • Recognise an answer that records a category rather than a decision, and rewrite it as a reviewable one
  • Explain why using the checklist as an opening agenda destroys the property that makes it work

The checklist

Fifteen items in five groups, three permitted answers each, run near the end against something real.

The fifteen-item high-level design checklist

coreintermediate

Fifteen items, and the reason to hold them as a list is that a design is rarely wrong in the part you thought about — it is incomplete in the part nobody mentioned. Read as a gap-finder rather than a script, the list falls into five groups. What is being built: requirements, constraints, capacity. Who talks to it: clients, APIs. What it is made of: services, data stores, caches, queues. What it depends on and where it runs: external dependencies, deployment topology. And how it behaves in the world: observability, security, failure handling, scaling strategy. The last group is where reviews find the most, because those four are the items a design can omit while still looking complete — a diagram with every component and no answer for "how would we know this is broken" reads as finished and is not. External dependencies deserve a specific mention too, because they are the parts you cannot fix during an incident, and a design that has not named them has not named its real availability ceiling. Used properly, the list is run near the end, once there is a design to test, and each item gets one of three answers: here is how we handle it, we deliberately do not handle it because X, or we have not thought about it. The third answer is the reason the checklist exists, and writing it down beats discovering it later.

Think of it as

A pre-flight checklist. Its value is not that pilots forget how to fly — it is that a list catches the one item a competent, busy person skipped, and it catches it before departure rather than in the air. It is read aloud near the end, it is answered item by item, and "not checked" is a valid answer that stops the flight. Treating it as a script to recite from the start would be useless; treating it as a final gap-finder is why it works.

text
Running the list on a design, near the end

  requirements       handled  goals + non-goals stated
  constraints        handled  must stay on existing Postgres
  capacity           handled  600 rps peak, 290 GB/yr
  clients            handled  web + mobile + 2 partners
  APIs               handled  4 endpoints, documented
  services           handled  3 services, ownership clear
  data stores        handled  1 primary, 1 index (derived)
  cache              handled  read-through, 60s TTL
  queues             handled  1 work queue, DLQ present
  external deps      handled  payment provider, mail
  deployment         handled  2 AZs, rolling deploys
  observability      NOT YET CONSIDERED   <-- the find
  security           handled  authn at gateway, authz per object
  failure handling   partial  no answer for provider outage
  scaling strategy   handled  stateless tier scales; db has headroom

Two items to fix. Neither would have surfaced
from the diagram, because the diagram was right.

What we're doing: Run the behaviour group against a design that already looks finished.

behaviour-group.txttext
The design: a document-sharing service. Every
component drawn, every arrow labelled, capacity
estimated. It looks complete.

OBSERVABILITY
  Q: how would we know sharing is broken?
  A: ... we would see errors in the logs.
  Gap: no signal for the failure that matters --
  shares that silently do not deliver. Nothing
  measures share-link opens against shares
  created, so a broken share is invisible until
  a customer reports it.

SECURITY
  Q: who can read a shared document?
  A: anyone with the link.
  Q: what happens when access is revoked?
  A: ... the link stops working.
  Gap: nothing revokes an already-issued signed
  URL before it expires. Revocation is a
  product promise the design does not keep.

FAILURE HANDLING
  Q: what happens when the storage provider is
     unavailable?
  A: uploads fail.
  Q: and reads?
  A: ... reads also fail. Everything fails.
  Gap: no degraded mode. A read-only cached
  view of recent documents would keep most of
  the product working.

SCALING STRATEGY
  Q: what breaks first at 10x?
  A: the metadata database, probably.
  Gap: "probably" is not a strategy. Which
  query, at what rate, against what ceiling?

Four items. Four real gaps. The diagram was
correct throughout.
8
This is the most common observability gap in any design: monitoring is defined in terms of errors, and the failure that matters produces no error. A share that is created and never delivered is a successful request on every dashboard.
19
Revocation is where signed-URL designs regularly break their own promise, because the URL is valid until it expires regardless of what the system later decides. Naming it here is cheaper than discovering it in a security review.
30
A degraded mode is only available if it was designed, and the checklist is the moment it gets asked about. "Everything fails" is a legitimate answer if it is a decision — it is a gap when it is a discovery.

Why this works: Every one of these four gaps sits in the group a completed-looking diagram can omit entirely, which is why the behaviour group is where a checklist earns its keep. None of them are architecture mistakes; they are questions nobody was prompted to ask, and the prompt is the entire mechanism.

Running the checklist as an agenda from the start

Wrong

text
# Minute 1: "Let's go through the checklist.
# Item 1, requirements..."
# The design is now shaped by the list's order
# rather than by the problem, and every item
# gets equal time whether or not it matters
# here.

Better

text
# Design the system. Then, near the end, run
# the list against what exists.
# Most items are already answered and take
# seconds. The value is entirely in the two or
# three that are not.

What you see: A design that covers all fifteen items uniformly and commits to nothing, with the genuinely hard part of the problem given the same three minutes as the client list.

Why: A checklist tests a design; it cannot generate one. Used up front it dictates structure and spreads attention evenly, which is the opposite of what a design needs — and it also loses the property that makes it work, which is that the answers are checked against something real rather than imagined item by item.

Fifteen items in five groups

What is being built

Requirements

Constraints

Capacity

Who talks to it · what it is made of

Clients

APIs

Services

Data stores

Cache

Queues

What it leans on

External dependencies

the real availability ceiling

Deployment topology

How it behaves

Observability

Security

Failure handling

Scaling strategy

  • What is being built
    • Requirements
    • Constraints
    • Capacity
  • Who talks to it · what it is made of
    • Clients
    • APIs
    • Services
    • Data stores
    • Cache
    • Queues
  • What it leans on
    • External dependencies — the real availability ceiling
    • Deployment topology
  • How it behaves
    • Observability
    • Security
    • Failure handling
    • Scaling strategy

The fifteen items, grouped by the question each answers

The fifteen items, grouped by the question each answers
GroupItemsThe question
What is being builtRequirements · Constraints · CapacityWhat must it do, what are we not free to change, how much of it is there?
Who talks to itClients · APIsWho calls it, over what contract, from where?
What it is made ofServices · Data stores · Cache · QueuesWhat are the parts, and which one owns what?
What it leans onExternal dependencies · Deployment topologyWhat can we not fix during an incident, and where does this run?
How it behavesObservability · Security · Failure handling · Scaling strategyHow do we know it works, keep it safe, survive failure, and grow?

The three permitted answers per item

The three permitted answers per item
AnswerMeansFollow-up
Handled: <how>There is a design for itNone
Deliberately not handled, because <reason>A scoped-out decision, on the recordRevisit when the reason changes
Not yet consideredA real gapThe most valuable output of running the list

Remember: Fifteen items in five groups: what is being built (requirements, constraints, capacity), who talks to it (clients, APIs), what it is made of (services, stores, cache, queues), what it leans on (external dependencies, deployment topology), and how it behaves (observability, security, failure handling, scaling). Run it near the end against a real design, give each item one of three answers — handled this way, deliberately not handled because X, or not yet considered — and make every "handled" specific enough that a reviewer could disagree with it. The behaviour group is where the finds are.

See also: what belongs in a high level design · moving between abstraction levels · the ten step sequence · mapping critical vs optional dependencies · symptom based alerting · defining degraded mode

Advertisement