My flavour of Hexagonal Architecture

Lorenzo Panzeri
5 min readApr 10, 2024

--

Today I want to deep dive into the Hexagonal Architecture, there are 2 ways of doing it: the first is write another high level article but you can find already bunch of them around, the second is actually doing an hand down project and explain every single step.

If you know me (or if you read my blog), you know the only one I can go with 😎.

As usual, you can find this project on my Github.

Before going into the real building, let’s recap why this way of structuring an application is so interesting.

About Hexagonal Architecture

First sight of this Architectural Pattern comes from a Jan 2005 blogpost of Alistair Cockburn … and no the 6 faces of an hexagon are not, at least, completely involved in the story 😅

The key idea is to set (and enforce) boundaries between the Domain (or business) logic and the external resources with the goal of achieving better abstraction while interacting with “the outside”.

These boundaries should “force” the developers to keep up the abstraction and should pay them off in 3 key points:

  • Testability: decoupling from internal logic and external resource should bring clarity in what to test and how (and should also be easier).
  • Maintenance: if something changes externally, will only impact the adapters and not the core Domain.
  • Reusability: I can move my Domain logic indipendently from the external technology that is available to use.

Now, you know, we developers are wild dogs so every implementation of Hexagonal Architecture is slighty different from another but, as soon as this principle is enforced (and some documentation with examples is provided), we can deal with it.

Let’s dig a little bit into naming conventions:

  • Ports: interfaces that allows isolated communication from the Domain to the outside.
  • Adapters: actual implementation of the Port, coupled with the technology that will actually do the job.
  • Domain: referred sometimes as Business Logic, is the functionality (and so the “real value”) of the application. Every Domain has it’s own “dictionary”, defining it should be covered in the early phase of Domain Design.

All the other naming is not always consistent in all the implementations but this is the core.

Before starting from scratch I let myself into the rabbit hole of documentation about Hexagonal Architecture and I found a lot of resources but the most useful one was this article from Ramón Bailén that gave me a solid base to start from.

How it works

As you can see there are the 3 layers: Adapters, Ports and Domain. How they are related? Like this:

  1. The Adapter is the actual implementation of an input Port, in this case a REST service, that are UseCases (what the application is capable of doing/fulfill),
  2. The UseCases as Ports have their actual Domain logic implemented into the Domain.
  3. The Domain relies another time on Port if it needs some interaction with external resources to complete the task.
  4. The Port is implemented from an Adapter, in this case to provide the persistence, bounded with the technology that the external infrastructure offers (in this case relational db with PostgreSQL)

The actual “magic” behind

To make all this decoupling works there is the need of something that acts like a “router” or better that manages the wiring related to the actual dependency injection: in my implementation this is the BeanBinder.

Actually I am wiring this:

Inbound

The Domain logic (CreateFruitUseCaseImpl & GetFruitUseCaseImpl) receives the input from the CreateFruitUseCase & GetFruitUseCase Ports that are actually implemented by the FruitRestAdapter.

Outbound

The Domain logic (CreateFruitUseCaseImpl & GetFruitUseCaseImpl) fulfils the task by leveraging the FruitPersistencePort, that is actually implemented by the FruitPersistenceAdapter.

Note: pay particular attention that I am providing the Adapter to the Domain layer but the Domain is using the Port:

The Domain is decoupled from the Adapter because there is the Port in between.

Testing

One of the benefit of the Hexagonal Architecture should be an easier and better testing: let’s see if it’s true.

You can scope your test classes on the Domain logic to test the actual behaviour of your application and on the Adapters to test the actual implementation does what is needed to cover the feature.

Pay attention that the decoupling is enforced by using also in the test the Ports instead of the Adapters into the Domain testing:

In the Adapters I am using the UseCase interface, that is a Port (even if I am mocking it):

Therefore you have an actual guideline that helps you to keep boundaries in your tests and that make easy to identify what is the scope of the test that you are writing.

Closing up

Just a quick note about

As all the things in Software Development there is no Silver Bullet: Hexagonal Architecture is only one of the possible approach that you can take. More than the architecture itself, I hope I was able to explain the core principle that you can abstract and apply when needed:

Keep always in mind the coupling and reduce it as more as possible (with common sense). The choice you made today could not be the correct one forever. Decoupling will make affordable the price to pay to change in the future: our solutions evolve with the domain, the business and the technology.

I hope this was an interesting lecture for you, as usual any feedback is more than welcome.

See you the next article! 😉

Lorenzo

--

--

Lorenzo Panzeri

Passionate Developer - Compulsive learner - Messy maker