intermediate 2 min answer

A team applies hexagonal architecture and finds it adds ceremony without benefit. When does the pattern earn its cost?

hasurahexagonalports-adaptersabstractiontestability
Show the full answer Hide the answer

When it earns its cost

  • When the external dependency is genuinely replaceable and replacement is plausible. A payment provider, a storage backend, a search engine, a third-party API with a contract renewal date. The port is what makes the swap a project rather than a rewrite.
  • When the domain logic is complex and worth testing without I/O. A port with an in-memory adapter makes domain tests fast and deterministic, which for a system with substantial business rules is a large practical benefit.
  • When several adapters genuinely exist — the same domain driven by an HTTP API, a message consumer and a scheduled job.

When it is ceremony

When the adapter is one-to-one with the thing it adapts and will never be replaced. A repository interface with one implementation, mapping fields one-to-one onto a database the team will never change, is indirection that adds a file and obscures the query.

When the domain has no logic, and the "domain layer" is a pass-through between a controller and a repository. That is a large fraction of CRUD applications, and applying the pattern there produces four layers restating one concern.

The diagnostic

Count the files a small change touches. Adding one field should touch the schema, an index if performance requires it, and a policy if the field needs one. If it touches nine files across four layers, the layers are restating one concern at four altitudes rather than separating different concerns — which is layering applied by convention rather than by responsibility, and it taxes every feature for the life of the system.

Also check the opposite direction: if a cross-cutting change is cheap and a single-field change is expensive, the separation is inverted.

The middle position

Apply it at the boundaries that matter and go direct elsewhere. Ports for the third-party integrations, the datastore if replacement is plausible, and the entry points. Direct access for everything internal.

A pattern applied uniformly is a convention, not a design decision — and conventions applied without regard to whether they earn their cost are the most common source of accidental complexity in otherwise well-intentioned codebases.