A reading, not a verdict

Why It Is There

Every layer running beside your application is answering something. The useful question is what.

Caches, object-relational mappers, message queues, distributed locks, application servers, orchestration clusters, whole operating systems. These are the standard furniture of a serious deployment — assumed by reference architectures, budgeted for, staffed, monitored. Each one was added by someone solving a real problem.

Some of them are answering the problem the software exists for. Others are answering a constraint of the model underneath — how state is stored, and what that costs in reads, in contention, in coordination. Both are legitimate answers to real pressure. What differs is where the pressure comes from, and whether it would still be there if the model underneath worked differently.

The goal is not to decide whether a technology belongs in your architecture. It is to understand why it is there.

Two questions

Asked in this order, they describe rather than judge.

01

Name the pressure

What is this layer responding to? Not the benefit — the pressure. “It is faster” names a benefit and stops the enquiry. “The model serialises writes against a shared store” names a pressure, and everything downstream depends on that sentence being said plainly. If nothing can be named, the layer is either doing the problem's own work, or answering something outside what this reading can see.

02

Then change the constraint

Now picture that pressure absent — not engineered around, but not arising, because the model underneath stores things differently. Does the layer still have a job? If it does, it was answering the problem all along. If it does not, it was answering the model. Neither answer says the layer should go.

How to read one

One layer, one use, one reading.

The unit is not the product. It is the pair: this layer, for this use. The same product routinely reads differently for two of its uses in the same building, which is why it is read once per use rather than once per logo on the diagram.

  1. Take one layer and one thing you use it for. Say out loud what pressure it is answering.
  2. If you can name one, ask whether the layer would still have a job in a model where that pressure does not arise.
  3. Still has a job → structural. It is answering your problem, and it would be there under any model.nothing follows from this one; it is where the enquiry stops
  4. No job left → model-dependent, and you now have the constraint written down beside it.worth knowing; not by itself a reason to change anything
  5. Nothing nameable, and the reason is organisational, regulatory, historical, or a question of what the team knows well → unclassified.a real answer, not a gap in the analysis

The third outcome is what keeps the other two honest. Plenty of layers are there for reasons a technical reading cannot see — a contract, a migration nobody has budget for, ten years of operational knowledge. Without somewhere to record those, a reading quietly files them under one of the other two and starts arguing with them.

A worked case

The in-memory store in front of the database.

Almost every stack has one, and it is the clearest case to read because it answers so many different pressures under one familiar name. Run the two questions across the things it is actually used for, and the readings do not come out the same — which is the point of reading per use rather than per product.

What it is used forThe pressure it answersReading
Caching database resultsReads and writes compete at the storage layer, and rebuilding state from storage is expensiveModel-dependent
Holding sessionsStateless application servers keep nothing between requests, by designModel-dependent
Publish and subscribe between your own componentsThere is no shared record of what happened across components, so coordination is reconstructedModel-dependent
A queue for deferred workWork handed from one component to another arrives without the record of what caused itModel-dependent
A distributed lock over a shared entitySeveral processes write the same logical thing from different placesModel-dependent
Leaderboards and running totalsAggregating in real time against the storage layer is expensiveModel-dependent
Publish and subscribe to systems outside your boundaryNot the model's. Webhooks, partners and subscribers stay exactly as they are however you store thingsStructural
Rate limiting external trafficNot the model's. A quota describes your relationship with the other partyStructural

Six of eight, and then two that do not move — and the two that do not move are the interesting ones. A reading that returned the same answer for all eight would be describing itself rather than your stack. It is also worth saying what the six do not mean: every one of those uses is a real solution to a real pressure, and the reading says where the pressure comes from, not whether the choice was right.

It is a ladder, not a list

Each rung answers a wider version of the same pressure.

Read in order, the canonical layers are not an inventory. They climb, and what they climb is the radius of what is being answered — from inside one process to the machine the whole thing runs on.

  1. Within one processThe in-memory cache
  2. Within the applicationThe object-relational mapper
  3. Between processesThe message queue and the distributed lock
  4. The application stackThe application server framework
  5. Across machinesThe orchestration cluster
  6. The hosting substrate itselfThe whole operating system

The ladder is open at the top. Backup tooling, the service mesh and distributed tracing extend it, and the layers not yet invented will extend it further — each answering a wider version of what the rung below answers.

What a reading is worth

A model-dependent reading is not an argument for removing anything.

Teams keep such layers for good reasons: something that works and has worked for years, a contract that requires it, a migration nobody has budget for, people who know it deeply. All of that is rational, and a reading that ignored it would be worth less, not more. What changes afterwards is only that the layer's presence is understood — tied to the model underneath rather than to the problem — which is something a team can weigh, rather than something inherited without a reason attached.

One consequence is worth knowing before anyone reaches for a replacement: when two layers are answering the same constraint, exchanging one for the other leaves the reading where it was. That is not a comment on either product. It is that the reading was never about the product — it was about the constraint, and the constraint is a property of the model.