Ports and Adapters is an architecture pattern that aims to decouple your application from the details. By details here, I mean things like: Your web framework of choice Your database of choice Your favorite (or least favorite) ORM A third-party API you use to support application use case(s) The application layer protocol a client and server […]
Ports and Adapters is
an architecture pattern that aims to decouple your application from the
details. By details here, I mean things like:
My experience confirms this claim. On a recent project, our team decided to
start with a Ports and Adapters architecture, which paid off as our team grew.
Our team was building a handful of services that needed to integrate. Ports and
Adapters let us push off some integrations and decouple our domain models from
our database schema, which afforded our team flexibility and insulated our
application from such details.
But there was a cost. Our architecture choice meant that folks joining our
project faced a learning curve. Most folks were unfamiliar with the pattern; or
perhaps had heard of it, but did not have hands-on experience yet.
My own path to understanding Ports and Adapters was meandering. I encountered
many diagrams on the Internet visualizing the pattern using a hexagon, but it
was hard to come by a concrete example to help me form my own mental model.
If you have had a similar experience and given up, or are currently trying to
make sense of Ports and Adapters, I offer this.
To understand Ports and Adapters, I think it is helpful to see it beside a more
common architecture pattern for web applications, like Layered Architecture.
Most web application frameworks I have encountered, along with their associated
tutorials, promote this pattern. It may look familiar.
This is what your typical Rails app might look like. A controller interacts
with your business logic, and business logic interacts with the database. This
is a fine pattern. It is simple and it can get you up and running really fast!
But the layered architecture may not always be the most suitable. For example,
on our project, a layered architecture might have been easier for newcomers to
pick up, but we would have lost nimbleness.
Ports and Adapters is like a layered architecture, but it inserts ports to
invert the direction of dependencies. It inserts ports between your controller
and your application, as well as between your application and your database
adapter or ORM.
A port is a metaphor for an Operating System port. In this example, a port
is simply an interface. However, you could also substitute a duck type, no
The ports in the diagram are the red and yellow boxes. The difference in color
here is intentional because there are two kinds of ports: an incoming port,
and a outgoing port.
Incoming ports will be the interface(s) that your application
implements. Outgoing ports are the interfaces that your application
depends on. "Incoming" and "outgoing" are the terms that our team adopted.
"Driving port" and "driven port" is the terminology you may find in other
That leaves us with adapters. Just like ports, there are two kinds of adapters:
incoming, which are represented in blue; and outgoing, which are represented in
purple. The distinction here is incoming adapters depend on the incoming port,
and outgoing adapters implement the outgoing port.
Ports and Adapters isn't just for web frameworks. The incoming adapter and the
outgoing adapter are not limited to being fulfilled by a controller and a
database adapter. They can be fulfilled by any type of adapter.
For example, a command line interface could fulfill your incoming adapter, and
an HTTP client could fulfill your outgoing port. My example depicts only one
adapter and port on the incoming and outgoing sides, but you can have as many as
Let's look at a concrete example inspired by
the SmallerWebHexagon, which
is referenced in Alistair Cockburn's blog post on Ports and
Let's say we have a web application that will accept a number and apply a rate
to it. I've color-coded the components according to the role that each plays in
the Ports and Adapters diagram.
The components break down as follows:
RatingUseCase is an incoming port. It is the interface that
RatingApplication will implement, and the
KtorHttpAdapter will depend
RatingApplication corresponds to the "Application Use Case" in the
diagrams. This where our critical business logic lives. This is arguably the
most important component, and it is kept free of details like which web
framework or ORM we are using.
RatingProvider in yellow is our outgoing port. This is the abstraction
that the application depends on to fetch the correct rate, and it is the
interface that the outgoing adapter will implement.
InCodeRater is the outgoing adapter. It implements
RatingProvider interface and fetches the rate for the application.
Imagine a future where we need to fetch this rate from a file or a
database. We can add this behavior without modifying our core application!
KtorHttpAdapter is the incoming adapter. It depends on the incoming
port, and it will accept it through its constructor. This is the adapter that
will drive our application.
Lastly, there is the
main function that configures
RatingApplication with the
InCodeRater and the
RatingApplication and starts the server.
And finally, if we shift our boxes a bit and add a hexagon around the ports
and application, we start to see a familiar diagram.
This resembles the diagrams in the original Ports and Adapters blog post and
the hundreds of images presented if you image search "Hexagonal Architecture."
Throughout this post, I use "Ports and Adapters" instead of "Hexagonal
Architecture," but they are the same. They are both fun names, but the essence
of the pattern is to invert your dependencies by depending on abstractions.
I hope seeing Ports and Adapters beside a Layered Architecture, along with
color-coded example, has unlocked this architecture pattern for you.
Reading Getting Your Hands Dirty on Clean
Architecture helped me get a solid grasp on
this pattern. The concrete examples were exactly what I needed, and I recommend
it to anyone looking for a deeper dive on the subject.
A full runnable version of the source code can be
Source: 8th Light