Question

Hexagonal Architecture seems to make so much sense when I read about it (like more than I can say; the ultimate eureka moment), but actually implementing it is a different story.

I more or less understand the structure, but my biggest problem I think is the delineation between components.

In the simplest example, say we're just doing simple retrieval of data, with a UI library, a Logic library, and a Data library (and a program running it all).

The user opens a window, or a webpage, and a list of data should appear there. The series of requests is something like: UI Event -> Primary Adapter -> Logic -> Secondary Adapter -> Database (and then returning back up the chain). (The Primary and Secondary Adapters have each implemented their respective Ports).

The main questions I have are:

  • Who does what?
  • Who lives where?

Let's say my DB Model is differently structured than my Business Logic Model. And then there is also a UI Model of sorts (presentation types).

I want to say that it should be the DB library's responsibility to translate the DB Model into the Logic Model, and that the Core Logic should be ignorant of this process. Similarly it should be the UI library's responsibility to translate the Logic Model into the UI Model.

But if I do this, then the issue is that I have not actually captured anything of value in the Logic Layer. And also, the UI Model is something that is not actually specific to any particular UI. The "presentation rules" are something that could be taken out of the UI and put into a reusable place.

It's almost as if there could be UI and DB "translation layers" put in between the Logic Library and UI and DB Libraries. You would then have a Logic Model, a separate UI Model, and an actual UI Implementation Library. Similarly you could separate the DB into one or more Data Access Libraries (in my case I have at least two separate databases), and a Data Translation Library that translates data from the DBs into the Logic Model.

Or... the translation could live in the UI and DB Libraries? Or it could live in the Logic Library?

As concrete examples, imagine that a single concept in the Business Logic actually comes from two different places (databases) and must be composed together. Similarly, when presented, there are things like running totals, grand totals, numeric text formats, etc. that are basically "UI Rules" rather than Business/Logic rules and are (or can be) separate from the UI implementation itself.

(And then I still feel like I would not have determined where things actually go in practice. For each interface that is defined there is the question of whether it should be implemented alongside it, or in the neighbouring library.)

Was it helpful?

Solution

Don't think you can use hexagonal architecture to do your design for you, there are still decisions to be made around what sits where. But do take into consideration that the whole idea of hexagonal architecture is that the core/domain/central hexagon shouldn't need to change if the outside world does.

There is absolutely nothing wrong with your core taking in multiple business objects and doing some transformation into another object (maybe, keep reading).

What it shouldn't be doing is things like XML to JSON transformation or specialising the output of a request because of the requestors implementation.

So for your UI related questions. You can have a UI model in your core, and you can do calculations in your core to fill out that UI model. But even if you have several UIs (e.g. website and native apps), you still have one UI model in the core. Filtering data or UI implementation specific calculations are a problem for the adapters or maybe the actual UI. Don't take this too literally, if you have two very different views of your data, then by all means cater for that in the core.

The question about requiring calls to two different databases to do some business logic is not so cut and dry. If the fact that there are two databases instead of one is an implementation choice, then the adapter should be giving the core one object. If those databases are very different things and you'd never seriously consider consolidating them into one database, then it's perfectly acceptable for the core to know that there are two things with seperate ports/adapters.

Licensed under: CC-BY-SA with attribution
scroll top