11

I've seen a couple of talks on Hexagonal architecture where they illustrate problems with N-tier architecture. Specifically, they show a spaghetti of service layer dependencies as the software grows. For example, the image below is from the Hexagonal Architecture with Grails talk: https://www.infoq.com/presentations/hexagonal-arch-grails/

hexagonal architecture with grails

I agree this is typically where N-tier apps wind up as they grow. But I don't really understand how hexagonal arch avoids or improves this situation. The business logic will still have the same dependencies. Those dependencies exist because some business code (whether intermingled with framework/persistence code or not), needs to call some other business code. Whether it's in a service layer or in something we call "core" seems irrelevant.

Somewhat related is the concept of number of layers. While the talks on hexagonal architecture say it's a single layer architecture (or outside versus inside), it all comes down to perception or how it's drawn in diagrams. In my view it's still N-tier, except we can call the web tier and data layer "adapters". Whether it's represented as horizontal layers or vertical slices seems more a matter of illustration or code organization. But the latter is often dictated by our framework.

2
  • 1
    I think it mainly has to do with things like that one line that goes from the web layer back to the data layer in that diagram.
    – JimmyJames
    Commented Jun 11, 2021 at 14:42
  • Nice question. Wish we saw more questions like this. Commented Jun 11, 2021 at 17:55

3 Answers 3

9

The supposed difference is who owns the interfaces. In a layered architecture the layer below offers things which I can use. In the hexagonal version the core offers "ports" to which you can write adapters to.

You are right though, when you say that dependencies are essentially the same.

I've written about similar topics many times, here and here for example. From the discussions I had I think most people only consider direct technical dependencies. What I mean by that is, a piece of code syntactically uses, imports, references another piece.

What is almost always overlooked are semantical dependencies. Being honest about what influences what. Consider this: you offer a port to list all customers. Great. But you want to implement a web UI, and you don't want all records in the UI. You want the ability to page results, because that's how your UI wants to work. You want maybe to filter, sort, etc. Now you have to change your port because of the UI.

Same for a database. It is simply a myth, that you can change persistence technologies on a whim and don't have to change the "core". Not even among SQL dialects is that possible, and certainly not with most NoSQL databases. Their feature set is just too different. So you'll most likely end up having to modify your "core" because you have changing requirements outside. This is not supposed to happen.

The way these kinds of architectures deal with this, is to use the absolute bare minimum CRUD features and hope to get away with it. This also means you can't use specific database features, write stored procedures, or optimize a particular use-case. If you try it will feel weird and out of place.

What I mean to say is, who owns some artificial boundaries inside the same application is meaningless. If you separate things that belong together (like persistence, UI and business logic of the same thing), you will end up searching for, and modifying all the separate pieces when something changes. So you're right, the difference is superficial.

2
  • Having to change things in multiple places doesn't seem ideal but I'm not sure if it's necessarily bad architecture. My quandary is whether adding an additional "pure business" layer like in hexagonal architecture has more pros than cons. The pro might be enhanced testability (not swapping out databases - as I agree that's not realistic). It seems clearer to create tests which mock out a port (in hex arch) than mocking JPA entities. And the con would be having one more abstraction and place to change things.
    – nogridbag
    Commented Jun 11, 2021 at 19:09
  • 1
    That depends on what you're comparing it to. Mocking JPA things sounds really bad. Anything else is probably better. Comparing to N-tier, as I said, I don't see a significant difference there. Do it one way, and in your next project the other way :) See how it feels. Trust no one. :) Commented Jun 11, 2021 at 19:55
2

I would not say the diagram is representative of what layered architectures look like. The diagram doesn't show the dependencies within a layer. Also, OAuthController skips a layer, so that means that you have some domain login in the controller (I think that is called loosely layered or something along those lines).

The point of hexagonal architecture is that when using it, you operate in your own language of the domain. As you know you have ports and adapters. The primary ports are entry points into your application, the secondary ports are the access points for your application to the outside world. The business logic - the rules of the business - do not depend on the outside world.

You might say that they depend on the ports, but ports are under your control. You write tests for the ports and adapters have to conform to the port behavior instead of your business logic having to adapt to the IO layer. You also don't do ports for the "data layer", but any kind of outside dependency - library, messaging, etc.

This allows you to easily change the adapters and swap persistence layer for example. You might be using Hibernate and Postgres and you decide that Hibernate makes your life hard and change it to JDBI. Then you might say that SQL database does not suit you and you would rather use MongoDB. It even allows you to decide what database to use later in development. You can start just with in memory database for the development purposes and add database later if needed, which speeds up your development as you don't need to deal with the database.

You can also do benchmarks way easier if you need, because you can have multiple adapters implementing one port and then it is just the matter of the configuration.

You can do all this without touching the domain logic - all the business rules stay the same. Hexagonal architecture basically allows you to program at a higher level while you are working on business rules, hiding the implementation details away.

You don't have stuff like EntityManager, UserEntity (the @Entity class) or ObjectMapper in your domain. You simply have eg. UserRepository, User (domain object) and UserMapper, which you define. You then implement them with PostgresUserRepository and JacksonUserMapper. The domain is detached from the implementation this way, which prevents a mess.

As you said, the business logic still has the same dependencies, but at least you are not dragging in the dependencies that have nothing to do with the business.

That being said, this style makes sense when you develop something that will have a long life. I do not see the benefit of this style for a hello world application, that will be thrown away, unless you want to practice this style of thinking.

Here is a good talk regarding this: https://www.youtube.com/watch?v=SxJPQ5qXisw

3
  • Thanks. Watching the video now. Do you think creating interfaces for left-side ports makes any sense? It seems the only point would be if it helps test the adapter in isolation. In Alistair's own example he does not create interface for left-side ports: alistair.cockburn.us/hexagonal-architecture The left-side adapter simply creates "the hexagon" and invokes a method.
    – nogridbag
    Commented Jun 11, 2021 at 19:26
  • I was thinking about that too, and I think it does not matter (it is a bit ugly, because it leaves you with a Impl class that implements it). but I like doing it, because I can quickly see the use-cases that are implemented. I don't think it helps with the testing, because you can still mock the class using a framework, but I also don't think that you should communicate with primary ports directly. I would have some sort of messaging in place and thus have loosely coupled modules. It is then way easier to split this code into microservices if needed.
    – Blaž Mrak
    Commented Jun 11, 2021 at 19:44
  • This is another good video about hexagonal architecture: youtube.com/watch?v=sOaS83Ir8Ck Brace yourself, the facades (basically ports) he shows are huge, but that is because they represent a module and are basically an entry point into some domain.
    – Blaž Mrak
    Commented Jun 11, 2021 at 19:50
-2

To be honest I know nothing about Hexagonal architecture, but I know that spaghetti is a marketing buzzword used for decades. The first time I heard the words "spaghetti code" was in a talk about the great improvements Object Oriented was bringing over procedural programming. Then came SOA promising to solve the problems of "spaghetti architectures" later reinforced by the promises brought by the ESB. The most blatant marketing came when proponents of the newly arrived microservices argued that SOA was a spaghetti architecture.

The truth is that you cannot solve any spaghetti code or spaghetti architecture just by adopting a special methodology. In my experience most of the spaghetti in enterprise archtectures derives from poor collaboration between teams or swift changes in the technologies that can be applied only partially. While in the single services/applications spaghetti code derives from poor collaboration between developers, too tight deadlines requiring quick and dirty solutions, poor handling of bug fixes and requirement changes.

The above mentioned problems can be solved only if the management really understands them and is willing to dedicate a lot of resources to address them. It takes time and money to enforce common guidelines between the teams and within the teams. You need dedicated architects who have good diplomatic skills, but are also strongly backed by the management.

For what matters N-tier architecture the claim that it has inherent problems is arguable. Obviously in a chaotic enterprise environment most of the implementations end up with a lot of spaghetti inside. But if it well implemented, taking into account the proper abstractions, it can be a good architecture.

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