Hexagonal architecture: when faced with two evils, choose the lesser of the two
Hexagonal Architecture aims to isolate the application and the domain from the infrastructure. The trade-off is that the infrastructure knows the domain.

Hexagonal architecture: isolating the domain
On paper, hexagonal architecture is a developer’s paradise.
And rightly so, because it allows us to write domain code and application code while abstracting away from technical contingencies, that is, the infrastructure: databases, third-party APIs, etc. We get straight to the point, the heart of the business, implementing a coherent set of business rules in isolation using Test-Driven Development, and we deliver value very quickly.
There’s no magic here, just a few well-understood patterns:
-
Dependency inversion, and the injection of these dependencies when the application starts;
-
An adapter that maps the actual dependency to the interface defined by the domain.
For us developers, this is paradise 🌞🏝️🌈 Everyone has their own version of paradise, I’ll grant you that.
Help! My domain is leaking!
Except that when it comes time to put all this into practice, it’s common to feel a vague sense of dissatisfaction. Upon further reflection, we eventually put it into words:
But there’s domain logic outside the hexagonal core! My domain is leaking!
And here’s the bad news: that’s normal.
What does that mean? If my domain changes, my adapter must change as well, since it’s a domain adaptation layer. This clearly proves that there is some business knowledge outside the hexagon.
This is the case, for example, when performing joins in an SQL query. A join uses a link between two business objects. This link is an integral part of the domain.
Suppose we want to ensure that SQL queries have no knowledge whatsoever of the domain. This would force us to use the application layer to perform joins between queries. Ouch… I’ve been there (which just goes to show that a good question can lead to bad answers).
What are the alternatives?
At that point, we had to ask ourselves what the alternatives were. We had three options:
-
Solution 1: the domain and application layers are perfectly contained within the core of the hexagon, but in exchange, the domain is aware of its dependencies;
-
Solution 2 (hexagonal architecture): a domain and an application layer that aren’t polluted by their dependencies, but in exchange, there’s a small leak of the domain outside the hexagon;
-
Solution 3: a domain and an application layer that aren’t contaminated by their dependencies, and dependencies that know nothing about the domain. It’s a beautiful idea, but it doesn’t exist.
It’s the same as medical testing protocols. A pregnancy test, for example:
-
If you don’t want any false positives, you have to accept false negatives. The right choice if you’re hoping for a baby 🐣
-
If you don’t want any false negatives, you have to accept false positives. The right choice if you don’t want children 🚫
In our case, Solution 3 isn’t really a solution, so we have to choose between Solutions 1 and 2.
Hexagonal architecture makes a firm choice to insulate the domain from the outside world, as this facilitates change and testing.