Requirements Scope and Measurable Service Targets

Requirements and the Design Framework · 35 min

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.

A requirement is reviewable when you can describe the workload and a test that would prove it was violated.

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.

Functional requirementAn action the product must support.
SLOA service-level objective: a target for a defined measured service indicator.
PercentileA value below which a specified fraction of observations falls, such as p99 latency.

02 Worked example

Turn “fast and available” into a contract

Requirements Scope and Measurable Service Targets worked diagram01User actionWhat must happen?02WorkloadHow much traffic?03IndicatorWhat do we measure?04ObjectiveWhat counts as good?Requirements Scope and Measurable Service Targets compact diagram01User actionWhat must happen?02WorkloadHow much traffic?03IndicatorWhat do we measure?04ObjectiveWhat counts as good?
Turn a user action into a measurable contract: define the workload, the observation point and the threshold before choosing components.
1
Start vagueThe prompt says the link service must be fast and highly available.
2
Make scope explicitInclude creating and following links; defer analytics and custom domains.
3
Choose measurable targetsAssume 500 QPS, p99 below 200 ms at the gateway, and 99.9% good requests over 30 days.
4
Add an invariantA successful creation must return a unique stored code and remain recoverable after app restart.

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

  1. 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.

  2. 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.

  3. 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.

  4. 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 code

Check 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=80

The 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 conceptRememberCheck
FeatureCreate a short linkBehavior and authorization test
Latencyp99 below a targetBoundary, workload and distribution
AvailabilityFraction of good eventsWindow and denominator
InvariantUnique ownershipConcurrent and failure tests

05 Where & why

Check the primary references

Use official references for protocol and implementation details. The questions here are teaching prompts.

Primary reference
Google SRE: service-level objectives

Read Google SRE: service-level objectives

State the implementation version and the workload assumptions when defending your own design.

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?
An action the product must support.
What does SLO mean?
A service-level objective: a target for a defined measured service indicator.
What does Percentile mean?
A value below which a specified fraction of observations falls, such as p99 latency.
Why is average latency insufficient?
Averages can hide a small group of very slow requests. A percentile objective makes the relevant tail visible, while still requiring a defined workload and measurement boundary.
What belongs in a scope box?
The supported user actions, excluded features, scale assumptions, correctness rules and service targets. It should be short enough to revisit when a new requirement appears.
Are time-based and request-based availability equivalent?
No. They weight failures differently when traffic varies. State the indicator rather than quoting a percentage without its denominator.
Can every response with HTTP 200 count as success?
Only if it also fulfills the business contract. Returning an empty result after an internal failure can make the status look good while the service fails the user.
What do you do when no target is supplied?
Propose explicit exercise assumptions, ask for corrections and proceed. Keep them visible so later design choices can be revised coherently.

07 Practice problems

Practice a new case

Solve the new cases before revealing hints. Complete worked solutions follow the set.

Classify a target

Easy
Classify exporting CSV and keeping p95 export-start latency below 1 second.
Show the hint
Separate behavior from quality.

Find ambiguity

Easy
Name two missing details in “the API is 99.99% available.”
Show the hint
Ask what is counted and over what period.

Downtime arithmetic

Medium
Calculate the time budget for 99.95% over a 28-day month.
Show the hint
Convert the full window to minutes.

Request arithmetic

Medium
For 200,000 eligible requests at a 99.9% objective, find the allowed bad-request count.
Show the hint
Use the complement of the success fraction.

Define business success

Medium
Define a good event for a booking confirmation endpoint.
Show the hint
Include the invariant, not just response timing.

Resolve conflicting targets

Hard
A product asks for instant global updates and continued writes through any network partition; write a clarification note.
Show the hint
Identify the desired behavior when regions cannot communicate.

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.