intermediate 2 min answer

A team adopts a layered architecture with strict dependency rules and finds every small change touches many files. Is the architecture wrong, or the application of it?

clean-architecturelayersindirectionpragmatismatlassiantrade-off
Show the full answer Hide the answer

Usually the application

The dependency rule — that inner layers know nothing of outer ones — is sound and delivers a real benefit: business logic that can be tested and changed without infrastructure, and infrastructure that can be replaced without touching business logic.

The cost appears when the layering is applied uniformly regardless of whether a given piece of code has business logic worth protecting.

Where the ceremony is not justified

Pass-through operations. A create-read-update-delete endpoint with no business rules gains nothing from an entity, a use-case class, a repository interface, an implementation and a mapper. It gains five files and an indirection to trace, protecting logic that does not exist.

Mapping between near-identical representations. Where the domain model, the persistence model and the API model are effectively the same shape, maintaining three and mapping between them is pure cost. Distinct models are justified when they are genuinely distinct — when the API must remain stable while the domain evolves, or when persistence has constraints the domain should not inherit.

Where it is justified

Where the business logic is complex and long-lived, and where infrastructure genuinely changes. If the rules are intricate, contested and frequently revised, isolating them from persistence and transport is what keeps them testable and comprehensible.

The pragmatic resolution

Apply layering by subdomain, not uniformly. Core complex logic gets the full treatment; supporting data management gets a simple structure. This is the same classification that makes domain-driven design tractable, and it applies for the same reason.

Also worth doing: keep the dependency rule even where the layers are thin. Business logic not importing infrastructure is nearly free to maintain and delivers most of the benefit; it is the proliferation of classes and mappers that costs.

The test for any layer

What change does this layer make cheaper, and how likely is that change? A layer isolating a database you will never replace, protecting logic that is a field assignment, is paying certain indirection for a hypothetical benefit — which is the same failure as speculative abstraction generally.