Layers, hexagons, features and components

This blog post is a follow-up to the discussions I've had with people after my recent Modular Monoliths talks. I've been enthusiastically told that the "ports & adapters" (hexagonal) architectural style is "vastly", "radically" and "hugely" different to a traditional layered architecture. I remain unconvinced, hence this blog post, which has a Java spin, but I'm also interested in how the concepts map to other programming languages. I'm also interested in exploring how we can better structure our code to prevent applications becoming big balls of mud. Layers are not the only option.

Setting the scene

Imagine you're building a simple web application where users interact with a web page and information is stored in a database. The UML class diagrams that follow illustrate some of the typical ways that the source code elements might be organised.

Some approaches to organising code in a simple Java web app

Let's first list out the types in the leftmost diagram:

  • CustomerController: A web controller, something like a Spring MVC controller, which adapts requests from the web.
  • CustomerService: An interface that defines the "business logic" related to customers, sometimes referred to in DDD terms as a "domain service". This may or may not be needed, depending on the complexity of the domain.
  • CustomerServiceImpl: The implementation of the above service.
  • CustomerDao: An interface that defines how customer information will be persisted.
  • JdbcCustomerDao: An implementation of the above data access object.

I'll talk about the use of interfaces later, but let's assume we're going to use interfaces for the purposes of dependency injection, substitution, testing, etc. Now let's look at the four UML class diagrams, from left to right.

  1. Layers: This is what a typical layered architecture looks like. Code is sliced horizontally into layers, which are used as a way to group similar types of things. In a "strict layered architecture", layers should only depend on lower layers. In Java, layers are typically implemented as packages. As you can see from the diagram, all layer (inter-package) dependencies point downwards.
  2. Hexagonal (ports & adapters): Thomas Pierrain has a great blog post that describes the hexagonal architecture, as does Alistair Cockburn of course. The essence is that the application is broken up into two regions: inside and outside. The inside region contains all of the domain concepts, whereas the outside region contains the interactions with the outside world (UIs, databases, third-party integrations, etc). One rule is that the outside depends on the inside; never the other way around. From a static perspective, you can see that the JdbcCustomerRepository depends on the domain package. Particularly when coupled with DDD, another rule is that everything on the inside is expressed in the ubiquitous language, so you'll see terms like "Repository" rather than "Data Access Object".
  3. Feature packages: This is a vertical slicing, based upon related features, business concepts or aggregate roots. In typical Java implementations, all of the types are placed into a single package, which is named to reflect the concept that is being grouped. Mark Needham has a blog post about this, and the discussion comments are definitely worth reading.
  4. Components: This is what I refer to as "package by component". It's similar to packaging by feature, with the exception that the application (the UI) is separate from the component. The goal is to bundle all of the functionality related to a single component into a single Java package. It's akin to taking a service-centric view of an application, which is something we're seeing with microservice architectures.

How different are these architectural styles?

On the face of it, these do all look like different ways to organise code and, therefore, different architectural styles. This starts to unravel very quickly once you start looking at code examples though. Take a look at the following example implementations of the ports & adapters style.

Spot anything? Yes, the interface (port) and implementation class (adapter) are both public. Most of the code examples I've found on the web have liberal usage of the public access modifier. And the same is true for examples of layered architectures. Marking all types as public means you're not taking advantage of the facilities that Java provides with regards to encapsulation. In some cases there's nothing preventing somebody writing some code to instantiate the concrete repository implementation, violating the architecture style. Coaching, discipline, code reviews and automated architecture violation checks in the build pipeline would catch this, assuming you have them. My experience suggests otherwise, especially when budgets and deadlines start to become tight. If left unchecked, this is what can turn a codebase into a big ball of mud.

Organisation vs encapsulation

Looking at this another way, when you make all types in your application public, the packages are simply an organisation mechanism (a grouping, like folders) rather than being used for encapsulation. Since public types can be used from anywhere in a codebase, you can effectively ignore the packages. The net result is that if you ignore the packages (because they don't provide any means of encapsulation and hiding), a ports & adapters architecture is really just a layered architecture with some different naming. In fact, if all types are public, all four options presented before are exactly the same.

Approaches without packages

Conceptually ports & adapters is different from a traditional layered architecture, but syntactically it's really the same, especially if all types are marked as public. It's a well implemented n-layer architecture, where n is the number of layers through a slice of the application (e.g. 3; web-domain-database).

Utilising Java's access modifiers

The way Java types are placed into packages can actually make a huge difference to how accessible (or inaccessible) those types can be when Java's access modifiers are applied appropriately. Ignoring the controllers ... if I bring the packages back and mark (by fading) those types where the access modifier can be made more restrictive, the picture becomes pretty interesting.

Access modifiers made more restrictive

The use of Java's access modifiers does provide a degree of differentiation between a layered architecture and a ports & adapters architecture, but I still wouldn't say they are "vastly" different. Bundling the types into a smaller number of packages (options 3 & 4) allows for something a little more radical. Since there are fewer inter-package dependencies, you can start to restrict the access modifiers. Java does allow interfaces to be marked as package protected (the default modifier) although if you do this you'll notice that the methods must still be marked as public. Having public methods on a type that's inaccessible outside of the package is a little odd, but it's not the end of the world.

With option 3, "vertical slicing", you can take this to the extreme and make all types package protected. The caveat here is that no other code (e.g. web controllers) outside of the package will be able to easily reuse functionality provided by the CustomerService. This is not good or bad, it's just a trade-off of the approach. I don't often see interfaces being marked as package protected, but you can use this to your advantage with frameworks like Spring. Here's an example from Oliver Gierke that does just this (the implementation is created by the framework). Actually, Oliver's blog post titled Whoops! Where did my architecture go, which is about reducing the number of public types in a codebase, is a recommended read.

I'm not keen on how the presentation tier (CustomerController) is coupled in option 3, so I tend to use option 4. Re-introducing an inter-package dependency forces you to make the CustomerComponent interface public again, but I like this because it provides a single API into the functionality contained within the package. This means I can easily reuse that functionality across other web controllers, other UIs, APIs, etc. Provided you're not cheating and using reflection, the smaller number of public types results in a smaller number of possible dependencies. Options 3 & 4 don't allow callers to go behind the service, directly to the DAO. Again, I like this because it provides an additional degree of encapsulation and modularity. The architecture rules are also simpler and easier to enforce, because the compiler can do some of this work for you. This echoes the very same design principles and approach to modularity that you'll find in a modern microservices architecture: a remotable service interface with a private implementation. This is no coincidence. Caveats apply (e.g. don't have all of your components share a single database schema) but a well-structured modular monolith will be easier to transform into a microservices architecture.


In the spirit of YAGNI, you might realise that some of those package protected DAO interfaces in options 3 and 4 aren't really necessary because there is only a single implementation. This post isn't about testing, so I'm just going to point you to Unit and integration are ambiguous names for tests. As I mention in my "Modular Monoliths" talk though, I think there's an interesting relationship between the architecture, the organisation of the code and the tests. I would like to see a much more architecturally-aligned approach to testing.


I've had the same discussion about layers vs ports & adapters with a number of different people and opinions differ wildly as to how different the two approaches really are. A Google search will reveal the same thing, with numerous blog posts and questions on Stack Overflow about the topic. In my mind, a well implemented layered architecture isn't that different to a hexagonal architecture. They are certainly conceptually different but this isn't necessarily apparent from the typical implementations that I see. And that raises another interesting question: is there a canonical ports & adapters example out there? Of course, module systems (OSGi, Java 9, etc) change the landscape because they allow us to differentiate between public and published types. I wonder how this will affect the code we write and, in particular, whether it will allow us to build more modular monoliths. Feel free to leave a comment or tweet me @simonbrown with any thoughts.

About the author

Simon is an independent consultant specializing in software architecture, and the author of Software Architecture for Developers (a developer-friendly guide to software architecture, technical leadership and the balance with agility). He’s also the creator of the C4 software architecture model and the founder of Structurizr, which is a collection of open source and commercial tooling to help software teams visualise, document and explore their software architecture.

You can find Simon on Twitter at @simonbrown ... see for information about his speaking schedule, videos from past conferences and software architecture training.

Re: Layers, hexagons, features and components

It's that distinction between published and public that's crucial but difficult to define in the language. We've ended up using conventions and coaching to distinguish the two.
As we use .net (for package read assembly) we experimented using "internals visible to " to provide cross package access for testing. But ended up going the cultural way to encourage dependency only on published interfaces even within a package. I'd be interested to see how one could really make this distinction within the language in a more effective way.
We are starting to see our granularity coarsen, with packages bound by deployment rather than by simply logical areas being more the norm. And in turn deployment too is becoming more coarse grained as we start to see less risk deploying whole services every time.
At the end of the day, a hacky coder is going to couple to your db schema behind your back anyway ;)

Re: Layers, hexagons, features and components

I really like C#'s internal assembly visibility because it, again (see the other comments), provides a way to physically prevent dependencies that shouldn't be permitted. Having said that, I often get resistance from teams when I suggest they increase the number of class library projects to take advantage of this. It's all trade-offs...

Re: Layers, hexagons, features and components

I believe you are overlooking one important aspect of the Ports and Adapters architecture. It encourages you to to separate the packages com.mycompany.myapp.web, com.mycompany.myapp.domain, and com.mycompany.myapp.database from your example into different source code projects (e.g. Maven modules, ...). This effectively makes it impossible for domain to access types that it is not supposed to access even though they are defined public. For example, CustomerServiceImpl would not be able to access JdbcCustomerRepository because it is in a project that domain doesn't depend on. Obviously you would end up with a lot of source code projects this way which is why you would usually divide your application into several bounded contexts: com.mycompany.myapp.context.web, com.mycompany.myapp.context.domain, and com.mycompany.myapp.context.database that implement a specific functional area of an application.
Once you have *.web, *.domain, and *.database (which should be named *.infrastructure and can implement access to a database or other external service) in different source code projects you gain the following advantages:
* The domain has no access to infrastructure specific libraries (e.g. Oracle JDBC driver) which ensures that it contains business logic only. It also ensures that the domain uses the infrastructure always through the interfaces it sees since it can't access the repository implementation.
* You can more easily swap the infrastructure project that the domain depends on with a stub or mock of the infrastructure.
* You can bundle only the infrastructure specific libraries you actually need (e.g. don't need to include an in-memory JDBC driver in the production version).
Ports and Adapter my not be the perfect fit in all cases but I believe one of the advantages it gives you is that unlike in option 3 and 4 domain has no access to third party libraries (JDBC drivers, JMS implementations, ....). This ensures that the business logic is truly independent of the environment in which it is going to run.

Re: Layers, hexagons, features and components

Thanks, that makes a lot of sense. How many teams do you think use separate Maven modules/source code projects to physically separate the various parts of their application? And I'm guessing that you have a bunch of tests executed after deployment to confirm whether the correct (e.g.) adapters have been plugged in and configured appropriately?

Re: Layers, hexagons, features and components

We follow this approach on the team I am working on. I would assume all teams that take modularity seriously to separate their project into several source projects with dependency inversion taken into account. Getting the packages right gives you only half of the benefit since you still have all those third party libs on a shared classpath.
In our case each source project has its own spring context and in the integration tests you either add the real or the stub context depending on what you intend to test.
I am following your blog for quite a while now and really like your take on linking source code to the architectural representation. Have you had a look at Structure101? It is the most useful tool I could find so far that doesn't rely on additional metadata (e.g. custom annotations) or other conventions.
Also recommend you to check out the book Java Application Architecture by Kirk not well written but good concepts.

Re: Layers, hexagons, features and components

Hi Simon, thanks for the link. I'd like to add few comments here:

- "everything on the inside is expressed in the ubiquitous language, so you'll see terms like "Repository" rather than "Data Access Object".": in fact on the inside (i.e. Domain code kingdom) you won't find any reference to "Repository" types because you will name them instead with the (ubiquitous) language of your business (e.g. ProductCatalog, Lexicon, etc.)

- "the interface (port) and implementation class (adapter) are both public.". There has been much debate on this subject but after few checks with Alistair and other happy few, the "port" describe something you don't code (i.e. a middleware API, a database driver, a springboot REST exposition, etc.) whereas the "Adapter" is what we code in order to bridge the 2 separated worlds: the infrastructure code where the adapter belongs and the Domain code the Adapter interacts with.

- "especially if all types are marked as public.": Everything marked as public? Hell no! That's an orthogonal topic but you shouldn't do that of course. I'll have to dig more about how to make it in java but in .NET I used to create 2 projects/assemblies(packages?): one for the "MyAppOrServiceTopic.Domain" and the other for "MyAppOrServiceTopic.Infra". Since the "Infra" assembly is referencing the "Domain" one, there is no way for the Domain assembly code to reference any Infrastructure Implementation (you can't have such cross project reference in .NET). BTW, within the "Infra" assembly I only set 'public' the various (Repository) implementation types that are needed by the app bootstrapper (i.e. composition root which is part of the Infrastructure kingdom) or by the Domain code (via the magic of the Dependency Inversion Principle - DIP). All the other infrastructure types are set 'internal' (or 'public' if we become lazy) for my tests to work with.

Re: Layers, hexagons, features and components

Excellent, I'm glad that you picked up on the "Repository" naming thing. :-) But this naming strategy seems very common for some reason. What would you rename the CustomerRepository to? "Customers"?

Again, having a physical separation between the domain and infrastructure parts of the application makes sense, and C# allows you to do this very neatly with the internal visibility modifier. Would you lump all infrastructure implementations (web, database, middleware API) into a single assembly? Or would you have one per adapter?

To achieve physical separation in Java, you would really need to use a module framework (it's the public vs published types thing again) or setup a number of Maven modules/source code projects, and ensure the appropriate dependencies between them. As a number of comments have suggested, I think physical separation is a really important part of implementing the ports & adapters pattern. Why don't people mention this?

Re: Layers, hexagons, features and components

Of course the name of the repository will depend on the (domain) context, but we can imagine a "OurCustomers" type for instance.

Regarding the adapters, I tend to (YAGNI ;-) start with one single assembly for the whole Infrastructure part (with all the adapters). I may split it afterwards if necessary (i.e. due to real deployment or release management constraint). I stopped for years to create tons of projects/assemblies just in case I'd like to release & patch them separately (one day...)

"Why don't people mention this?" : because almost no one is using the Hexagonal Architecture pattern nowadays (unfortunately ;-( Having a widely known architect like you promoting this kind of simple design may probably change that brutal fact ;-)

Re: Layers, hexagons, features and components

"one single assembly for the whole Infrastructure part" ... so that single assembly would contain all of the "outside" code? And therefore, in theory, web code could bypass the domain model and call the database code directly? ;-)

If anything, I've probably made the situation worse! Judging by the discussions I've had, the blog posts out there and the questions on places like Stack Overflow, I don't think it's really clear what ports & adapters is really about. Most examples being subtle twists on a layered architecture doesn't really help too. I believe there's an opportunity to create a canonical ports & adapters example, but physical separation of code needs to be a big part of this ... it's essentially a plugin architecture, where adapter implementations are plugged in to the application at runtime. I think that's a far more compelling description of ports & adapters that a simple variation of a layered architecture. The downside is this requires a much more rigorous and disciplined approach to development because you need to create an environment where domain code absolutely cannot see/use those adapter implementations directly. One assembly or source code project/module per adapter gives you that compile time check that the inside code isn't depending on the outside code. But those additional assemblies/source code projects/modules are a trade-off I don't think people are willing to make. Without this physical isolation, we're really back to a variation on a well implemented layered architecture.

Re: Layers, hexagons, features and components

One adapter per project will unfortunately kill your build performance after a while. It's better to use tooling (e.g. NsDepCop, NDepend) to allow you to set up dependencies between namespaces within a single project, although use of these isn't particularly widespread*.

Re: Layers, hexagons, features and components

"I think physical separation is a really important part of implementing the ports & adapters pattern. Why don't people mention this?" I agree, I consider it very important, I try to achieve it with several Maven projects. It's quite messy, lot of projects for every port , every adapter, and dependencies. I don't see it though in most of hexagonal architecture examples over the internet... they use to just split the whole application in two layers, the hexagon and the adapters, but they don't distinguish every adapter nor ports. I think it's more correct to physically split every port and adapter (ports being the api of the hexagon). The other way it would be just a layered architecture, not hexagonal.

Re: Layers, hexagons, features and components

A hex architecture is only going to be different from a layered one where there are 4+ layers; 3 or fewer connected boxes can always be drawn either way. So any example involving simply web, domain and database is not enough to capture the distinction.

Re: Layers, hexagons, features and components

I like to think of it as more of a honeycomb where you might have hexagons for each bounded context. Or maybe "hexagons all the way down".

Re: Layers, hexagons, features and components

I see you quoted some of our code. I made a conscious decision some years ago to simplify my use of java access scoping. Nowadays I tend to use only public and private. Having once used languages, such as Modula-3 and Ada95, with more sophisticated access scoping, I found that the coarse-grained control in Java didn't really carry its weight. Instead, I focus on using package conventions to make the public/published distinction. For really local code, I might use private inner classes.

This seems to work well enough on most teams that I've seen, and teams that don't understand this usually have deeper problems with their code. And sometimes the unrestricted prompting in the IDE throws up commonalities we hadn't noticed yet.

Re: Layers, hexagons, features and components

I just realized that I had not dropped my hexagonal architecture code sample here (done only on Twitter). Explanations and code are available here:

Re: Layers, hexagons, features and components

Hello Thomas, I've taken a look a your hexagonal architecture sample. But it seems that you structure the project in layers (domain,infra,...). More like "onion" architecture, isn't it? For implementing hexagonal, I split the infra layer in separate project per adapter, and I separate the ports from the domain, so that every adapter depends just on its port.

Re: Layers, hexagons, features and components

Hello Juan,

While I was preparing a live-coding session with Alistair Cockburn about his pattern, I realized that I didn't grasp correctly the notion of Port and Adapter so far.

A Port is what represent the intention of going-in/going-out the hexagon. In C# it is an interface which is part of the Domain. BTW, Ports are always part of the Domain side.

An Adapter is whatever is needed to go-in/go-out the hexagon at runtime. It gathers things you code (i.e: mapping between infra<->domain data models) but also things you don't code (like your favorite http stack for instance). Adapters are always part of the Infrastructure side

Now regarding the pattern name. An onion has much more than 2 layers in general ;-) This is why I dislike it as a pattern. I'd prefer having 2 layers only: Domain and Infrastructure, so that we can keep being focused on the Domain problem without being lost in our tech talent to multiply the number of Layers (what I see everywhere).

To clarify more the implemention, I suggest you have a look at our recent live-coding session with Alistair:

Part1 (Alistair only):

Part2 (Alistair and me doing the live-coding):

Part3 (end of our live-coding session + Q&A with Romeu Moura):

Re: Layers, hexagons, features and components

I used to think of a 'Jigsaw' architecture where the holes in the pieces are ports, and the sticky-out bits are adaptors. I prefer "Ports and Adaptors" terminology - the terms 'Jigsaw', 'Onion' and 'Hexagonal' seem to confuse people by making them worry about which things should be adjacent to each other, probably because these are things from the physical world, where in fact the connections between software modules are arbitrary. You can teach someone 'Port' and 'Adaptor' in 10 minutes, and doing so really helps people realise get the difference between a Domain Services and an Infrastructure Service (now an adaptor). Another thing I like to think about is that it's "Ports and Adaptors all the way down" (like with turtles), from the module level down to the class level.

Re: Layers, hexagons, features and components

Hi Thomas, yes you are right, I consider ports belonging to the hexagon too, maybe I didn't express myself well, sorry. Is just that I split the hexagon in core and ports. Ports are the api/spi of the hexagon. They belong to the hexagon, they are for communication with the outside world. As some comments in this post pointed out, in my approach I have lot of subprojects (I use Java and Maven), in order to separate physically every adapter, port, etc. and define the concrete dependencies (not just a dependendy from the outside towards the hexagon). If I don't do it this way the adapters, for example, could reference to each other, or they could reference more parts of the hexagon, not just the ports, that is not desirable to reach, etc. The drawback of this approach is the complexity of the whole project, with lot of subprojects and dependencies. But I think that if I don't do it this way, it's more a "two layered architecture with DIP"(1) than a ports&adapters. Ports & Adapters would need a more complex project structure, in order to separate physically the distinct ports and adapters and configure the dependencies between them. (1) workaround name for "onion with 2 layers" :-)

Re: Layers, hexagons, features and components

Hello Simon, I like your articles about web software architecture.

I'm developing a new project from scratch trying to implement a "package by component" style. But one of the problems I have is how and where to put the generic data access services and daos, that I had when I used layers.

They implement the tipical crud operations and some search methods, and concrete services extends them in order to dont repeat code.

How do you deal with it? I've thought on having a generic data access component from which the concrete components extends. Do you think it's ok?

I see two problems here...

(1) Doing this it's like having an hexagonal architecture (data access component for accessing the external database)

(2) Generic data access component breaks encapsulation, as it has public implementing classes, for letting concrete components extends them.

The later can be solve using composition over inheritance, but I really don't like it very much, because you have to write lots of forwarding methods.

Another doubt I have is wether you have shared domain entities and database, or if you split the database, and every component has its entities and database tables. My approach is to have one database (and one entities package), shared by all the components. But if you split the database how do you deal with relationships between entities of different components?

Thank you very much.

Re: Layers, hexagons, features and components

Very insightful post, thanks. I've learned to do hexagonal architecture using the component model, number 4, and I even throw in the boot-logic (spring related code for instance) in that same package. I think the version 2 while, long-lived, was just training wheels until I learned about organising along probable change-patterns. i.e. covariant code goes close together. There's a paper "on the criteria to be used in decomposing systems into modules" from 1972(!)

Add a comment Send a TrackBack