Hexagonal Architecture: Why and How

Jyoti
6 min readAug 7, 2024

--

Hexagonal Architecture

In my team, we recently started following hexagonal architecture design for designing micro services. This decision came because of problems we faced in our existing systems. I will try to share things I learned about hexagonal architecture in this blog.

Are you working on a backend system following the MVC Architecture or Layered Architecture ? You might have encountered a situation where a simple, naive code worked perfectly well. So, why should you implement a complex architecture? Is it really necessary to over-engineer and use all the fancy and complex things in application architecture just because it looks cool?

Let’s revisit the normal architecture that worked fine for us. The MVC structure, which stands for Model-View-Controller, is commonly used for communication in applications.

A simple layered architecture typically consists of three layers:

  1. Presentation Layer [Controllers]: Responsible for handling incoming requests, interacting with the client (e.g. web browser, mobile app), and returning responses. In a web application, this layer is often implemented using Spring MVC or Spring WebFlux.
  2. Service Layer [Application Service]: Contains the business logic of the application. It coordinates the application’s functionality and interacts with the data access layer. Services are often implemented as Spring @Service classes.
  3. Data Access Layer [Repository]: Responsible for interacting with the database or other data storage systems. It includes repositories or DAOs (Data Access Objects) that perform CRUD operations on the database. Spring Data JPA or Spring JDBC can be used in this layer.

Simple layered architecture looks like below:

Image Source: Google

If your application interacts with third parties, you may need an additional layer: the Integration Layer. This layer interacts with third parties using adapters and WebClient using RestTemplate in Spring Boot.

Things were going well until one day decision came as we need to use different third party for getting some information.Now, as a development team, what do you need to do? You need to update at application service wherever you are interacting with third party with new one. It’s a breaking change. Now, the application code will have to call this new third party to get information.

Every time there is a change in third-party contracts, you need to ensure that it does not affect your core business logic and implementation. Why? Because your core application or business logic and the third party are tightly coupled. Won’t it be good if you just have to update third party implementation adapter and clients, and your application, the core one just calls the interface getInformation. Depending on the third party implementing it, it will pass the getInformation functionality to that implementation.

Lets consider other scenario:

Scenario: Payment Processing in E-commerce Platform

Layered Architecture :

  • Presentation Layer (Controllers): Handles incoming HTTP requests.
  • Service Layer: Contains business logic.
  • Data Access Layer (Repository): Interacts with the database.
  • External Service Layer: Interacts with external payment gateways.

In this approach, the service layer might directly interact with the external payment gateway. If there’s a change in the payment gateway’s API or a need to switch to a different payment gateway, you would need to modify the service layer. This tightly couples the application to the external payment gateway and makes it harder to test and maintain.

There are a few ways to handle this and some workarounds as well. But imagine if you could find a sweet spot where any change in the third party can be handled without worrying about application logic change.

That sweet spot is the hexagonal architecture.

Just look at below nice diagram

Image source: Google
  1. Driving Side: The driving side represents the outer layer of the hexagon, which is responsible for initiating and driving the application’s flow. This side contains the application’s primary logic and interfaces with external actors, such as users, external systems, or devices. The driving side typically includes components like controllers, REST APIs, or user interfaces.
  2. Driven Side: The driven side represents the inner layer of the hexagon, which contains the application’s core business logic and domain model. This side is “driven” by the inputs and requests received from the driving side. The driven side does not have direct dependencies on external systems or interfaces. It focuses on implementing the business rules and operations that define the application’s behaviour.

The driven side i.e inner layer of hexagon, the more independent of third party it is, the better it is.

Lets see the similar payment gateway problem, how this system with hexagonal architecture can easily handle.

Hexagonal Architecture Approach:

With hexagonal architecture, you would have the following components:

  • Application Core (Domain): Contains the business logic and domain model.
  • Adapters (Ports and Adapters): Adapters interact with the external world.
  • Inbound Adapter: Handle incoming requests (e.g., REST API controllers).
  • Outbound Adapter: Interface with external services (e.g., payment gateway adapters).

In this approach, the payment gateway integration would be implemented as an outbound adapter. The application core would define interfaces (ports) that the adapter implements. If you need to change the payment gateway or its API, you would only need to modify the outbound adapter, keeping the core business logic unchanged. This decoupling makes the application more flexible, testable, and maintainable.

Below diagram summarises how folder structure for this will look like and how you can easily handle when third party change is there:

lets see each folder one by one:

adapter: we place all external interation code, configurations, controller, DTO in adapter layer

domain: we place our core business and domain logic, domain models in domain layer. It also have ports which are interfaces with which application interact with third party. Port is implemented by adapter layer in providers or thirdparty.

utils: Common utilities files we store in utils folder

You can just see how beautifully hexagonal architecture helped us. We are not polluting the application logic and third party being handled smoothly.

There is one more pattern known as Anti corruption layer which we accept as part of this. The Anti-Corruption Layer (ACL) is a pattern used to ensure that interactions between different parts of a system (especially with external systems) do not corrupt the core domain model. It provides a way to translate or adapt external concepts and data formats into the language and concepts of the core domain. The ports and adapter of hexagonal architecture provides us same thing, the separation of concerns. The adapter layer deals with different objects and our core application deals with domain object. It is responsibility of top layer whoever is passing or interacting with domain layer to convert incoming request to domain model. Mostly application service is the one who interacts with domain service. Every service basically deals with its own object and thus manipulate or do any business logic over it.

In conclusion, hexagonal architecture is beneficial for applications that require flexible integration with external systems, such as payment gateways, by providing a clear separation of concerns and reducing dependencies on external interfaces.

--

--

Jyoti
Jyoti

Written by Jyoti

Explorer, Observer, Curious and a head full of questions and thoughts.

No responses yet