Hexagonal Code Architecture — Clean Architecture

For modern cloud-native architecture

DHRUV BANSAL
Deutsche Telekom Digital Labs
6 min readMay 11, 2021

--

Introduction

There are various ways of structuring the code i.e. defining code architecture. The whole point of having a good code architecture with the help of different design principles and patterns is to increase code maintainability, reusability, etc. With the modern agile practices and microservices patterns, the dev team should be able to keep up the pace of changing business and customer needs and adapt them quickly in the code.
One of the traditional ways of code architecture is Layered Architecture.

In-store for you

In this blog, we will compare Layered Architecture with another domain-centric architecture style for managing code. And in the end, we will conclude what architecture is suitable for what type of business solution.

Layered Architecture

A conventional web application architecture consists of a web layer, a domain layer, and a persistence layer.

The preceding diagram shows a high-level view of the very common three-layer architecture.

- Web layer, which receives requests and routes them to a service in the Domain or business layer.

- The service does some business magic and calls components from the Persistence layer.

- Persistence layer to query for or modify the current state of our domain entities.

What can go wrong with layers

Database-Driven Design

The web layer depends on the domain layer, which in turn depends on the persistence layer and thus the database.
Think back to the last use cases you have implemented in any application. Did you start by implementing the domain logic or the persistence layer? Most likely, you thought about what the database structure would look like and only then moved on to implementing the domain logic on top of it.

But any typical application should be designed to solve some business problem. So application design should be centered around that business problem not how data would be persisted in a way of solving that problem.

Critical Business Services can become complex — serving multiple responsibilities

Due to unclear boundaries of business domains, over time, some services could start serving multiple use cases. Such a broad service has many dependencies on the persistence layer, and many components in the web layer depend on it. It makes it hard to find the service that’s responsible for the use case we want to work on.

How much easier would it be if we had highly specialized narrow domain services that each serve a single use case? Instead of searching for the user registration use case in the UserService, we would just open up the RegisterUserService and start working. But the practice which is generally followed in layered architecture is to have one business service corresponding to one database entity.

Clean Architecture

Clean Architecture is suggested by Robert C. Martin, Prentice-Hall, 2017, Chapter 22. In clean architecture, in his opinion, the business rules are testable by design and independent of frameworks, databases, UI technologies, and other external applications or interfaces.

That means that the domain code must not have any outward-facing dependencies.

https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

The layers in this architecture are wrapped around each other in concentric circles. The main rule in such an architecture is the dependency rule, which states that all dependencies between those layers must point inward.

The core of the architecture contains the domain entities, which are accessed by the surrounding use cases.

The use cases are what we have called services earlier (in layered architecture) but are more fine-grained to have a single responsibility (that is, a single reason to change), thus avoiding the problem of broad services that are discussed above.

Development Mindset

This Architecture should naturally let developers think of business problems first. To implement in a Hexagonal way, one needs to define business domains and use cases first and then move to other details like persistence, UI, etc.

Since the domain code knows nothing about which persistence or UI framework is used, it cannot contain any code specific to those frameworks and will concentrate on the business rules. We have all the freedom we could wish for, to model the domain code. We could, for example, apply Domain-Driven Design (DDD) in its purest form. Not having to think about persistence or UI-specific problems makes that so much easier.

Hexagonal Architecture (Ports & Adapters pattern)

The primary source for the term “Hexagonal Architecture” is Alistair Cockburn’s blog post at https://alistair.cockburn.us/hexagonal-architecture/.

It applies the same principles that Robert C. Martin later described in more general terms in his clean architecture.

  • The application Core is represented as a hexagon, giving this architecture style its name. The core comprises all the elements that correspond to a particular business problem. Business domain entities, service objects, use-case classes are all part of the core.
  • Outside of the hexagon, we find various adapters that interact with the application. There might be a web adapter that interacts with a web browser, some adapters interacting with external systems, and an adapter that interacts with a database.
  • The adapters on the left-hand side are adapters that drive our application (because they call our application core) so they are called driving adapters. While the adapters on the right-hand side are driven by our application (because they are called by our application core) hence they are called driven adapters.
  • To allow communication between the application core and the adapters, the application core provides specific ports. For driving adapters, such a port might be an interface that is implemented by one of the use case classes in the core and called by the adapter. For a driven adapter, it might be an interface that is implemented by the adapter and called by the core.

Note that the hexagon has no outgoing dependencies, so the dependency rule from Martin’s clean architecture holds true. Instead, all dependencies point toward the center.

Advantages of Hexagonal Architecture over Layered Architecture

Business logic first

The mindset to start from business logic and complete code design is independent of any communication layer.

Business logic testability

Business Logic is testable without worrying outside “Details”. Outside details here is persistence logic, web adapters. Basically, any kind of communication.

Promotes Single responsibility principle

Architecture promotes to design different classes serving different business use-cases. Similarly, each communication port/adapter can be easily designed independently of each other.

Path to Domain Driven Design is easy

Only a Domain-Centric Architecture lays a strong foundation for Domain-Driven Design.

Does this mean should domain-centric design always be preferred over layered Architecture?

No, layered architecture has its own strength and, in some cases, implementing domain-centric design can unnecessarily increase the complexity of the code.

When your code or microservice doesn’t have complicated business logic, the layered architecture is the best choice. In some cases, you can entirely skip the ‘Service layer’. For example, if your code or microservices is

  • Just an integration layer/communication adapter (no business logic).
  • Serving master data
  • or code is intended to support simple CRUD.

All above-mentioned cases are best suited for layered code architecture.

Conclusion

When you have complex business logic, use case, complicated business rules to implement then the domain-centric design is the best suited. On the other hand, simple code logic without complex use-cases and business scenarios is easily complimented by Layered Architecture.

References

https://blog.cleancoder.com

Get Your Hands Dirty on Clean Architecture by Tom Hombergs

--

--

DHRUV BANSAL
Deutsche Telekom Digital Labs

Loves to architect, build & scale disruptive technology consumer products