Logical Separation in the Hexagonal Architecture
Join the DZone community and get the full member experience.Join For Free
Have you ever lied to your stakeholders? I must confess that I did once (unintentionally)... I drew a very nice picture of boxes and arrows and I presented it to them as the "logical view" of the architecture of the software product they were in charge of. However, those logical boxes, which were supposed to be groups of classes with a specific purpose, were not represented in code. Source code was a real mess, basically just spaghetti code. There were dependencies everywhere without any defined rules or without any architectural rule. There was a clear gap between my picture and the source code.
If you have read my previous post, Coding your Architecture Structure, you know that one of the structures to architect a software system is created using syntactical constructions. Usually those constructions are packages, namespaces, or modules. So, with this idea we create an application using the Hexagonal Architecture Style, where each logical group of classes that this style suggests is represented as a package in the picture below.
When we define and write logical groups of classes (layers, modules, components, etc.) and their relationship using namespaces or packages, we say that there is a logical separation between them. That is, its limits are defined by syntactical elements, but all the classes, regardless of the namespace to which they belong, are located in the same physical place. This means that we are able to reference from any class in any package to any other class in any other package (in languages like Java you have the package private classes, but it is not enough for what we want to do). In addition, as shown in the picture above each logical group has its own dependencies. For instance the
adapters.store package has a dependency on the DB driver implementation artifact. However, nothing prevents the application package to use a class that belongs to the DB driver artifact.
On the other hand, when we define groups of classes and their relationships using tiers that communicate in the form of inter-process (for example, through HTTPS messages) we are imposing a physical separation between them. Physical separation ensures compliance with basic architecture rules. To mention a few, groups of classes with physical separation will only be able to communicate between them through their public interface. In addition, the dependencies (third-party libraries) of a certain group of classes will only be available to them.
But we don't want to use tiers, at least at the beginning we want to keep things simple. If we have to scale, then tiers will be an alternative, so we must ensure that if needed, in the future we can go there without a re-write of the application.
So, what are the options? We could create one source code project/repository for each package (group of classes). And produce artifacts from them. So, for instance, the
adapters.store project will have as a dependency the
application.ports.out artifact. That will work, and will ensure our architecture rules but it will complicate things a bit. The other option is to validate the dependencies on every commit using tools like ArchUnit or jqassistant. If you don't ensure these architecture rules at some point your dependencies will be spaghetti and you won't be able illustrate your Hexagonal style. And what is worse, if your application succeeds and you need to scale, you won't be able to do a physical separation without first decouple groups of classes.
This article is an extraction from the book Coding an Architecture Style.
Opinions expressed by DZone contributors are their own.