lumo

Module 01 · Lesson 5 of 14Free

Functional and non-functional requirements

Level
Beginner
Topic
System design fundamentals
Reading time
15 min

When you finish this page you can

  1. Distinguish a feature’s behavior from its quality targets and constraints.
  2. Turn vague wishes into measurable indicators and objectives.
  3. Calculate what monthly reliability targets allow.
  4. Resolve conflicting requirements through explicit product decisions.
  1. Latency and throughput: measuring speed and capacity14 min

Video lesson · coming soon

adds order tracking before its festival sale. A customer opens her order and waits 8 seconds to see “Shipped”.

The feature passes its test: it displays the right status. The customer still thinks it is broken.

What must we specify beyond “customers can track orders” to build the right feature?

A working feature can still fail

Start with two statements:

  • A customer can view the shipping status of her own order.
  • The tracking response arrives within 300 ms for at least 95% of eligible requests.

The first describes what the system does: a . The second describes how well it must do it: a .

Non-functional does not mean optional. Both belong in the design’s acceptance criteria, rather than being left for implementation teams to guess. Microsoft’s architecture guidance similarly connects functional and non-functional choices to business needs.3

Check yourselfAnswer in your head first, then reveal
Kartly always returns the correct status, but every response takes 8 seconds. Has it met the requirement “customers can track their orders”?Show answerHide answer
It may have met the narrow behavior described, but the requirement leaves acceptable waiting time undefined. The mistake is treating an incomplete requirement as proof of a good feature.

Diagram not drawn yet: kartly-tracking-requirement-chain.svg

Three connected boxes: customer problem, waiting without useful information; required behavior, view own order status; acceptance evidence, response timing and update visibility. Arrows connect the problem to behavior and behavior to evidence.

A requirement connects a customer problem to behavior you can verify. Naming a feature alone leaves that connection incomplete.

For this lesson, Kartly still has one app server and one PostgreSQL database. Tracking shows shipment status, not a live courier map.

The initial behavior is small:

Product question Agreed behavior
What can a customer see? The latest confirmed shipping status and its update time
Whose orders can she see? Only orders belonging to her account
Who changes the status? Authorised fulfilment staff
What happens after a failed refresh? Preserve the previous display and label it as not refreshed

The ownership rule describes behavior and also supports privacy. The categories can overlap. Their purpose is to reveal missing requirements, not to force every sentence into one category.

We now know what tracking does. We still need to define acceptable service.

“Fast” needs a measurement boundary

“Make tracking fast” leaves several questions unanswered. Does timing start when the customer taps, when the server receives the request, or when a database query starts?

As Latency and throughput established, the boundary changes the number.

A , or SLI, measures an aspect of service quality. A , or SLO, gives that indicator a target over a stated period. A useful indicator is often good events divided by eligible events.1

Here is Kartly’s proposed tracking agreement.

Wish Indicator Proposed objective
“It opens quickly” Fraction of eligible reads returning a valid status within 300 ms At least 95% each calendar month
“It works when needed” Fraction of eligible reads returning a valid status within 2 seconds At least 99.9% each calendar month
“Updates appear promptly” Fraction of observed committed changes displayed within 30 seconds At least 99% each calendar month

These are illustrative product targets, not measured Kartly performance or universal recommendations.

Define eligible reads as authenticated requests for an existing order owned by the requester. Time starts when the request reaches Kartly’s public entry point and ends when its response leaves.

and server errors count as bad events. A quick error does not count as a fast, valid status. Invalid requests and deliberate attempts to read someone else’s order are excluded from these service indicators.

The update objective has a different boundary. It starts when PostgreSQL confirms a status change. It applies to customers already viewing that order in an online, foreground app. An expected update that misses its deadline counts as bad, not as a missing sample.

This objective does not promise that Kartly knows about a parcel within 30 seconds of physical movement. That would require a separate agreement about how staff record shipment events.

Measurement boundaries expose promises that the system cannot make.

One extra nine removes most allowance

An is the bad-event allowance implied by an SLO. A 99.9% success objective leaves 0.1% for bad events. It is a planning limit, not permission to ignore failures.1

People often translate percentages into minutes. That is valid for a time-based measure: available time divided by total time. Request-based availability uses a different denominator.2

For the following calculation only, assume a time-based objective and an exact 30-day month.

Find the whole observation period

30 days × 24 hours/day × 60 minutes/hour = 43,200 minutes

Use the actual month length for a calendar-month report.

Calculate the 99.9% allowance

43,200 minutes × 0.001 = 43.2 minutes

That allows 43 minutes and 12 seconds of total unavailability.

Calculate the 99.99% allowance

43,200 minutes × 0.0001 = 4.32 minutes

That allows 4 minutes and 19.2 seconds. The extra nine makes the allowance ten times smaller.

Under this time-based example, a 6-minute restart exceeds the entire 99.99% allowance. It does not exceed the 99.9% allowance by itself.

But Kartly’s proposed objective counts requests. In an illustrative month with one million eligible reads, 99.9% allows 1,000 bad reads. At 99.99%, the allowance is 100.

Do not describe those request budgets as guaranteed downtime allowances. A short interruption during the festival sale can affect more requests than a longer interruption overnight.

Higher availability targets also require more demanding recovery and operating practices. Buying another server alone does not establish a service guarantee.2

For Kartly, the consequence is a question for the product owner: does reducing the allowance justify the additional engineering work?

Targets choose the refresh behavior

The simplest implementation reads the status when the customer opens the page. The app server checks ownership, reads PostgreSQL, and returns the status.

That satisfies the initial display behavior. It cannot satisfy the update objective if the customer leaves the page open.

A small improvement is : the app asks for the current status repeatedly. The question becomes how often.

How should Kartly refresh an open tracking page?

Read once when the page opens.

The page can show an old status indefinitely. This works only if customers are expected to refresh manually.

Push each update to the app.

The server sends changes over a long-lived connection. Updates can arrive sooner, but reconnecting and recovering missed changes need additional behavior.

Why this choice

Choose polling provisionally because the target allows some delay and the existing read path already works. The 20-second interval leaves part of the 30-second target for requests and rendering.

This is not a guarantee: slow networks and delayed timers can still miss the deadline. Validate the choice with measurements. Reconsider push if customers need much faster updates or repeated reads become too costly.

Diagram not drawn yet: kartly-tracking-refresh-deadline.svg

A timeline starts with a poll at zero seconds. A status change commits just afterward. The next scheduled poll starts at 20 seconds. Request and rendering time follow, with a separate deadline marker at 30 seconds. A delayed poll crosses the deadline and is labelled missed target.

The polling interval consumes part of the freshness budget. Network delay, timer delay and rendering consume the rest.

For a worked example, assume a change commits just after a poll. The next poll starts about 20 seconds later. Suppose its request and rendering take another second. The customer sees the change after about 21 seconds.

A 30-second interval leaves almost no room for that extra work. Setting an interval equal to the deadline confuses one component’s timing with the whole experience.

Server concurrency explains how the server handles overlapping reads. We will estimate their volume in Capacity estimation.

Freshness has changed client behavior. The failure objective changes what happens when refreshing cannot succeed.

A fallback can hide a failure

Suppose a refresh cannot reach PostgreSQL. The app already displays an earlier status.

Showing that status is useful, but calling it current would mislead the customer.

Should an old tracking display count as a successful refresh?

Count any displayed status as success.

The screen stays useful, but the metric can report success while customers never receive updates.

Clear the display whenever refreshing fails.

The customer loses even the information already available. This may be necessary for sensitive information, but shipment status does not require it here.

Why this choice

Kartly chooses an honest fallback. The app preserves its previous display, shows “Could not refresh”, and retains the last successful check time.

After a later read succeeds, the app replaces the status and clears the warning. If the product later requires confirmed-current information before an action, disable that action until verification succeeds.

This choice preserves information without changing the meaning of success. Google’s SLO guidance similarly distinguishes degraded service from an undegraded result.1

The privacy constraint changes a third implementation detail. The server checks ownership on every read, even when an order identifier appears difficult to guess.

If ownership cannot be verified, it returns no order information. On logout, the app clears its retained tracking display.

For this scenario, privacy wins over returning a status. It is a required rule, not something Kartly may violate within a monthly allowance.

Requirements become useful when they say what to sacrifice during a conflict.

Conflicts need an explicit owner

Suppose the team proposes two launch requirements:

  • Every tracking view must confirm the latest status.
  • Tracking must remain usable when the database cannot be reached.

If PostgreSQL is the only source of current status, the system cannot meet both during a database outage.

Do not hide that conflict behind “best effort”. Present the product owner with the consequences:

Choice Customer consequence
Require a fresh database read Tracking can fail during an outage
Permit an explicitly old display Customers keep earlier information, but it may be outdated
Add another serving path More recovery behavior must be designed and verified

For this lesson, the product owner accepts the labelled old display. Current verification remains unavailable during the outage.

Record the decision, its owner and its reconsideration condition. Here, reconsider if customers need tracking information to make a time-sensitive delivery choice.

Negotiation and clear documentation are part of architecture work, not evidence that requirements have failed. Microsoft’s guidance describes requirements refinement as an iterative, collaborative process.3

Evidence turns targets into decisions

Before launch, write acceptance checks from the agreement:

  • Delay a tracking response beyond its deadline.
  • Commit a change immediately after a poll.
  • Interrupt database access during a refresh.
  • Request another customer’s order.
  • Log out after displaying an order.

For timing, begin with controlled test clients. Compare the last observed status with the committed change, and record whether the deadline was met.

In production, entry-point measurements cover Kartly’s response boundary, not the whole phone experience. Client measurements can reveal failures outside that boundary, but introduce their own coverage limitations.1

Keep the objectives provisional until there is evidence. If measurements miss a target, investigate the cause before choosing between changing the design and negotiating the target.

Detailed operating policies belong in SLOs and error budgets.

Where this shows up

Kartly now has explicit promises; next, it needs to estimate the traffic and storage required to support them.

Common mistakes

  • Naming a technology as a requirement. “Use push” is a proposed solution. “Show updates within 30 seconds” leaves alternatives open.
  • Reporting only an average. It does not establish that the agreed fraction of requests meets the deadline.
  • Excluding inconvenient failures. A database timeout still affects the customer.
  • Treating every rule as a percentage. Protecting another customer’s information is not an error-budget tradeoff.

Check your understanding

Check yourselfAnswer in your head first, then reveal
Kartly returns an error in 50 ms. Does this count as a good event for its 300 ms objective?Show answerHide answer
No. Kartly defined good events as valid status responses within the deadline, not merely quick responses.
Check yourselfAnswer in your head first, then reveal
A time-based objective is 99.99% over an exact 30-day month. Does a 6-minute outage fit within the allowance?Show answerHide answer
No. The allowance is 4.32 minutes across the whole period, not per incident.
Check yourselfAnswer in your head first, then reveal
The team changes polling to every 30 seconds. Can it now promise every committed change appears within 30 seconds?Show answerHide answer
No. A change just after a poll already waits almost the whole interval before the next request starts. Request and rendering time add more delay.
Check yourselfAnswer in your head first, then reveal
The database is unavailable, but the app still shows yesterday’s status. Has Kartly met its successful-read objective?Show answerHide answer
No. The retained display is a useful fallback, not a successful refresh. It must remain labelled as unverified.

Summary

  1. Specify both the feature’s behavior and measurable quality targets to define what “works” means.
  2. An SLI measures service quality; an SLO sets its target and observation period.
  3. In a time-based 30-day month, 99.9% allows 43.2 minutes unavailable; 99.99% allows 4.32 minutes.
  4. Freshness, failure and privacy requirements change refresh behavior, fallback rules and ownership checks.
  5. Resolve conflicts explicitly: name what loses, who accepts that consequence and when to reconsider.

Report a mistake

Tell us what’s wrong in this lesson and we’ll fix it.