System Design · Module 1 · Lesson 2 of 4 · 35 min
Requirements Scope and Measurable Service Targets
Turn vague product language into a scope box, correctness rules, a workload and measurable latency and availability targets.
01 The idea
The problem this lesson solves
“Build a fast, reliable link service” sounds like a requirement, but it does not tell you what to test. A response that takes 300 ms might be excellent for one product and unacceptable for another. A system that serves old destinations during an outage might satisfy a browsing tool and violate a safety-critical redirect policy. In this lesson you turn those ambiguous words into a contract that guides architecture and gives you a way to reject an unsuitable design.
You need basic programming and arithmetic. This module introduces the design vocabulary; the next module develops HTTP step by step.
02 Worked example
Turn “fast and available” into a contract
03 The method
Understand the mechanism
Separate actions, invariants and quality targets
A functional requirement describes an action: create a link, follow a link, edit a destination or list an owner’s links. An invariant describes a rule that must remain true: one code cannot identify two different active mappings, and a caller cannot edit another owner’s link. A quality target describes how the service performs those actions: latency, successful-request fraction, durability or recovery time.
These categories need different tests. An endpoint test can demonstrate link creation. A concurrent insertion test can expose a uniqueness violation. A load test can measure latency at a stated traffic level. A failover or restore drill can assess a recovery claim. One successful demonstration does not establish all four.
Start the exercise with creation and redirect in scope. Include destination editing only if you want to teach cache invalidation; an immutable mapping has a different freshness problem. Explicitly defer click analytics, custom domains and billing. These are legitimate features, but including them changes data volume, authorization and background processing.
The scope is not a permanent product roadmap. It is the boundary of the design being assessed. If a later question adds analytics, update the write workload and response contract instead of quietly assuming the original architecture already covers it.
Define the workload as a distribution
“A million users” is not a request rate. Some users may never return, while a small group makes many requests. Describe active users, operations per user, read/write mix, peak factors, payload sizes and geographic distribution. A service with many registered accounts and few active users can need less capacity than a smaller service with intensive usage.
For this requirements exercise, assume a single region and 500 redirect requests per second at the gateway. Management writes are a separate workload. Say whether 500 is a sustained peak or a short burst, and whether the payload includes only headers or a larger response body. These details determine which resource is likely to matter.
Distribution matters within the workload too. If one viral link receives half the reads, aggregate QPS can conceal a hot key. If traffic arrives in a one-second spike, a one-minute average hides the queue that forms. If writes update the same row, lock contention can dominate despite a modest total write rate.
Record unknowns as assumptions rather than disguising them as facts. You can reason with an assumed 5× peak factor, but the eventual system should compare it with observed traffic. The design becomes revisable because its inputs are visible.
Read percentiles without confusing them with averages
Latency is a duration measured between two boundaries. Browser navigation time includes work that an application timer may exclude, such as DNS, connection setup and network transfer. A target should name its boundary before it names a number.
An average adds every observed duration and divides by the count. A percentile describes a position in the sorted distribution. Using the nearest-rank convention on 100 requests, p99 is the 99th sorted observation. Consider 98 requests at 20 ms and 2 at 1,000 ms. The mean is (98×20 + 2×1,000)/100 = 39.6 ms, but p99 is 1,000 ms. A low average can coexist with a poor tail.
Our example target is p99 below 200 ms at the gateway under the stated 500-QPS workload. Define whether failed attempts count in the latency series and pair latency with an error objective. Dropping failed requests from all reports could make a failing service appear fast.
Do not add component percentiles to manufacture an end-to-end percentile. The 99th-percentile database request and the 99th-percentile network delay may occur on different requests, or they may be correlated. Measure the end-to-end distribution and use traces to understand which components contribute to its tail.
Build an availability indicator with an honest denominator
A service-level indicator, or SLI, is the measurement. A service-level objective, or SLO, is a target for that measurement over a window. For request-based availability, define good eligible requests divided by all eligible requests. The denominator matters as much as the percentage.
Suppose 200,000 eligible redirects arrive and 120 fail because of server errors. The good fraction is 199,880/200,000 = 99.94%. Against a 99.9% objective, the total allowance is 200 bad requests, so 80 remain for that particular window. This arithmetic says nothing about how those failures are distributed among users.
A time-based objective weights unavailable minutes, while a request-based objective weights requests. For a 30-day window, 0.1% of 43,200 minutes is 43.2 minutes. That is a downtime allowance only for the time-based definition. A ten-minute outage during a traffic peak can consume much more than ten quiet minutes of a request-based budget.
Specify which client errors are eligible and why. Excluding clearly invalid requests can be reasonable. Excluding server-generated errors because they lower the score defeats the purpose. A response also needs correct business meaning: returning 200 with an invented empty destination is not a good redirect.
Turn the target into an operating decision
An error budget is the permitted amount of failure implied by the objective. It creates a common language for discussing release risk and reliability work. It is not permission to deliberately break the system until the allowance is exhausted.
If the service is consuming its allowance rapidly, a team might slow risky releases and investigate the dominant failure mode. If the budget remains healthy, shipping useful changes may be appropriate. The specific policy belongs to the organization; the architectural lesson is that reliability work should be tied to measurable user impact.
Separate availability from durability. A service may be temporarily unreachable while retaining every committed mapping. Conversely, it may return responses promptly after restoring an old backup that lost yesterday’s data. Recovery point objective describes the acceptable data-loss window; recovery time objective describes the acceptable time to restore service. Both need explicit definitions and tests.
For example, “restore within one hour with at most five minutes of lost writes” requires evidence about backup freshness, log capture, restore speed and cutover. A box labeled backup does not establish those properties. The requirement tells you which recovery experiment to perform.
Resolve competing requirements before choosing machinery
Suppose destination changes must be visible immediately everywhere, but every region must also accept updates while disconnected from the others. Ask what should happen when two isolated regions change a7 to different destinations. The conflict is about permitted behavior, not a missing database logo.
Possible contracts include assigning one authoritative writer and refusing some writes while it is unreachable, accepting updates locally and later resolving conflicts, or weakening the immediate-visibility requirement for selected operations. Each choice changes what users observe. The first step is to name the operation and failure condition clearly.
Keep a short requirements record with four fields per item: statement, workload or failure boundary, measurement, and acceptance test. “One code maps to one destination” can be tested with concurrent code creation. “p99 under 200 ms” needs a load profile and gateway measurement. “Survive an app restart” needs a restart test after an acknowledged write.
This record is the foundation for later trade-offs. When someone proposes a cache, you can ask which latency or capacity target it helps and which freshness requirement it complicates. When someone proposes a replica, you can ask which reads may tolerate lag.
Guided tutorial
Draft a concrete requirements record
Create four entries: create a link, follow a link, prevent duplicate code ownership, and meet the gateway latency target. For each, write an acceptance test. For uniqueness, run two attempted inserts of a7 with different destinations and require at most one success. For latency, state 500 QPS and the observation boundary.
Compute the tail and budget
Use 98 observations of 20 ms and 2 observations of 1,000 ms. Sort them and calculate the mean and nearest-rank p99: 39.6 ms and 1,000 ms. Then compute the bad-request allowance for 200,000 eligible requests at 99.9%: 200. Explain why these are different measurements of quality.
Test an ambiguous success
Imagine the database times out and the API returns 200 with an empty destination. Mark this as a failed business operation even though the status is 200. Update your good-event definition so it requires the documented redirect outcome and not merely a successful status family.
Review a failure requirement
Write an app-restart test: create a7, wait for success, restart the app, then follow a7. Next write a database-restore test with explicit recovery time and data-loss limits. These tests expose why surviving one process restart is a narrower promise than surviving a storage failure.
Example requirements
scope: create links, follow links
workload: 500 redirect requests/second, one region
latency: p99 below 200 ms, measured at the gateway
availability: good / eligible requests >= 0.999 over 30 days
correctness: a successful create has one durable unique codeCheck your result
Your design brief states 500 redirect requests/s, p99 below 200 ms at the gateway, and at least 99.9% good requests over 30 days. Define which requests count as eligible.
Calculate a percentile and an error budget
Run this with Python 3. The nearest-rank convention is explicit, and the two slow requests remain in the measured population.
from math import ceil
latencies_ms = sorted([20] * 98 + [1000] * 2)
mean = sum(latencies_ms) / len(latencies_ms)
p99 = latencies_ms[ceil(0.99 * len(latencies_ms)) - 1]
eligible, bad, allowed_bad = 200000, 120, 200
print(f"mean_ms={mean:.1f}, p99_ms={p99}")
print(f"good_percent={(eligible-bad)/eligible*100:.2f}")
print(f"remaining_bad_requests={allowed_bad-bad}")
Expected output
mean_ms=39.6, p99_ms=1000
good_percent=99.94
remaining_bad_requests=80The mean hides the tail. The remaining allowance is a request count for this window, not a number of downtime minutes. Change the two slow values and observe that latency changes independently of the separately modeled error count.
04 Cheat sheet
Review the decisions
Use this table to explain the mechanism and its limit without memorizing a product name.
| Choice or concept | Remember | Check |
|---|---|---|
| Feature | Create a short link | Behavior and authorization test |
| Latency | p99 below a target | Boundary, workload and distribution |
| Availability | Fraction of good events | Window and denominator |
| Invariant | Unique ownership | Concurrent and failure tests |
05 Where & why
Check the primary references
Use official references for protocol and implementation details. The questions here are teaching prompts.
06 Interview questions
Explain the reasoning out loud
Answer before opening the explanation. The questions progress from vocabulary to decisions and failure behavior.
What does Functional requirement mean?
What does SLO mean?
What does Percentile mean?
Why is average latency insufficient?
What belongs in a scope box?
Are time-based and request-based availability equivalent?
Can every response with HTTP 200 count as success?
What do you do when no target is supplied?
07 Practice problems
Practice a new case
Solve the new cases before revealing hints. Complete worked solutions follow the set.
Classify a target
EasyShow the hint
Find ambiguity
EasyShow the hint
Downtime arithmetic
MediumShow the hint
Request arithmetic
MediumShow the hint
Define business success
MediumShow the hint
Resolve conflicting targets
HardShow the hint
Worked solutions
1. Classify a target
CSV export is functional. The p95 target is a performance objective and needs a workload and measurement boundary.
2. Find ambiguity
The service indicator and observation window are missing. Also clarify eligible requests, success semantics and whether the indicator is time-based or request-based.
3. Downtime arithmetic
28 × 24 × 60 = 40,320 minutes; 0.05% unavailable permits 20.16 minutes.
4. Request arithmetic
0.1% of 200,000 is 200 bad requests. This is a count budget for the chosen window, not a duration budget.
5. Define business success
A good event returns the documented response within the target and confirms ownership of the correct seat under the booking contract. Internal errors and false confirmations are bad events.
6. Resolve conflicting targets
Ask which operations require immediate agreement, which can be temporarily unavailable, and which can accept conflicts or staleness. Specify the partition behavior per operation before promising both targets together.