12

So, in the hexagonal architecture layer, the application layer has incoming ports (usecases) that's called from incoming adapters, implemented by services, that uses outcoming ports that is 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?

2
  • 6
    "Layered" is very general - almost any architecture is layered, including hexagonal architecture (they just draw the layers more like onion layers than a layer-cake, but this is rather arbitrary). But many traditional layered architectures consider the database the lowest/innermost layer, whereas hexagonal consider the domain model the innermost layer. So this is a shift of perspective.
    – JacquesB
    Jan 23 at 13:10
  • 2
    Putting the domain model at the center of the architecture is not just enforced by hexagonal architecture. Onion architecture also does this. Jan 23 at 13:12

4 Answers 4

13

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)

7
  • 1
    Could you give concrete examples of hexagonal architectures? What should be needed in the RefPerSys project or the Frama-C to make its architecture "hexagonal"? Feel free to email me (to basile@starynkevitch.net at home), or to basile.starynkevitch@cea.fr at office, working at www-list.cea.fr Jan 30 at 15:03
  • @BasileStarynkevitch basically most microservice based systems rely on an hexagonal architecture or a derivatives. But why are you looking for examples? What makes you think your systems should use hexagonal architecture, and what makes you think that they currently are not?
    – Christophe
    Jan 30 at 16:27
  • @BasileStarynkevitch (Sorry if do not reach out for your private email: I have a full-time job and am here in my free time for contributing to the public knowledge. I therefore have no interest in starting private email discussions, even if in my youth I've read "Metaconnaissances" and was fascinated by the ideas behind your RefPersys. Moreover, 89Mb for one repository and 1,5 Mb for the other would require too much of my time to provide you a meaningful answer. If you can formulate a specific question, don't hesitate to post it on SE).
    – Christophe
    Jan 30 at 16:29
  • It is the first time I read about "hexagonal" architectures (software)? Did you heard of / can you give example of "square" architectures, "triangular" ones, "spherical" ones (in software architecture)? Jan 30 at 17:24
  • Has the GCC compiler some "hexagonal" architecture? Jan 31 at 10:10
12

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.

3
  • Ok, but I think in a layered architecture, the domain entities can be agnostic too, for instance, Let's say I may decide to use for instance mongoDAO, insetead of MySQL dao, and it would not be so "dependent" on it, i would just change "a line", like the one with hexagonal.
    – codemonkey
    Jan 23 at 13:31
  • @codemonkey There's a difference in where you change that line of code. In a layered architecture, you change your business layer. In a hexagonal architecture (ports and adapters), you leave your core application completely unchanged and instead swap the database-specific adapter, so basically architecture-level dependency injection. Personally, I think that ports & adapters is overkill and layers are perfectly fine for a lot of software, like smallish CRUD apps. But ideas like DDD, microservices, and onion architectures clearly have a lot of appeal in larger and more enterprisey software.
    – amon
    Jan 23 at 14:20
  • @amon Personally I've never once seen a layered architecture that could actually replace its database layer with a different technology after the fact without large amounts of effort and refactoring. Turns out having a direct reference to the DB specific code (even if there are interfaces and whatnot involved) virtually guarantees that someone is going to rely on a leaky abstraction. But yeah might be doable for small applications with maybe 100k LOC.
    – Voo
    Jan 24 at 10:40
4

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.

1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.