36

So, in the hexagonal architecture layer, the application layer has incoming ports (use cases) that are called from incoming adapters, implemented by services, that use outcoming ports that are implemented by outgoing adapters.

Is it really different than the layered architecture? Other than calling outcoming adapters as DAO? And some kind of pretty package structuring? We have services as well implemented by interfaces.

  • So am I doing hexagonal without knowing?

  • In other words, what problem does hexagonal architecture solve, that a layered architecture doesn't?

5 Answers5

24

The key difference is about dependency management:

Layered architectures are intended to reduce dependencies by stacking layers: every component in one layer may depend on components of the layer below (in principle, immediately below, although "open layers" can be bypassed). There are many variants, but for example:

                             dependency
Presentation (UI)                |
Services                         |
Data access layer (DAL)          |
Database                         V 

Hexagonal architecture (and subsequently Onion or Clean architectures as well) use dependency inversion. In this architecture, the outer cores shall only be dependent on inner cores. But dependency inversion is used to allow the inner cores to use abstract interchangeable interfaces without knowing their specific implementations.

                                      dependency  dependency inversion
Interfaces (to DB, with user, ...)        |        <--+
Services                                  |           |
Business logic                            |           |
Entities                                  V        ---+

When the layers/cores represent an internal decomposition in your system, the hexagonal approach allows you to have more abstract elements at the center, and build concrete classes on abstractions, whereas the layers require you to depend on concrete implementations.

Some more thoughts:

  • when layers become tiers, i.e. deployable components that could run on different servers, a careful API design may sufficiently decouple the abstractions between each of the layers, to make the difference less obvious

  • layers are more difficult to split horizontally, whereas in the hexagonal approach, it's easy to rely on abstractions whose implementations are outsourced via a port and a connector to another hexagon (that's the idea behind the microservice architecture)

psmears
  • 196
  • 4
Christophe
  • 81,699
22

It can be confusing, with Layered Architecture being such generic term. Nowadays, anything is layered architecture. Difference is what each layer does and how they depend on each other.

(Legacy) Layered Architecture or Three-tier achitecture consists of layers. On to bottom is database /persistence layer, where data is persisted. On top is business layer, where all the interesting domain logic happens. And on top of that is presentation layer. The most important thing to notice is that business layer depends on persistence layer. This means that you cannot use business objects without also dragging in persistence. Usually in form of database.

Hexagonal, Clean and Onion architectures also have layers. But the difference between these and the (legacy) layered architecture is that it puts the business domain at the bottom/center. This means that business model and domain entities are independent of their persistence. This is really helpful for testing, as you don't need to bother to spin up the database. And is agnostic to persistence, so you can use SQL, NoSQL, etc... and you domain entities shouldn't care about what database you use.

Euphoric
  • 38,149
11

Layered is usually like this (arrow indicates a dependency):

Data <-- UI

Which split apart a bit more can become:

Data <-- Logic <-- UI

Hexagonal uses dependency inversion to achieve:

Data --> Logic <-- UI

And further:

 Database -->  |-------|  <-- CLI
Resources -->  | Logic |  <-- Desktop GUI
    Files -->  |-------|  <-- Web UI

The modules on the left are called "driven" and simply respond to requests. The modules on the right are called "drivers" and are where requests are generated. Everything goes through the Logic which is the business rules of the system written in pure dependency-free code. The Logic becomes the language of the system that any of the parts can use to communicate with the other parts.

This sounds amazing, and it is, though it can be a bit more tricky to implement than this sounds. But at the same time, I find everything has a tendency to fall into place; everything has a clear place to live.

In the Data <-- Logic <-- UI setup, I found that the code in "Logic" never made sense to put anywhere in particular. It could go in any of the three places and still never felt right. This is because it was still really database code, and since the UI knew about the database, database code could still go right in the UI. Or it could go in the Data layer. Or it could go in the "Logic" layer.

With Hexagonal, all dependency is filtered out of your Logic like a sieve, leaving only pristine dependency-free Logic code left over. You now want to put as much code as you can in the Logic module, because just by putting it there you remove its dependencies and make it more reusable.

5

Remember that software is built from code, not diagrams. Certainly both architectural views have been employed in working software, so it is not that one isn't useable, just that the maintainability is different.

In layered architecture, the UI is the first interaction point and triggers processes in the Service layer, which gets its data from the database (layer). However, these interaction points are hardwired, the API of the database layer is defined by the database needs and a change in deeper layers often requires changes in upper layers, e.g., the UI integration.

In hexagonal architecture, the business logic is at the center, and it just uses an database adapter that was provided at the start and conforms to the API (= port) that the business layer expects to do its job - and if the some service is not conforming to the business API, it is adapted to that interface.

However, this is the static architectural view. In the end, both architectures produce a very similar call stack during run time. The UI still is the first interaction point, an event triggers processes through the input port of the business API, which further calls a database adapter... because the user experience and end results should be the same.

4

I am under the impression that the only difference between layered and hexagonal is the fact that hexagonal forces you to always depend on interfaces instead of implementations, which is widely considered a best practice regardless of the architecture. In my experience I have always used what I thought to be layered architecture, but by always coding to interfaces, I was probably using hexagonal...

I would say hexagonal is different way of describing the layered architecture that suits well with DDD and Microservices, but in the end, both architectures will essentially produce the same code and call stack: Controller -> Service -> Repository

IonutB
  • 49