---
id: PERF01
pillar: performance-efficiency
title: PERF 1. How do you derive performance targets from user expectations?
description: Without a stated target, performance work has no completion criterion and no failure criterion. It continues until someone loses interest or a budget runs out.
status: draft
services: []
sidebar:
  order: 10
  label: Performance targets
source_url: "https://framework.stackit.cloud/architecture/pillars/performance-efficiency/perf-01-performance-targets/"
source_file: "docs/architecture/pillars/performance-efficiency/perf-01-performance-targets.mdx"
---

"Fast" is not a specification. Without a number, nobody can say whether the current behaviour is
adequate, whether a change made things worse, or when to stop optimizing. The work continues until
attention moves elsewhere.

The number comes from the people the system serves. It is not derivable from infrastructure
capability, and a benchmark result tells you what the system does rather than what it should do.

## Best practices

- [`PERF 1.1`](/architecture/pillars/performance-efficiency/perf-01-performance-targets/#perf-11-state-the-target-per-flow-at-a-percentile-under-a-defined-load) State the target per flow, at a percentile, under a defined load
- [`PERF 1.2`](/architecture/pillars/performance-efficiency/perf-01-performance-targets/#perf-12-derive-it-from-what-users-and-downstream-systems-actually-need) Derive it from what users and downstream systems actually need
- [`PERF 1.3`](/architecture/pillars/performance-efficiency/perf-01-performance-targets/#perf-13-have-it-agreed-by-someone-who-represents-the-users) Have it agreed by someone who represents the users
- [`PERF 1.4`](/architecture/pillars/performance-efficiency/perf-01-performance-targets/#perf-14-keep-the-target-separate-from-the-current-behaviour) Keep the target separate from the current behaviour

---

## PERF 1.1 State the target per flow, at a percentile, under a defined load

**Risk if not established:** Medium

Three components, and a target missing any of them cannot be tested.

**Per flow**, using the ranking from [`REL 2.2`](/architecture/pillars/reliability/rel-02-critical-flows/#rel-22-rank-flows-by-the-consequence-of-failure-rather-than-by-traffic-volume). The checkout path and the monthly report have
different requirements, and one number applied to both is wrong for at least one of them.

**At a percentile**, not as an average. An average hides the tail, and the tail is where users
notice. A system averaging 200 milliseconds with a 95th percentile of four seconds is a system
where one request in twenty is unacceptable, and the average will not tell you.

**Under a defined load**, because latency without a throughput figure is meaningless. A system
that meets its target at a hundred requests per second and misses it at a thousand has no single
answer, and which one you meant is the whole question.

Different flow types need different shapes of target. Interactive requests need latency. Batch
processing needs a completion deadline. Streaming needs sustained throughput. Using latency for
all three produces a target that does not describe what anyone cares about.

**On STACKIT.** Nothing on the platform supplies your target. It comes from the business, as
[`REL 1.1`](/architecture/pillars/reliability/rel-01-reliability-targets/#rel-11-quantify-what-an-outage-and-what-data-loss-cost-the-business) does for reliability.

The one platform-side note is that STACKIT's published service commitments cover availability
rather than latency, so they constrain [`REL 1.3`](/architecture/pillars/reliability/rel-01-reliability-targets/#rel-13-check-every-target-against-the-published-availability-of-the-services-it-depends-on) and not this question. Performance ceilings on
the platform appear as capacity characteristics of the option you choose, which is [`PERF 3`](/architecture/pillars/performance-efficiency/perf-03-service-selection-and-sizing/).

**Tradeoffs.** None between pillars. The cost is stakeholder time to agree, and the first attempt is
usually wrong. A rough target that gets refined beats no target, because it can at least be tested.

**Verify.** For your highest-ranked flow, what is the latency target, at which percentile, and
under what load? If any of the three is missing, what would you compare a measurement against?

---

## PERF 1.2 Derive it from what users and downstream systems actually need

**Risk if not established:** Medium

Targets pulled from a round number are arbitrary, and arbitrary targets are either unreachable or
so loose that nothing is ever measured against them.

Three sources give a defensible figure. **User perception** for interactive flows, where the
question is what feels responsive for this kind of interaction rather than what is technically
achievable. **Downstream commitments**, where another system depends on your response and its own
target constrains yours. **Business process deadlines**, where a batch has to finish before
something else can start.

Where the requirement is genuinely soft, say so and pick a figure that is achievable, then tighten
it if complaints arrive. A target nobody can justify is better than none provided it is honest
about being provisional.

Look for the flows where the target is much stricter than anyone assumed. A background job feeding
a customer-visible cache inherits the customer's expectation, which is not obvious from looking at
the job.

**On STACKIT.** No platform feature applies. This is a conversation with the people who use the
system.

**Tradeoffs.** **Cost Optimization.** A strict target justifies capacity that a loose one does
not, which is why the source of the figure matters. A target derived from user need can be
defended in a cost review; one derived from ambition cannot.

**Verify.** For each target, what is it based on? How many can you trace to a user expectation, a
downstream commitment or a business deadline rather than to a preference?

---

## PERF 1.3 Have it agreed by someone who represents the users

**Risk if not established:** Medium

An unowned target erodes. Under delivery pressure the acceptable latency creeps upward, each step
individually defensible, until the system is materially slower than anyone intended and no
decision was ever made.

An agreed target with a name against it turns each of those steps into a decision somebody has to
make explicitly. That is its main function, and it is the same mechanism [`REL 1.4`](/architecture/pillars/reliability/rel-01-reliability-targets/#rel-14-have-each-target-agreed-and-recorded-by-someone-accountable-for-the-outcome) uses.

Record what was agreed, by whom, when, and what it was based on. The reasoning ages faster than
the number, and a target whose justification nobody can reconstruct will be treated as arbitrary
the first time it is inconvenient.

Set a revisit trigger rather than a date: a change in usage pattern, a new client type, or a
material change to the flow.

**On STACKIT.** No platform feature applies. The record belongs wherever architecture decisions
live.

**Tradeoffs.** **Operational Excellence.** Another artefact to keep current, and a stale target is
worse than none because it carries authority it no longer deserves.

**Verify.** Who agreed the latency target for your most critical flow, when, and where is that
recorded?

---

## PERF 1.4 Keep the target separate from the current behaviour

**Risk if not established:** Medium

A target calculated from what the system currently does is not a target. It is a description, and
it will move whenever the system does, which makes it useless for detecting that the system got
worse.

Keep the two apart deliberately. The **target** is what the flow must achieve, set from `PERF
1.2`. The **baseline** is what it currently achieves, measured under [`PERF 2`](/architecture/pillars/performance-efficiency/perf-02-baseline/). Comparing them
tells you whether you have a problem; comparing the baseline with itself over time tells you
whether you have a regression. Both are needed and they answer different questions.

The failure mode is subtle: teams that only track the baseline detect regressions and never notice
that the system has been below target since it launched. Teams that only track the target notice
they are failing and cannot say when it started.

Where the current behaviour is far from the target, that gap is a piece of information rather than
an argument for changing the target. Record it as an accepted risk under [`REL 3.4`](/architecture/pillars/reliability/rel-03-failure-mode-analysis/#rel-34-record-accepted-risks-explicitly-with-who-accepted-them) if it will not
be closed.

**On STACKIT.**
<LinkChip href="https://docs.stackit.cloud/products/logging-and-monitoring/observability/">Observability</LinkChip> holds
the measurement, and expressing the target as an alerting threshold is what makes the comparison
automatic rather than a periodic review.

**Tradeoffs.** Little. The cost is the discipline of maintaining two numbers where one feels
sufficient.

**Verify.** For your critical flows, what is the target and what is the current measured value? If
those are the same number, which one moved to make it so?

---

## Related

- [`REL 2.2`](/architecture/pillars/reliability/rel-02-critical-flows/#rel-22-rank-flows-by-the-consequence-of-failure-rather-than-by-traffic-volume) Flow ranking, which this attaches targets to
- [`PERF 2`](/architecture/pillars/performance-efficiency/perf-02-baseline/) Baseline, which measures against these targets
- [`PERF 3`](/architecture/pillars/performance-efficiency/perf-03-service-selection-and-sizing/) Selection and sizing, which the target constrains
- [`REL 1`](/architecture/pillars/reliability/rel-01-reliability-targets/) Reliability targets, set by the same conversation with the same people
- [`COST 7`](/architecture/pillars/cost-optimization/cost-07-flow-based-optimization/) Flow-based optimization, which uses the same ranking
