Skip to content
Latticework
Esc
Try
No. 016Systems & Structure

Separation of Concerns

Divide a system so each part addresses one distinct concern and can be reasoned about on its own.

“…“the separation of concerns”, which, even if not perfectly possible, is yet the only available technique for effective ordering of one's thoughts…”

Give each concern one deliberate home instead of smearing it across every part of the system.

To an executive

When each part of a system has one clear job, teams can change it safely and independently. That means faster delivery and fewer side effects from every change.

To an engineer

Give each concern one deliberate home. Give cross-cutting ones such as security, observability and tenancy their own place so they are not scattered across every module.

The idea

Edsger Dijkstra used the phrase in a 1974 note, On the role of scientific thought. He described intelligent thinking as studying one aspect of a problem in isolation, for the sake of its own consistency, while knowing that the other aspects exist. A program must be correct, and it should be efficient, but you can study each on its own day. He called this "the separation of concerns", and said that even if it is not perfectly possible, it is the only technique he knew for ordering one's thoughts effectively.

Software took the idea from thinking into structure. It is the root of layering, modularity and the split between policy and mechanism. Concerns can be functional, such as billing versus shipping, or cross-cutting, such as security, observability and tenancy. Each needs a deliberate home, or it ends up smeared across everything.

Why it works

Small heads need small problems. Nobody can hold a whole system in mind. Separating concerns lets people reason about one part at a time.

Each concern changes for its own reasons. Security rules, business rules and infrastructure change at different times. Separating them lets each change without disturbing the others.

One home makes a concern auditable. When authorisation lives in one place, you can review, test and prove it. When it is everywhere, you cannot.

Where it applies

  • Business logic versus infrastructure, so domain code does not depend on databases, queues or frameworks.
  • Cross-cutting concerns, which belong in platforms, middleware or sidecars rather than copied into every service.
  • Read and write paths, when their performance and consistency needs diverge.
  • Specification versus implementation, where Dijkstra himself drew the line: state what the system must do separately from how it does it.

How to apply

  1. List the concerns. Name the functional areas and the cross-cutting ones explicitly.
  2. Give each one home. Decide where each concern lives, and write it down.
  3. Keep the boundaries narrow. Let parts talk through small interfaces, so one concern does not leak into another.
  4. Check by change. When a change to one concern forces edits across many parts, the separation is not working.

Example scenario

Authorisation checks were scattered across 40 endpoints, each written slightly differently by different developers. An audit could not say with confidence who could do what, and a review found three endpoints where users could act on other tenants' data.

The team moved the decisions into a central policy engine with a single decision point that every endpoint called. The policies could now be read, tested and audited in one place, the three privilege-escalation bugs were closed, and new endpoints got correct authorisation by default.

Questions to ask

  • What is this component's single reason to exist, in one sentence?
  • Where does each cross-cutting concern — security, logging, tenancy — live today?
  • Can someone change this part without having to understand the rest?

When not to use it

  • Very small programs and scripts, where separation adds more structure than the problem needs.
  • Concerns that are genuinely intertwined, such as tight performance work, where separating them hides the trade-off you need to see.

How it misleads you

Over-separation creates so many layers and indirections that following a single request means opening twelve files. Dijkstra's point was clearer thinking, not more boxes. If a separation makes the system harder to understand, it is the wrong one.

Further reading

Last reviewed · Suggest an improvement