# The layer spine

> This section covers the layer spine, the one axis along which systems decompose, running from domain through application, processing, runtime, infrastructure…

Page: Architecture · Model
Canonical: https://banes-lab.com/software-architecture#the-layer-spine

This section is stop 54 of 102 in the learning route. Previous: [02 - Definitions own what, code owns how](https://banes-lab.com/software-architecture/model/definitions-own-what.md). Next: [04 - The direction axis](https://banes-lab.com/software-architecture/model/the-direction-axis.md). It builds on [01 - A system is a graph](https://banes-lab.com/software-architecture/model/a-system-is-a-graph.md), [25 - Placement is a grammar](https://banes-lab.com/disciplined-methodology/build/placement-is-a-grammar.md).

This section covers the layer spine, the one axis along which systems decompose, running from domain through application, processing, runtime, infrastructure and operations to product, as shown in [C1·a the spine](https://banes-lab.com/software-architecture#the-layer-spine-panel-a) and [C1·b concerns to layers](https://banes-lab.com/software-architecture#the-layer-spine-panel-b). The spine is a classification axis, and who may import whom is described separately in [the direction axis](https://banes-lab.com/software-architecture/model/the-direction-axis.md). The practice that parses a tree against the spine is described in [placement is a grammar](https://banes-lab.com/disciplined-methodology/build/placement-is-a-grammar.md) on the methodology page.

### Classification

Layering is usually a diagram, and neither the developer nor the model can say which layer a given file is on, because the layer was never derived from anything the file declares. A converter sits in a folder named for the feature it serves, the feature is renamed, and every rule that keyed on the folder now sees a file of no layer at all. A layer inferred from a folder name changes when the folder is renamed, and a layer inferred from a file's importance is argued at every review, so only a layer derived from the concern stays true without attention.

For this reason the layer spine classifies what a file is, and a file's layer is read from its concern. The layer is derived from the concern rather than from the folder or from importance. In practice, every concern in the vocabulary is tagged to one layer of the spine, and a file's layer follows from its concern. A file is classified by what it does, never by the folder it happens to sit in, and a file that fits two concerns equally well is treated as two files rather than as a tie to break. The tagging is held in data a check reads, so a layer is a derivation from the concern and never a fact the developer or the model has to remember.

To check this, take a file and derive its layer from its concern tag alone, without opening it. A file whose layer cannot be derived is outside the model, and a file whose derived layer surprises you is misclassified, or is two files. The spine orders kinds of thing and never orders importance. A product-layer file is not lower than a domain-layer file, and a layer is never a folder. Two files in one concern folder sit on the same layer because their concern does, whatever the folder above them is called.

### Belonging by kind, never by folder

Every [layered architecture](https://banes-lab.com/records/arch/layered-architecture.md) has to answer what makes a thing belong to a layer, and most answer it by folder. A folder is a rule about placement and says nothing about kind, so the layer of a file is whatever its author believed on the day. [Clean architecture](https://banes-lab.com/records/arch/clean-architecture.md) and [hexagonal architecture](https://banes-lab.com/records/arch/hexagonal-architecture.md) answer the direction question well and leave this one to taste.

The spine answers it by kind. Every concern in a [closed vocabulary](https://banes-lab.com/records/arch/closed-vocabulary.md) is tagged to one layer, the concern is decided by reading what the file does under [one concern per file](https://banes-lab.com/records/arch/one-concern-per-file.md) and the [narrowest concern](https://banes-lab.com/records/arch/narrowest-concern.md) that fits, and the layer is a derivation. [Concern-folder correspondence](https://banes-lab.com/records/arch/concern-folder-correspondence.md) makes the derivation visible in the tree, because the folder names the concern and the concern names the layer, so nothing has to be remembered.

### The seven layers

The seven layers map onto how a system decomposes rather than onto how a team is organised. The domain holds what the system is about, such as its models, records, policies and specifications. The application holds what it does with that, such as coordinators, behaviours, intents, selectors and stores. Processing holds transformation, such as converters, normalizers, analyzers, validators and pipelines.

Runtime holds what runs and when, such as entrypoints, lifecycles, timers and pools. Infrastructure holds what everything else stands on, such as registries, factories, adapters, resolvers, constants, schemas and the vocabulary itself. Operations holds observation and upkeep, such as probes, counters and reporters. Product holds what a customer meets, such as views, components, renderers, styles and the strings.

A concern belongs to exactly one layer, and a concern whose layer is contested is two concerns. A file with two concerns is a split, never a tie to break. [Layer spine precedence](https://banes-lab.com/records/arch/layer-spine-precedence.md) is the one tie-break the canon holds, and it applies only to an irreducible overlap between two tags for one concern. In that case the file classifies to the domain-ward tag, and the rule stays a classification rule, never a dependency rule.

### A converter, placed twice

Take a converter. It takes one shape and returns another, so it is processing whatever it converts and whichever feature asked for it. Put it in a folder named for the feature and it has a home but no layer, and the next feature that needs the same conversion either reaches across a boundary or copies the file.

Put it under its concern and the layer follows, the second feature finds it where the concern says it is, and a check can hold that nothing in processing reaches into product. [Separation of concerns](https://banes-lab.com/records/arch/separation-of-concerns.md) then has a mechanism behind it. [Package by feature](https://banes-lab.com/records/arch/package-by-feature.md) answers a different question, how a team navigates, and a feature cuts across every layer as a layer cuts across every feature, so only one of the two can be the folder.

C1·a the spine

```mermaid
block-beta
columns 1
domain["domain · what the system is about"]
application["application · what it does with that"]
processing["processing · how data is transformed"]
runtime["runtime · what runs and when"]
infrastructure["infrastructure · what everything else stands on"]
operations["operations · how it is observed and kept alive"]
product["product · what a customer meets"]
```

C1·b concerns to layers

```mermaid
flowchart LR
converter["converter"] --> processing["processing"]
validator["validator"] --> processing
registry["registry"] --> infrastructure["infrastructure"]
factory["factory"] --> infrastructure
view["view"] --> product["product"]
renderer["renderer"] --> product
model["model"] --> domain["domain"]
policy["policy"] --> domain
```

## Links to

- [The direction axis](https://banes-lab.com/software-architecture/model/the-direction-axis.md)
- [Placement is a grammar](https://banes-lab.com/disciplined-methodology/build/placement-is-a-grammar.md)
- [Layered Architecture](https://banes-lab.com/records/arch/layered-architecture.md)
- [Clean Architecture](https://banes-lab.com/records/arch/clean-architecture.md)
- [Hexagonal Architecture](https://banes-lab.com/records/arch/hexagonal-architecture.md)
- [Closed Vocabulary](https://banes-lab.com/records/arch/closed-vocabulary.md)
- [One Concern Per File](https://banes-lab.com/records/arch/one-concern-per-file.md)
- [Narrowest Concern](https://banes-lab.com/records/arch/narrowest-concern.md)
- [Concern-Folder Correspondence](https://banes-lab.com/records/arch/concern-folder-correspondence.md)
- [Layer Spine Precedence](https://banes-lab.com/records/arch/layer-spine-precedence.md)
- [Separation of Concerns](https://banes-lab.com/records/arch/separation-of-concerns.md)
- [Package by Feature](https://banes-lab.com/records/arch/package-by-feature.md)

## Linked from

- [Placement is a grammar](https://banes-lab.com/disciplined-methodology/build/placement-is-a-grammar.md)
- [The direction axis](https://banes-lab.com/software-architecture/model/the-direction-axis.md)
- [Containers on the spine](https://banes-lab.com/anatomy/reading/containers-on-the-spine.md)

## Evidence in the code

- [treeTab](https://banes-lab.com/source/tree/domain/converters/anatomy.converter.ts.md)
- [layersText](https://banes-lab.com/source/tree/domain/converters/anatomy.fragment.converter.ts.md)
