Beliebte Suchanfragen
|
//

Hexagonal Architecture is just an island

22.1.2025 | 10 minutes of reading time

Imagine an island called "Alistair Island." This island is a vibrant place with houses, fertile soil, and a well-coordinated community of residents who live by well-defined routines. Every activity on the island has significance and serves a specific purpose. Daily tasks and rituals are established, and the island functions like a well-coordinated ensemble.

The island is surrounded by a mainland where various countries with diverse industries and populations exist. These countries produce different goods, offer a range of services and speak different languages. The inhabitants of the mainland are diverse including craftsmen, merchants, postal workers, and many other professions.

Not only do the languages and goods of the different regions of the mainland vary, but the island's residents also have their own language and a unique culture distinct from anything known on the mainland.

Although the island is isolated, there are numerous connections to the outside world. At various coastal points, harbors facilitate trade and communication with the mainland. Ships dock at the harbors of both the mainland and the island to transport messages, goods and other stuff.

To ensure organized trade, a trade agreement is in place. It specifies that ships transporting goods from the island to the mainland or vice versa must use designated trade routes. Ships traveling from the mainland to the island use the routes west of the island, while ships traveling from the island to the mainland take the eastern routes.

There are various types of ships. Large cargo ships are loaded with food and supplies. Passenger ships bring visitors to the island. Smaller boats are used to deliver specific messages and fulfill special assignments.

Each ship has a home harbor. Ships traveling on the western trade routes and dispatched from the mainland dock at designated mainland harbors. Ships from the island wait at the island’s harbors to embark on their journey.

The key distinction lies not in the direction of goods or messages but in who initiated the request. Viewing everything from the island’s perspective, ships coming from the mainland are considered inbound ships. Ships dispatched from the island are outbound ships. Whether they deliver goods or make requests to get goods. An outbound ship might even intend to transport goods from the mainland to the island, yet it is classified as outbound since the intent originates from the island.

Due to the different languages spoken by the islanders and mainlanders, ships must be equipped with translators to make the mainland's messages understandable for the islanders. Goods may also need to be repackaged. For example large cranes might be used for loading on the mainland, while everything is transported manually on the island. Quality checks are also advisable to ensure the goods meet the island’s needs. If not, the ship provides immediate feedback to the mainland. This process works the other way around as well. Outbound ships repackage, translate and verify that goods destined for the mainland are appropriate.

The ships are the only ones capable of understanding both the language of the island and that of the mainland as well as how to repackage goods accordingly. However, they are specialized for their respective trade routes. When new trade routes emerge, different ships are deployed.

Another important aspect of this world is the stability of the island. The island's stability remains intact regardless of changes in goods or the construction of new harbors. Only the type of ship and its crew need to adapt, or new trade routes need to be established. The islanders continue to receive their goods and messages in the manner and language they are used to.

Thats how the Alistair Island exists secure and stable in the middle of the vast ocean. Despite the emergence of new ships or changes on the mainland the island remains what it is: a place full of life, structure and a unique connection to the world around it.

Transferring the Analogy to Hexagonal Architecture

Let’s now transfer the analogy of the island, harbors and ships into the terms of hexagonal architecture to clarify their relationships.

Island - Domain

The island in our analogy represents the domain – the core of the business logic. The island is the center where all critical processes and routines take place, just as the domain is the place where business logic is managed and executed.

Ships - Adapters

Ships in the analogy represent the adapters in hexagonal architecture. They ensure that communication between the external world and the domain can actually take place. These ships act as specialized translators that convert the "language" between the domain and the external world in both directions.

Adapters are therefore crucial in transforming external requests into a format the domain can process. In addition they translate internal domain responses into a format the external world can understand. For example, an inbound adapter might translate a REST API request into a domain object, while an outbound adapter might convert domain objects into a format suitable for database queries or external API calls.

We distinguish between inbound and outbound adapters:

  • Inbound adapters receive requests from external systems or actors (the mainland), translate them and pass them to the domain. These correspond to inbound ships which depart from the harbors of the mainland to reach the island.
  • Outbound adapters on the other hand take the responses or data from the domain and prepare them for external systems or actors (the mainland) in a comprehensible and usable way. These correspond to outbound ships stationed at the island’s harbors ready to transport information from the domain back to the mainland.

Whether an adapter is inbound or outbound is determined primarily by who initiated the request. The perspective is always that of the domain (the island).

Harbors - Ports

The harbors we used in the analogy correspond to what are known as ports in hexagonal architecture. Ports are the clearly defined interfaces that separate the domain, the core of the business logic, from the external world. A distinction is made between inbound and outbound ports. As mentioned in the analogy, ships are also divided into inbound and outbound, depending on who issued the order and dispatched the ship. Ports reflect this concept as well.

For example, an inbound port might receive an order from a webshop, while an outbound port might send payment information to an external payment provider.

How is the domain structured?

Interestingly we have so far barely touched on the inner workings of the island itself. How the residents act, what structures and rituals they maintain. For instance one might ask how they efficiently distribute goods, make decisions by consensus or establish rules for harmonious coexistence. What do they do with the goods and messages? How are the paths in the city organized, what rules exist and how are they enforced? This is because the actual design of the domain, the core business logic, is not part of hexagonal architecture.

Hexagonal architecture focuses exclusively on designing the interfaces (ports) and their corresponding adapters. This focus is essential as it ensures that the domain remains independent and can adapt flexibly to changes in the external world without compromising its internal logic. How the people on the island interact, what rules they follow and how everyday processes function are governed by other architectural principles. Concepts like Domain-Driven Design (DDD) can play a role in structuring the domain. Alternatively, you could devise your own principles or simply build as you go. None of this directly affects hexagonal architecture and is not dictated by it.

The most important rule of hexagonal architecture is: Separate the domain from the external world. Let the island's residents work and live autonomously. No change in the external world should directly impact the island's inhabitants.

Why a hexagon?

A common question among beginners in hexagonal architecture is: Why a hexagon? Does it always need six elements? Do the opposite sides of the hexagon have a special relationship?

The simple, although somewhat underwhelming, answer is: there is no deeper meaning behind the hexagonal shape. Alistair Cockburn, who conceptualized this architecture, simply found the hexagon visually appealing and wanted a more illustrative name for the architecture than just "Ports and Adapters." In fact "Ports and Adapters" is the correct name for this architecture but it’s too generic and not particularly memorable.

As we’ve seen in the island analogy the concept also works with completely organic shapes and doesn’t require any specific geometry. The hexagon is merely a symbolic tool to make the different interfaces and relationships more visually comprehensible.

From the harbor to the Java interface.

A quick note upfront: If you’re using languages like JavaScript, Python and similar you won’t find interfaces as explicit constructs. In these languages interfaces exist only as implicit signatures. However the principle remains the same even though interfaces are not explicitly defined.

Now, let’s take a look at how to implement this in code. To do so, we’ll examine the following diagram.

As we can see we have distinguished between inbound and outbound adapters. These are our ships traveling back and forth between the mainland and the island.

The island is also represented in the form of the domain. This includes the services and ports. Based on the arrows, you can clearly see who depends on whom and who implements what. It’s important to note that the outbound port is essential because it ensures the dependency is inverted. This follows the Dependency Inversion Principle. The inbound port however is not technically mandatory. The adapter can directly access the service without issues. But by introducing interfaces you achieve looser coupling. Additionally, testability suffers slightly if the adapter directly accesses the service. Therefore, you should typically also define a port on the inbound side.

Now let’s briefly look at how this appears in code.

Let’s assume we are using a framework that handles dependency injection for us such as Spring. This makes everything straightforward: If a class uses an interface, you simply pass it as a constructor parameter in the class.

1//uses
2@Service
3class SomeService(private val forUsingPort: ForUsingPort){
4    // what ever your service does
5}

When a class implements an interface, it does exactly what the name suggests: the class implements the port (ForImplementingPort) or more precisely inherits from it. It looks like this:

1// implements
2@Service
3class SomeService(): ForImplementingPort{
4     override fun functionOfPort(){
5         // what ever you should do here
6     }
7}

And that's it basically.

Conclusion

Hexagonal architecture is often perceived as an overly complex concept but it is based on a few clear principles that make its application surprisingly simple:

  • Separate the domain from the external world. Business logic and data processing should be designed independently of the database or web frameworks so they can be more easily replaced or extended.
  • Anything related to technology should not reside within the domain.
  • Add ports around your domain to ensure the first two points are upheld.

Once these principles are understood, hexagonal architecture can be applied in almost any situation. Even in small projects it is beneficial to keep the domain free of technical details to make it easier to test. For instance, business logic with no direct dependency on a specific database can be easily verified with isolated unit tests. Hexagonal architecture supports this separation and is an excellent tool for maintaining it.

A tip for getting started: A tool like ArchUnit can help you verify your implementation with tests. If you'd like to know more, check out my blog post on ArchUnit: ArchUnit in practice: Keep your Architecture Clean

|

share post

//

More articles in this subject area

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.