This is part of a series, start here!
This architecture, created by Alistair Cockburn in 2005, builds on the layer-based designs that came before it, putting a much bigger emphasis on the outer boundaries of the system.
Everything is I/O
Focusing on I/O to and from our application will help understand this architecture.
Try to see everything but the most core business logic as an I/O device.
- Database? I/O device.
- Messaging service? I/O device.
- GUI? I/O device.
- The web? I/O device.
We ditch the layers as we used them before and swap them for puzzle pieces of sorts, where our core business logic communicates with different types of I/O devices.
Keep this image in mind going forward.
Port
There is a really nice definition in the post Iâm leaning on to write this:
A port is a consumer agnostic entry/exit point to/from the application.
Itâs a piece of our core application that vaguely defines how we communicate with any given âI/O deviceâ, without caring about the implementation detail.
If we use a persistence port as an example, it should stay unchanged no matter if we use MySQL, MongoDB, or whatever else.
It just knows we need to persist and what parts of our domain need persistence.
In this example, it will most likely take the form of an Interface or a Trait: It defines that we need a persist(user)
functionality, but not how to implement it.
Adapter
A module that adapts to or from a specific port.
So if we are using an SQL database, its adapter will implement our persistence port and translate our domain to whatever SQL commands needed to read from or write to the database.
This, unlike its port, will not stay if we swap SQL for MongoDB. Our domain ends where our adapter starts.
This way, we decouple our domain from any particular technology we might be using.
This thought process should sound familiar, as it is, in practice, how you often implement a Repository from DDD.
Far Beyond Driven
You might have noticed that the example of a persistence port/adapter doesnât quite fit all types of infrastructure.
There is a difference between our previous SQL example and an REST API port/adapter: One is driven by our application while the other decides or drives what our application does.
Think about your typical REST API controller function, for example a GET controller that calls a GetUser
use case.
If you follow the D in SOLID, your controller should depend on that use case abstraction (interface), which will be implemented somewhere else inside the hexagon.
So the REST controller (Adapter) would use the use case (Port) which will be implemented within the boundaries of the application as part of the Business Logic.
Inwards dependency
By following these guidelines, we end up with the infrastructure related code depending on the Domain/Business Logic and not the other way around.
The Domain doesnât know a thing about a web UI, API calls, CLI, SQL, Redis, etc.
It knows its own rules and logic, it knows what it can do (driver ports) and what it needs to function (driven ports).
This allows us to focus on what actually matters, disregarding external libraries and other infrastructure as nothing more than âa thing that fits (or uses) the ports of the applicationâ.
It also has the (quite nice) added bonus of making the system really easy to test. Just swap the real adapter for a test one and you are good.
Considerations
This enforced isolation between our application and its dependencies is the most important idea Ports & Adapters has to offer.
By structuring an âus vs. themâ approach, it materializes the idea of âcore business rulesâ, which while present in previous architectures were not so clearly delineated.
Of course this only considers two concentric âlayersâ: Our code and the rest of the world. This will be expanded upon by Jeffrey Palermo three years later.
Hexagonal?
So whatâs the deal with the hexagon? Why is it called Hexagonal Architecture? What piece is repeated six times?
The shape should evoke the inside/outside asymmetry rather than top/down or let/right. Then Square is not suitable. Pentagon, Heptagon, Octagon, ⌠Too hard to draw.
So Hexagon is the winner.
Well, thatâs a bit lame. Donât get me wrong, hexagon is bestagon, but it might as well have been a circle.
âPorts & Adaptersâ is just a better name: itâs accurate and focuses your attention to what really matters and what defines this architectural design.