API Testing / Advanced: versioned evidence and review / Lesson 16
Interpret API performance evidence offline
Calculate synthetic latency summaries and budgets without benchmarking or generating traffic.
On this page
Lesson goals
- Define workload, latency boundary, and error policy before interpreting a metric.
- Explain why averages and tiny samples cannot establish a service objective.
Define the performance question first
โThe API is fastโ is not a testable requirement until the operation, workload, measurement boundary, and acceptance rule are defined. Distinguish client-observed duration from server processing time and queue delay. Payload size, dataset shape, concurrency, cache state, and dependency behavior can all change the result. A reading-list lookup and an export job need different objectives. This lesson uses invented duration samples for arithmetic only. It does not run a benchmark, send traffic, discover capacity, or recommend a universal latency threshold for any real service.
Read a distribution rather than one average
An average can hide a slow tail. The first program compares the mean and median of ten invented observations and computes a nearest-rank ninety-fifth percentile under an explicitly stated convention. Quantile definitions differ, and a tiny sample gives poor resolution: here the selected rank is simply the largest observation. Keep units and sample count attached to every summary. A numerical result calculated correctly from fictional data is still not measured service performance. Failed, cancelled, or timed-out requests must be accounted for under the stated measurement policy rather than quietly removed.
from math import ceil
from statistics import mean, median
samples_ms = [10, 11, 12, 12, 13, 13, 14, 15, 20, 180]
ordered = sorted(samples_ms)
p95 = ordered[ceil(0.95 * len(ordered)) - 1]
assert mean(samples_ms) == 30
assert median(samples_ms) == 13
assert p95 == 180
print("mean=30ms median=13ms nearest-rank-p95=180ms n=10")
mean=30ms median=13ms nearest-rank-p95=180ms n=10
The complete program performs deterministic arithmetic on ten synthetic values. The percentile convention is nearest rank. No runtime duration is measured, and the output cannot establish a real service objective or confidence interval.
Use a budget as a planning model
A sequential path can be decomposed into explicitly assumed stages to reveal where investigation may be needed. The second example adds routing, application, and dependency allowances under a fictional total budget. It is a planning calculation, not a prediction. Parallel stages, retries, connection establishment, and queueing do not necessarily add in this simple way. A real measurement plan must define the critical path and where each duration is observed. Avoid presenting an arithmetic budget as evidence that a dependency actually meets its allowance or that every request will fit the total.
allowances_ms = {"routing": 10, "application": 25, "dependency": 40}
fictional_budget_ms = 100
planned_total = sum(allowances_ms.values())
assert planned_total == 75
assert fictional_budget_ms - planned_total == 25
print("planned=75ms unallocated=25ms")
planned=75ms unallocated=25ms
This complete local calculation leaves twenty-five milliseconds unallocated under invented assumptions. None of the stage values is measured. It is not a timeout configuration, capacity test, or recommended allocation for a deployed application.
Control the interpretation of future measurements
An approved performance experiment needs an owned disposable target, a bounded workload, explicit stop conditions, and a clear question. Those operations are outside this courseโs executable examples. When reviewing existing authorized measurements, examine warm-up, sampling method, traffic mix, error rate, and resource saturation together. Closed-loop and open-loop workloads answer different questions, and timeout exclusions can make a degraded system look faster. Compare like environments and report relevant changes rather than attributing every difference to the code revision. A single local function duration cannot stand in for end-to-end API latency.
Make regression decisions evidence-based
Choose regression thresholds from the service objective and observed variability, with enough representative evidence to support the decision. A threshold that fails on normal noise wastes review time; one that ignores meaningful tail degradation misses user impact. Diagnose whether a change affects serialization cost, query shape, dependency calls, or waiting rather than immediately increasing timeouts. Record sample counts, uncertainty, and unmeasured boundaries. Performance evidence should be reproducible and tied to a workload, while capacity and reliability claims require additional approved experiments beyond these offline calculations.
Common errors and fixes
A low average hides slow users
- Why it happens
- The report omits distribution and error behavior.
- How to fix it
- Show the relevant tail, sample count, and failed outcomes.
- Prevent it next time
- Choose metrics tied to the user-visible service objective.
Invented samples are called benchmark results
- Why it happens
- Arithmetic demonstration is confused with measurement.
- How to fix it
- Label synthetic data and state that no traffic or timing was performed.
- Prevent it next time
- Record provenance for every performance value.
Increasing timeouts is the only repair
- Why it happens
- The waiting boundary and service objective are unexplained.
- How to fix it
- Localize the bottleneck using approved evidence before changing policy.
- Prevent it next time
- Review latency, errors, and resource constraints together.
Check your understanding
1. Why does the sample p95 equal 180ms rather than a smooth value near it?
Show worked solution
The chosen nearest-rank convention selects rank ceil(0.95ร10)=10, which is the maximum sample. Other estimators can interpolate differently. State the convention and tiny sample size; none of these calculations turns ten invented values into a reliable estimate of a real service tail.
2. A report excludes every timed-out request before computing latency. What is the concern?
Show worked solution
The remaining successful requests may look fast while many users receive no result. Review timeout rate and the stated latency measurement policy together. Preserve censored or failed outcomes appropriately rather than silently filtering them, and avoid claiming improved performance from a narrower successful subset.
Key takeaways
- Performance claims require a defined workload and observation boundary.
- Distribution, sample count, units, and errors belong together.
- Synthetic arithmetic is useful planning evidence, not a benchmark.