typing machine

adesso blog

Joining a new project means learning fast; new domain, new concepts, new architecture. One term stood out: Hexagonal Architecture. My team had already decided to redesign their old architecture in a more modular way and doing that alongside developing new business features turned out to be quite a challenge. A year later, the migration is still not finished. So, what makes it worth it?

Learning about Hexagonal Architecture

One term not related to the domain itself, but to software design, that also crossed my path was Hexagonal Architecture. Before I joined the project, my team had decided to redesign their old architecture in a more modular way, and the hexagonal approach was how they wanted to structure it. Doing this alongside developing new business features turned out to be quite a challenge. I can tell, because as I'm writing this, the migration is still not finished.

But what is hexagonal architecture, and what does it offer that makes this migration worth it? That is what I'm going to answer in this post, as I take you along on my own learning journey. I will give a brief background on when hexagonal architecture was introduced, how it relates to other software engineering principles, what advantages my team has seen in our code while implementing this architecture, what challenges we have faced, and finally, how it might impact AI-driven development. However, I will not explain all the principles of hexagonal architecture or how to implement it, because there are already many resources available online that cover these topics sufficiently.


Understanding Hexagonal Architecture

Hexagonal architecture was introduced by Alistair Cockburn in 2005 and is still very popular today. The goal of this architectural pattern is to decouple the business logic from other functions an application often needs, such as accessing a database or processing input from external sources. It consists of three main components that together form the hexagon: the business logic at the core, surrounded by ports, which are interfaces, inbound for accessing the service and outbound for communicating with other systems, and adapters, which implement the ports.

A practical example would be an application that receives requests via a REST API, processes those requests, and then sends data to another system. The REST API is implemented in an adapter, which can be a separate module or package, and it calls methods on an inbound port, an interface that exposes the functionality of the core. Within the core, the data is processed according to the business logic. Finally, the core uses an outbound port, again an interface, which is implemented by another adapter responsible for sending the data to a specific external system. In this example, the way the application communicates with the external system could change radically, for instance from HTTP communication to communication via an event bus. Even with such a change, the business logic in the core would not have to be adjusted, because the changes would, in most cases, only affect that specific adapter.

The goal of decoupling the business logic from technical details and external systems is still highly relevant, especially for large applications that continue to grow in complexity. Although hexagonal architecture is often described as an architectural style for large applications that also introduces a lot of overhead, I would not fully agree with that. Even in smaller applications, hexagonal architecture can make the application more future proof, since it enables developers to get new team members productive more quickly. Furthermore, when technical changes occur, for example in the way data is retrieved from another system, replacements can be made faster than in a traditionally designed application.


Hexagonal Architecture and Modern Frameworks

Furthermore, I think that hexagonal architecture fits well with today's mainstream technologies. Popular frameworks in the Java ecosystem, such as Spring or Quarkus, rely heavily on the principle of Dependency Injection, which is one of the ways to implement Dependency Inversion, meaning that high-level code does not depend on low-level code. In turn, Dependency Inversion is enforced by hexagonal architecture through the use of ports and adapters for communication with external systems. So, when working with most current systems in the Java (or Kotlin), your framework might already help you implement hexagonal architecture.


Hexagonal Architecture and AI

Another benefit discussed within my project team was that hexagonal architecture makes the use of AI in the development process safer. By isolating the business logic from the implementation details inside the different adapters, it becomes possible to define a single interface and ask AI to help implement it. In this way, the context can be restricted to a very specific part of the application's functionality, making it easier to verify that everything continues to work correctly. Also, by limiting the context and not having an AI agent scan the entire codebase for a certain task, it should be easier to keep token usage down and use AI in a more targeted and sustainable way.


Discussing Disadvantages

When I learned about hexagonal architecture, I also came across several posts that listed its disadvantages, which I would like to discuss now.

One thing that is often mentioned is the added complexity, especially when running and deploying the application, and the lack of performance that supposedly results from this complexity. The main argument is that if you split everything up into microservices that communicate via interfaces, you also have to manage this communication and deal with the latency it could introduce. Personally, I do not agree with that point. Hexagonal architecture only requires developers to isolate the business logic, but that does not mean it has to be a separate service. You can just as well implement hexagonal architecture in a monolith, with the different adapters implemented in separate packages around the core. In my team, we are working with a modulith, in which the different adapters are implemented in separate modules. Even then, it is still a single application. In this discussion about latency, it is important not to forget that terms such as "API" or "interface" do not necessarily mean "REST API". In many cases, a simple Java interface is already sufficient.

Regarding complexity, the only real aspect I have experienced is how much work it is to migrate an existing application to this architectural style. However, that is probably true for most larger migration projects.

Finally, people often describe hexagonal architecture as overwhelming when working with it for the first time. I understand where that impression comes from, as "hexagonal architecture" sounds like a big and abstract concept, but I can assure you that it is quite intuitive to learn, especially when you are already working with frameworks that support dependency injection.


In short

For me, it is a no-brainer to use hexagonal architecture with modern backend frameworks, since it is beneficial when working with AI, helps with code readability, and enables more people to work on the same application without hindering each other.

If you have a small pet project in which you are not using any larger framework, you do not necessarily have to consider implementing this. However, in any Spring application, I would recommend giving it a try and going for it. The only downside I have experienced is that when you do not have a greenfield project, which most developers do not, and you decide to migrate to this architecture afterwards, it requires a lot of work and costs time that could also be spent resolving other technical debt or doing other migrations, such as moving from Java to Kotlin, which is also a step taken by many teams nowadays.

Personally, I am convinced of this pattern. Even if it brings extra work when migrating an older application to it, as my team is currently doing, you are also resolving other issues along the way and end up with application code that is easier to read and work with.


More Resources

If you want to also use hexagonal architecture and need some more information about how this exactly works and how you could implement it, here are some resources that might come in handy:

• The Original Article: "The Hexagonal (Ports & Adapters) Architecture" by Alistair Cockburn, 2005: https://alistair.cockburn.us/hexagonal-architecture

• A more recent work by Alistair Cockburn about the pattern: "Hexagonal Architecture Explained - How the Ports & Adapters architecture simplifies your life, and how to implement it" by Alistair Cockburn, 2024: https://alistaircockburn.com/figs%20hexarch%20book.pdf

• Help with implementing and understanding Hexagonal Architecture: "Organizing Layers Using Hexagonal Architecture, DDD, and Spring", 2024: https://www.baeldung.com/hexagonal-architecture-ddd-spring

Picture Alexandra Schlüter

Author Alexandra Schlüter

Category:

Architecture

Tags:

-