ZeroCourse
Framed reading 30 minutes + canonical resource

The System Design Method: Requirements Before Architecture

Hook #

System design is where everything you've learned so far gets synthesized — data modeling, networking, distributed systems, all of it — into the skill of designing a system before you build it. And it's the skill everyone wants to jump to first, yet benefits most from doing last, because a good design is composed from the fundamentals underneath it. Here's the trap this lesson exists to prevent: faced with "design a system," the instinct is to immediately start drawing boxes — a database here, a cache there, a queue, a load balancer. That's backwards. The single most important move in system design is to resist architecture until you understand requirements, because you cannot make a good design decision without knowing what the system must do, how much load it must handle, and which qualities matter most. Requirements before architecture. This lesson is the method — a repeatable process that turns "where do I even start?" into a structured sequence you can follow every time.

What you'll be able to do by the end of this lesson #

  • Follow a repeatable system-design process: clarify requirements → estimate scale → sketch high-level design → deep-dive the hard parts → discuss trade-offs.
  • Distinguish functional requirements (what the system does) from non-functional requirements (how well — latency, availability, consistency, scale), and explain why the non-functional ones usually drive the architecture.
  • Ask the clarifying questions that scope a problem before designing (who uses it, how much, read-heavy or write-heavy, consistency needs).
  • Explain "breadth first, then selective depth" — reach a good-enough design quickly, then go deep on the two or three decisions that matter most.

A quick try before we start #

Before reading: someone says "design a URL shortener." Before drawing anything, what do you need to ask? (How many URLs created per day? How many redirects — the read load — per second? Do short codes need to be un-guessable? How long do links live? Is a slightly-stale redirect acceptable, or must it be immediately consistent?) Notice that every one of those answers changes the design — and that jumping to "use a hash and a database" before asking them is designing blind. That instinct to clarify before building is the entire discipline of this lesson.

Why this matters here #

Designing before building is a daily staff-engineer skill, not a whiteboard party trick — and treating it as mere interview prep undersells it. Every time you're handed an ambiguous "we need a system that does X," the difference between a senior and a junior response is that the senior scopes it first: what are the real requirements, what's the expected load, what qualities are non-negotiable, and therefore what's the simplest design that satisfies them. This lesson's method is that scoping discipline made explicit. It's also what makes the difference in system-design interviews (a time-pressured version of the same skill), where the most common failure isn't lack of knowledge — it's jumping to a complex architecture without establishing what's actually needed, then having no framework for the trade-offs. The methodology turns a blank-page panic into a checklist, and a checklist is what lets you think clearly under pressure.

Within the path, this course is the synthesis quarter — where the databases, networking, and distributed-systems fundamentals you've built get composed into complete systems. This first lesson is the process that organizes that composition. The rest of the course fills in the steps: estimation (lesson 2), high-level architecture and APIs (lesson 3), data modeling and scaling decisions (lesson 4), and the trade-off framework plus the Rails-scaling lens (lesson 5). And it draws directly on what came before — the requirements you gather here determine which distributed-systems trade-offs (CAP, consistency models from Quarter 9) and which data decisions (SQL vs NoSQL from Quarter 8) you'll make. System design is where the whole path pays off as judgment.

The engineer's lens #

The foundational insight is that non-functional requirements drive the architecture far more than functional ones — the what is usually easy; the how well is what forces every hard decision. The functional requirements of a URL shortener ("create a short link, redirect to the original") are trivial and would fit in a single-file script. What makes it a system design problem is the non-functional requirements: it must handle a billion redirects a day (scale), redirects must be fast (latency), it must stay up (availability), short codes must be unique (correctness). Each of those forces architectural choices — caching for read latency, replication for availability, a distributed ID scheme for uniqueness at scale. This is why experienced designers spend their first questions probing the non-functional space (how much load? how fast? how available? how consistent?), because those answers are the design constraints. It maps directly onto real work: the reason two systems with identical features have wildly different architectures is almost always their non-functional requirements — a prototype for 100 users and a platform for 100 million share a feature set but nothing else. Learning to lead with "how well must this perform, scale, and survive?" rather than "what does it do?" is the mental shift that separates system design from feature implementation, and it's the reason requirements come before architecture.

The second lens is "breadth first, then selective depth" and knowing when to stop — the discipline of reaching a good-enough design fast and going deep only where it matters, which is the opposite of the over-engineering instinct. Given a design problem, you could design forever, and the temptation — especially once you know about event sourcing, CQRS, sagas, service meshes, and every distributed pattern — is to reach for all of them. The staff-level move is the reverse: use the simplest thing that works, and be able to explain why the complex thing isn't needed yet. You sketch a complete-but-simple design quickly (breadth), identify the two or three decisions that genuinely carry risk or force trade-offs, and go deep only on those (selective depth) — leaving the rest simple. This is a learned discipline that fights a natural urge, and it's one of the highest-value habits in all of engineering: complexity is a cost you pay forever, so you add it only when a real requirement demands it, and you can articulate that demand. "We don't need a message queue here yet — a synchronous call is simpler and our load doesn't justify the operational overhead; we'll add async processing when the write volume crosses X" is a stronger answer than reflexively adding the queue. Recognizing that good design is often about what you leave out — and defending those omissions with reasoning about actual requirements — is the judgment this whole course cultivates.

What to focus on in Alex Xu Ch. 1 (+ the practice resources) #

  • The 4-step framework, internalized as a repeatable checklist. Understand requirements → estimate scale → high-level design → deep dive on the hard parts (then wrap up with trade-offs and bottlenecks). Having a fixed process eliminates "where do I start?" paralysis — develop your own version and follow it every time.
  • Functional vs. non-functional requirements, and clarifying questions. Practice the opening questions that scope a problem (users, load, read/write ratio, consistency, availability). The non-functional answers are your design constraints.
  • Breadth-first, then depth — and resisting over-engineering. Watch how the worked examples reach a simple design fast and go deep selectively. The skill is choosing which parts to deep-dive, and justifying the simple choices elsewhere.
  • Skip on first pass: memorizing specific reference architectures (design from principles, don't recall templates), and trying to "complete" every resource (pick one primary path — Alex Xu — and reference the rest). The method matters more than any single solved problem.

Explain it back #

Explain to a colleague why an experienced engineer, asked to "design a system that does X," spends the first several minutes asking questions instead of drawing an architecture. A strong answer: the architecture is driven by requirements — especially the non-functional ones (scale, latency, availability, consistency) — which the problem statement usually leaves unspecified, so designing before clarifying them means designing blind. The clarifying questions (how much load, read/write ratio, consistency needs, availability targets) establish the constraints that determine every subsequent decision; without them, you can't justify any choice. Bonus: connect this to "use the simplest thing that works and explain why the complex thing isn't needed yet" — you can only make that call once you know the actual requirements.

Where this connects #

Backward: This synthesizes the whole path — the requirements you gather determine which distributed-systems trade-offs (CAP, consistency, Quarter 9), data decisions (SQL vs NoSQL, Quarter 8), and networking realities (latency, Quarter 7) you'll apply. "Design before build" is the disciplined version of the architecture instincts running throughout.

Forward: Lesson 2 makes the "estimate scale" step concrete with back-of-envelope math. Lessons 3–4 are the high-level-design and data-modeling steps. Lesson 5 is the trade-off framework that closes every design, plus the Rails-scaling lens. And this methodology is the backbone of the whole quarter's case studies (Course 10.3) and the URL-shortener capstone — a repeatable process you'll use for every system you ever design.

That's the free preview. Sign in to continue this course.

Sign in to continue

New here? Make a desk →