# Separate, trade, or mitigate

> This section covers the three mechanisms that resolve every tension the canon holds, since applying the wrong one to a pair is what turns a review into an…

Page: Architecture · Principles
Canonical: https://banes-lab.com/software-architecture/principles#separate-trade-or-mitigate

This section is stop 63 of 102 in the learning route. Previous: [07 - A tension has a mechanism](https://banes-lab.com/software-architecture/principles/a-tension-has-a-mechanism.md). Next: [01 - An anti-pattern is a decay path](https://banes-lab.com/software-architecture/decay/an-anti-pattern-is-a-decay-path.md). It builds on [07 - A tension has a mechanism](https://banes-lab.com/software-architecture/principles/a-tension-has-a-mechanism.md).

This section covers the three mechanisms that resolve every tension the canon holds, since applying the wrong one to a pair is what turns a review into an argument. Which one applies is derived in [a tension has a mechanism](https://banes-lab.com/software-architecture/principles/a-tension-has-a-mechanism.md), and the recurring pairs under each are grouped in [H1·a the recurring pairs](https://banes-lab.com/software-architecture/principles#separate-trade-or-mitigate-panel-a).

### Three mechanisms, no exemption

One mechanism is applied to every tension, so a trade-off is argued as a violation and a semantic difference is drawn as a boundary that moves every time. A team decides that [consistency](https://banes-lab.com/records/arch/consistency.md) beats availability, ships a service that refuses every request under partition, and discovers that the decision was never a boundary but an operating point that had never been measured. A quality treated as a rule has no scope to be given, so a review argues a trade-off as though it were a violation, and a semantic difference treated as a scope has no boundary to draw, so a review draws one anyway and moves it next time.

For this reason scope separation, a measured trade-off and a mitigating rule are the three mechanisms, and which one applies follows from what is on each side and where it holds. The mechanism the pair's kinds and scopes select is applied, rather than the one the reviewer prefers. In practice, where two principles hold in different scopes, the scope each holds in and what holding means there are named, and the construct under review is classified to one scope before either is applied. Where a principle meets a quality, or two principles share one scope, the thing in tension is measured where the construct lives, an operating point is chosen, and the point is written down beside the choice so it is a decision with an owner rather than a mood. Where two things share a scope and differ in meaning, the rule that names the discriminator is written. Where a construct genuinely sits on both sides of a scope boundary, it is split along the boundary rather than either rule being weakened for it.

To check this, take any resolved tension and ask which mechanism resolved it. If both sides are principles and their scopes differ, the boundary settles it and both sides survive whole. If one side is a quality, or both sides share one scope, ask where the operating point sits and who measured it. If the pair claims a discriminator, ask where it is written. None of the three mechanisms is an exemption. A resolution where one principle is weakened inside its own scope was not a boundary, an unmeasured operating point is a mood, a discriminator held only in a reviewer's judgement is not yet a rule, and an override that names no scope and no reason is not a resolution at all.

### Separated by scope

Scope separation is the mechanism the core layers were built to produce, and its pairs recur because the [computation](https://banes-lab.com/records/layer/computation-core.md) and [resource](https://banes-lab.com/records/layer/resource-core.md) scopes answer the same question with different rules. In [statelessness](https://banes-lab.com/records/arch/statelessness.md) against snapshot before mutation, a computation flows through and a resource is snapshotted before it changes. In [immutability](https://banes-lab.com/records/arch/immutability.md) against protecting state, computed data is frozen after creation and resource state is mutable but managed.

In [fail fast](https://banes-lab.com/records/arch/fail-fast.md) against explicit invalidity, a broken resource invariant halts and a computation uncertainty is marked and carried. In not building the hypothetical against under-specifying deliberately, no code is written for a feature that was never requested, and no constraint is placed on an interface that would block one later. Each pair is the derivation at work, two principles on two layers.

The canon holds the same derivation as records where it has been consulted. [Single source of truth](https://banes-lab.com/records/arch/single-source-of-truth.md) against [decentralization](https://banes-lab.com/records/arch/decentralization.md), and [autonomy](https://banes-lab.com/records/arch/autonomy.md) against [standardization](https://banes-lab.com/records/arch/standardization.md), separate because each side governs a different layer. [Normalization](https://banes-lab.com/records/arch/normalization.md) against [query performance](https://banes-lab.com/records/lex/query-performance.md) is [recorded explicitly](https://banes-lab.com/records/tension/normalization-query-performance.md), with the [canonical model](https://banes-lab.com/records/arch/canonical-model.md) normalised and only derived read models denormalised, never the store. The test of a boundary is that both sides survive it whole.

### Traded at a measured point

A trade-off cannot be scoped away, and seeing why is what stops a review from arguing one as if it were a violation. A quality is exhibited on both sides of any boundary you draw. Consistency against [availability](https://banes-lab.com/records/lex/availability.md) is strong inside one [transaction boundary](https://banes-lab.com/records/arch/transaction-boundary.md) and [eventual consistency](https://banes-lab.com/records/arch/eventual-consistency.md) across autonomy boundaries, and both halves of that sentence are an operating point the developer chose, [not a side that won](https://banes-lab.com/records/tension/availability-consistency.md). The [CAP theorem](https://banes-lab.com/records/arch/cap-theorem.md) is the reason the point exists and never the point itself.

Fail fast against [graceful degradation](https://banes-lab.com/records/arch/graceful-degradation.md) shows the other road into a trade-off. Both are principles, but both hold in the one [correctness](https://banes-lab.com/records/arch/correctness.md) scope, so there is no side for either to hold whole on. The pair is [decided](https://banes-lab.com/records/tension/fail-fast-graceful-degradation.md) by where a halt costs less than a wrong answer, which is a measurement of the failure's blast radius and never a principle outranking another.

[Encapsulation](https://banes-lab.com/records/arch/encapsulation.md) against [debuggability](https://banes-lab.com/records/lex/debuggability.md) is [settled](https://banes-lab.com/records/tension/debuggability-encapsulation.md) by hiding internals and shipping a live inspector, a point on a line rather than a wall. [Backpressure](https://banes-lab.com/records/arch/backpressure.md) against [throughput](https://banes-lab.com/records/arch/throughput.md) is [bounded producers against sustained rate](https://banes-lab.com/records/tension/backpressure-throughput.md). In each case the mechanism is the same. The quality is named, measured where the construct lives and set at a chosen point, and a record keeps who chose it and against what number.

### Mitigated by a rule

Mitigation is the mechanism for two things in one scope told apart by meaning. [Do not repeat yourself](https://banes-lab.com/records/arch/duplicate-code.md) against [locality of behaviour](https://banes-lab.com/records/lex/locality-of-behavior.md) is the recurring case. Semantics are centralised, the rules, the schemas and the one place a fact lives, and incidental co-occurrence stays local, because two passages that happen to read alike are not one fact.

No boundary separates them, since both live in the [structural](https://banes-lab.com/records/layer/structural-core.md) scope, and no measurement decides them, since neither is a quality. What resolves them is a [rule that names the discriminator](https://banes-lab.com/records/tension/do-not-repeat-yourself-dry-locality-of-behavior.md), which asks whether the sameness is semantic or textual. A discriminator written down is consultable before the collision. One held only in a reviewer's judgement is rediscovered at every clone report, and abstracted wrongly half the time.

H1·a the recurring pairs

```mermaid
flowchart TB
subgraph scope["Scope separation · both hold whole"]
a1["stateless"] -- computation · resource --- a2["state before mutation"]
b1["immutability"] -- computed data · resource state --- b2["state over code"]
c1["fail fast"] -- resource halts · computation marks --- c2["explicit invalidity"]
d1["do not build what is not needed"] -- implementation · interfaces --- d2["deliberate under-specification"]
e1["single owner"] -- runtime resources · definitions --- e2["code as data"]
g1["normalisation"] -- the canonical store · derived read models --- g2["query performance"]
end
subgraph trade["Irreducible trade-off · measured to an operating point"]
i1["consistency"] -- inside a boundary · across autonomy boundaries --- i2["availability"]
j1["fail fast"] -- where a halt is cheaper than a wrong answer --- j2["graceful degradation"]
k1["encapsulation"] -- hidden internals · a live inspector --- k2["debuggability"]
l1["backpressure"] -- bounded producers · sustained rate --- l2["throughput"]
end
subgraph mitigate["Mitigation · a rule names the discriminator"]
m1["one source of truth"] -- semantic sameness · incidental likeness --- m2["locality of behaviour"]
end
```

## Links to

- [A tension has a mechanism](https://banes-lab.com/software-architecture/principles/a-tension-has-a-mechanism.md)
- [Consistency](https://banes-lab.com/records/arch/consistency.md)
- [Computation Core](https://banes-lab.com/records/layer/computation-core.md)
- [Resource Core](https://banes-lab.com/records/layer/resource-core.md)
- [Statelessness](https://banes-lab.com/records/arch/statelessness.md)
- [Immutability](https://banes-lab.com/records/arch/immutability.md)
- [Fail Fast](https://banes-lab.com/records/arch/fail-fast.md)
- [Single Source of Truth](https://banes-lab.com/records/arch/single-source-of-truth.md)
- [Decentralization](https://banes-lab.com/records/arch/decentralization.md)
- [Autonomy](https://banes-lab.com/records/arch/autonomy.md)
- [Standardization](https://banes-lab.com/records/arch/standardization.md)
- [Normalization](https://banes-lab.com/records/arch/normalization.md)
- [Query Performance](https://banes-lab.com/records/lex/query-performance.md)
- [Normalization / Query Performance](https://banes-lab.com/records/tension/normalization-query-performance.md)
- [Canonical Model](https://banes-lab.com/records/arch/canonical-model.md)
- [Availability](https://banes-lab.com/records/lex/availability.md)
- [Transaction Boundary](https://banes-lab.com/records/arch/transaction-boundary.md)
- [Eventual Consistency](https://banes-lab.com/records/arch/eventual-consistency.md)
- [Consistency / Availability](https://banes-lab.com/records/tension/availability-consistency.md)
- [CAP Theorem](https://banes-lab.com/records/arch/cap-theorem.md)
- [Graceful Degradation](https://banes-lab.com/records/arch/graceful-degradation.md)
- [Correctness](https://banes-lab.com/records/arch/correctness.md)
- [Fail Fast / Graceful Degradation](https://banes-lab.com/records/tension/fail-fast-graceful-degradation.md)
- [Encapsulation](https://banes-lab.com/records/arch/encapsulation.md)
- [Debuggability](https://banes-lab.com/records/lex/debuggability.md)
- [Encapsulation / Debuggability](https://banes-lab.com/records/tension/debuggability-encapsulation.md)
- [Backpressure](https://banes-lab.com/records/arch/backpressure.md)
- [Throughput](https://banes-lab.com/records/arch/throughput.md)
- [Backpressure / Throughput](https://banes-lab.com/records/tension/backpressure-throughput.md)
- [Do Not Repeat Yourself (DRY)](https://banes-lab.com/records/arch/duplicate-code.md)
- [Locality of Behavior](https://banes-lab.com/records/lex/locality-of-behavior.md)
- [Structural Core](https://banes-lab.com/records/layer/structural-core.md)
- [Do Not Repeat Yourself (DRY) / Locality of Behavior](https://banes-lab.com/records/tension/do-not-repeat-yourself-dry-locality-of-behavior.md)

## Linked from

- [Every record has a kind](https://banes-lab.com/software-architecture/principles/every-record-has-a-kind.md)
- [The resolutions](https://banes-lab.com/ontology/schema/the-resolutions.md)
