A marketplace ships saved-search alerts. The functional spec is one sentence - email a seller when a new listing matches their saved query - and it works. Six weeks after launch, alerts arrive anywhere between 4 minutes and 9 hours after the listing appears, and nobody can say whether that is a defect, because no one wrote down how fresh an alert had to be. Which of these is the missing non-functional requirement?
Show the full answer Hide the answer
What separates the four
Only one of them can be violated by a running system while every feature still works. That is the test for a non-functional requirement: it states how well, at a named measurement, with a number a build can be compared against. The other three fail that test in three different and common ways.
Why the freshness target is the one that shapes the design
The 4-minutes-to-9-hours spread is not random. It is the signature of a batch job: the listing is written, and a periodic matcher picks it up on its next run. A 5-minute target and a 9-hour target buy completely different architectures, and the number decides which:
- Hours. A nightly or hourly job scans listings created since the last watermark, joins them against saved queries, and sends. One scheduled process, no new infrastructure, and the cost is a few minutes of compute a day.
- Minutes. The match has to happen close to the write. Either the listing-created event goes onto a stream and a consumer evaluates saved queries against it, or the write path enqueues the match directly. That is a queue, a consumer, a retry policy, a dead-letter path and an on-call rotation that did not previously exist.
The functional requirement is identical in both designs. It is the freshness number, and only the freshness number, that forces the second one — which is what people mean when they say non-functional requirements decide the structure.
Why the other options fail
"Highly available and performant under load" is the most common thing written in place of a requirement. Nothing can be measured against it, so no design can be shown to satisfy it and no regression can be shown to violate it. It is a wish with the grammar of a requirement.
"Delivered reliably to every seller holding a matching saved search" is the functional requirement again, wearing the word "reliably". Ask what reliably permits — is losing one alert in ten thousand acceptable? — and either a number appears, at which point it becomes a real requirement, or nothing appears, at which point it was decoration.
"Reuse the existing message broker" is a constraint, not a requirement. It is a true and useful fact about the solution space, it rules designs out, and it came from the platform team rather than from anyone who wanted alerts. Filing a constraint under requirements matters because constraints expire — the broker may be retired next year — and requirements do not.
When not to argue for a number yet
If the team genuinely does not know whether sellers care about 5 minutes or 5 hours, do not invent the number in a design document. Ship the cheap hourly version, measure how many sellers act on an alert as a function of its age, and let that curve set the target. The mistake is not choosing the wrong number; it is having no number and therefore no way to tell success from the current situation.