Layered vs hexagonal architecture
“Compare layered architecture with hexagonal (ports and adapters). What problem does hexagonal solve that layers do not, and when is the difference not worth the extra structure?”
What this tests
- Understanding of dependency direction, not just layer names
- Whether the candidate knows the concrete problem hexagonal solves (domain depending on infrastructure)
- Testability as a consequence of structure
- Judgment about when the extra abstraction is not paid for
Answers by level
Read the beginner answer first and notice what is missing.
In a classic layered stack the arrows point down: controller → service → repository → database driver. The problem is that the domain layer ends up depending on the infrastructure layer, so business rules import the ORM, the tests need a database, and swapping the storage means editing the domain. Hexagonal inverts that one arrow: the domain defines a port (an interface such as OrderRepository), and the database adapter implements it. All dependencies point at the domain.
What that buys is concrete: the domain compiles without the database, a unit test injects an in-memory adapter and runs in milliseconds, and the same domain can be driven by a REST controller, a queue consumer or a CLI without change. The cost is the interface and the wiring: an extra type per external dependency and a composition root that assembles adapters.
For a CRUD service with little business logic, the domain is thin and the ports mostly wrap a repository one-to-one; the interfaces then add files without adding safety. Layers with a rule that the domain does not import the driver get most of the benefit.
Green flags · Red flags
- Explains the difference as dependency direction, not box arrangement
- Names the concrete failure: domain importing the ORM or driver
- Ties ports to testability with in-memory adapters
- States when the abstraction is not worth it (thin CRUD)
- Mentions enforcing the rule in CI
- "Hexagonal is more modern, so use it for everything."
- Cannot say which way the arrow points between domain and repository
- Thinks layers are about folder names
- Adds interfaces with exactly one implementation everywhere and calls that decoupling