What is the Hexagonal Architecture?
The hexagonal architecture is a software design pattern to develop applications that are highly maintainable. This design pattern is also known as the Ports and Adapters. The concept was introduced in 2005 by Alistair Cockburn and since then has been evolving.
The idea behind Hexagonal Architecture is that the fastest we apply changes to a system, the better. This pattern reduces the amount of technical depth in a system and software applications become easier to maintain.
The Hexagonal Architecture pattern in based on three main layers that connect to each other using ports and adapters. This design pattern allows for applications to keep a single code base while serving requests from multiple inputs.
In Hexagonal Architecture, any external change does not affect the internal business logic as it creates systems that have loosely-coupled components.
What are Hexagonal Architecture layers?
The Hexagonal Architecture design pattern is based on three layers: domain layer, application layer and framework layer.
Each layer is connected using Ports and Adapters. We are going to review these concepts later, but basically inner layers expose the Ports configuration and the outer layers connect to them via Adapters.
Hexagonal Architecture layers are independent from each other. The key principle of the pattern is that inner layers are not aware of their outer layers. This ensures that the core business logic of your application is not affected by any of the external services.
The object-oriented classes on each layer are going to define interfaces in order to model the data types and their dependencies. Then, the required objects are passed in using dependency injection at run time.
The number of ports that a layer expose is not fixed. Each layer can define a different set of ports than its relatives.
Ports in Hexagonal Architecture
Ports are defined by inner layers via interfaces. They expose the boundaries and the data formats of the application layer. Ports can be classified as:
- Primary Ports: the entry point of the application with the outside world. They “drive” the application. Usually the upstream is a client request while the downstream is the data of the response. In the graphical representation primary ports are located in the left side. Examples of primary ports: user browser device, testing tool software, external service performing a REST API request.
- Secondary Ports: in the opposite side are ports that are driven by the application. They are used for the app to pass or receive data from outside entities. The most common use case are databases. They are located on the right side of the graphical representation. Examples of secondary ports: SQL service, in-memory databases or file storage system.
There is not a fixed number of ports in Hexagonal Architecture. It is up to developers to decide how many ports should a system have according to the application needs. An extreme case would be adding a new port per each use case, leading to hundreds of application ports.
Similarly, we could merge all primary and secondary ports so that the application ends up with only two: left-side (Inbound - UI, automation, …) and right-side (Outbound - database, data storage, …).
Finding the right balance is usually the best choice.
Hexagonal Architecture Adapters
Adapters in Hexagonal Architecture design pattern are used by outer layers to connect and use logic of the inner layers. They are key to the hexagonal architecture as they allow for a custom implementation of the core without impacting the internal logic.
An adapter satisfies the needs of an external service without changing the inner code. Data can be manipulated and transformed outside the core.
This allows, for example, to trigger and application from a testing software or from a user device. The adapter in each case is going to be different, but the core logic of the application remains the same.
Hexagonal Architecture Examples and Application Testing
The Hexagonal Architecture is software design pattern that can be applied to any project. It is extremely helpful for software applications that are used by multiple external entities.
Hexagonal architecture also facilitates the unit testing of the application. The best practice is to write use cases for the internal core of the application and do not take into account the external services driving the system. That leads to small test cases which are cleaner and easier to understand.
It is a common mistake to write test cases which have knowledge from external services beyond ports and adapters. These use cases are usually long and complex to maintain.
Hexagonal Architecture Positive Aspects (pros)
- Application using Hexagonal Architecture are easier to maintain.
- New external services can be plugged into the system via adapters and core business logic is not impacted.
- Systems with friendly testing easy set up.
- In Hexagonal Architecture it is easy to replace technology of external services without impacting the core business logic.
Hexagonal Architecture Negative Aspects (cons)
- Additional complexity by adding more layers on the architecture.
- The addition of layers requires many mappers and value objects.
- As core layer has to be completely independent from outside world, entity objects and interfaces from outside service might get duplicated in order to keep the business logic independence. This is specially the case for systems using the micro-services pattern.