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

Damon Kelley, Software Crafter

Damon Kelley is a Software Crafter in New York.

Interested in 8th Light's services? Let's talk.

Contact Us