# An anti-pattern is a decay path

> This section covers how an anti-pattern forms.

Page: Architecture · Decay
Canonical: https://banes-lab.com/software-architecture/decay#an-anti-pattern-is-a-decay-path

This section is stop 64 of 102 in the learning route. Previous: [08 - Separate, trade, or mitigate](https://banes-lab.com/software-architecture/principles/separate-trade-or-mitigate.md). Next: [02 - Seven controls, seven classes](https://banes-lab.com/software-architecture/decay/seven-controls-seven-classes.md). It builds on [01 - Principles are typed](https://banes-lab.com/software-architecture/principles/principles-are-typed.md), [02 - Every record has a kind](https://banes-lab.com/software-architecture/principles/every-record-has-a-kind.md).

This section covers how an anti-pattern forms. A decay starts as a local shortcut that nothing refused, and it becomes dangerous the moment the shortcut becomes infrastructure, as shown in [A1·a a decay path](https://banes-lab.com/software-architecture/decay#an-anti-pattern-is-a-decay-path-panel-a) and [A1·b the propagation](https://banes-lab.com/software-architecture/decay#an-anti-pattern-is-a-decay-path-panel-b). The canon carries the class as a [contract of its own](https://banes-lab.com/records/algo/architecture-anti-pattern.md), and every anti-pattern it names is a [kind](https://banes-lab.com/records/kind/anti-pattern.md) a principle may point at and nothing else may.

### An absent control, a reproducible path

Anti-patterns are usually catalogued by how they look, and how they look is the last stage of a process that started with something missing. A module gains a second writer, then a third, each with a good reason, and by the time two of them disagree about its state no reviewer can say which change was the wrong one, because none of them was. A shortcut is cheap where it is taken and expensive where it is depended on, so blaming the first change finds a small thing, and the control whose absence let it through is invisible because absent things do not appear in reviews.

For this reason an anti-pattern is a reproducible decay path caused by the absence of a specific control. The control is repaired rather than the change that revealed it, because the next change will reveal it again. In practice, an anti-pattern is named by the control whose absence causes it, and its decay path is recorded as the sequence of stages that produces it, so it can be reproduced rather than argued about. The record also holds how it presents, which principles it violates, which signals detect it, which repairs reverse it and which gate prevents its return.

To check this, take an anti-pattern you have met and name the control whose presence would have made the first step of its decay path fail. If you cannot name one, you have named the symptom rather than the pattern. A decay path is a class, never an incident. The catalogue carries the shape, how it starts, how it presents and what was missing, and never which file or which developer, because a class transfers to a tree with nothing else in common and an incident makes the next project inherit another project's history as law.

### The path

A decay path is recorded as reproduction rather than description, and the [propagation](https://banes-lab.com/records/algo/anti-pattern-propagation-kernel.md) runs through the same stages every time. A local shortcut lands and nothing refuses it, which is where the missing control is named. The shortcut is repeated under delivery pressure until it is a convention, dependent code forms around it, and the repair is now expensive in proportion to what depends on it.

Recorded that way, the pattern becomes a test. Once the control is installed and the path replayed, the first stage should fail. [Lava flow](https://banes-lab.com/records/arch/lava-flow.md) is what a path looks like once it can no longer be replayed, as code kept because no reader knows what depends on it, and [temporal coupling](https://banes-lab.com/records/arch/temporal-coupling.md) is a path whose stages are hidden in the order things happen to be called.

### The repair

The [repair](https://banes-lab.com/records/algo/anti-pattern-remediation-algebra.md) follows the same algebra in reverse. The missing control is named, its inverse is introduced, the dependents are migrated off the shortcut, the old shape is verified absent, and its recurrence is gated.

A repair that removes one call site leaves the propagation path open and the pattern returns somewhere else. [Shotgun surgery](https://banes-lab.com/records/arch/shotgun-surgery.md) is the shape of that failed repair, one change spread across many files because the control was never installed, and [divergent change](https://banes-lab.com/records/arch/divergent-change.md) is its mirror, one file changed for many reasons because its concern was never split.

A1·a a decay path

```mermaid
flowchart TB
control["A control is absent · boundary, contract, ownership, versioning, observability, state isolation, enforcement"]
step1["A local shortcut lands · nothing refuses it"]
step2["It is repeated under pressure and becomes convention"]
step3["Dependent code forms around it · a boundary or contract erodes"]
presents["Systemic fragility · the anti-pattern, reproducible, named, detectable"]
repair["The repair · install the inverse control, migrate the dependents, check the absence, gate the recurrence"]
control --> step1 --> step2 --> step3 --> presents --> repair
```

A1·b the propagation

```mermaid
stateDiagram-v2
[*] --> Shortcut : a control is absent
Shortcut --> Repetition : nothing refuses it
Repetition --> Convention : delivery pressure
Convention --> Dependency : code forms around it
Dependency --> Fragility : the boundary erodes
Fragility --> Repair : the pattern is named
Repair --> [*] : inverse control installed · dependents migrated · recurrence gated
Repair --> Shortcut : one call site removed · the path stays open
```

## Links to

- [<Architecture Anti-Pattern>](https://banes-lab.com/records/algo/architecture-anti-pattern.md)
- [anti-pattern](https://banes-lab.com/records/kind/anti-pattern.md)
- [Anti-Pattern Propagation Kernel](https://banes-lab.com/records/algo/anti-pattern-propagation-kernel.md)
- [Lava Flow](https://banes-lab.com/records/arch/lava-flow.md)
- [Temporal Coupling](https://banes-lab.com/records/arch/temporal-coupling.md)
- [Anti-Pattern Remediation Algebra](https://banes-lab.com/records/algo/anti-pattern-remediation-algebra.md)
- [Shotgun Surgery](https://banes-lab.com/records/arch/shotgun-surgery.md)
- [Divergent Change](https://banes-lab.com/records/arch/divergent-change.md)

## Linked from

- [The gate holds the line](https://banes-lab.com/disciplined-methodology/build/the-gate-holds-the-line.md)
- [A check matches a shape](https://banes-lab.com/disciplined-methodology/build/a-check-matches-a-shape.md)
- [What the diagnoses found](https://banes-lab.com/anatomy/reading/what-the-diagnoses-found.md)
