A Color Coded Guide to Ports and Adapters

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:

  • 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 will use to communicate

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.

A Color Coded Guide

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.

Layered Architecture

Most web application frameworks I have encountered, along with their associated
tutorials, promote this pattern. It may look familiar.

posts/2021-05-18-a-color-coded-guide-to-ports-and-adapters/layered-architecture.svg
Fig.1 – Three-tiered Layered Architecture diagram

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

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.

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
problem.

posts/2021-05-18-a-color-coded-guide-to-ports-and-adapters/ports-and-adapters.svg
Fig.2 – Ports and Adapters architecture diagram

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
literature.

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.

Mix and Match

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
you need!

A Color Coded Example Application

Let's look at a concrete example inspired by
the SmallerWebHexagon, which
is referenced in Alistair Cockburn's blog post on Ports and
Adapters
.

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.

posts/2021-05-18-a-color-coded-guide-to-ports-and-adapters/rating-ports-and-adapters.svg
Fig.3 – Rating application diagram

The components break down as follows:

  • RatingUseCase is an incoming port. It is the interface that
    the RatingApplication will implement, and the KtorHttpAdapter will depend
    on.

  • The 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.

  • The 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.

  • The InCodeRater is the outgoing adapter. It implements
    the 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!

  • The 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
    the RatingApplication with the InCodeRater and the KtorHttpAdapter with
    the RatingApplication and starts the server.

posts/2021-05-18-a-color-coded-guide-to-ports-and-adapters/color-coded-example-application.svg
Fig.4 – Color coded example application source code. The colors here
corresponds to the colors in the Rating application diagram.
Source code can be found here.

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.

posts/2021-05-18-a-color-coded-guide-to-ports-and-adapters/hexagonal-architecture.svg
Fig.5 – “Hexagonal” in Hexagonal Architecture stems from the common
visualization of the Ports and Adapters architecture that organizes components
around a hexagon.

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
found here.

Source: 8th Light