Spring I/O

Domain-centric? Why Hexagonal- and Onion-Architecture are answers to the wrong question @ Spring I/O

51:16 · 13 Apr 2026 – 15 Apr 2026 · YouTube

About this talk

This talk discusses the appropriateness of hexagonal and onion architecture, suggesting they may address the wrong questions in software architecture. The speaker, who has extensive experience with the Spring engineering team, emphasizes that current frameworks often prioritize quick solution delivery rather than the more pressing need to manage changes in existing applications. The speaker references the book 'Structured Design' by Larry Constantine and Edward Yourdon, which argues that the cost of software change correlates to the level of coupling within code. By decoupling elements in software systems, developers can facilitate change while maintaining cohesion within modules. Ultimately, the speaker advocates for designing software with a focus on strong cohesion and manageable coupling, proposing that functional decomposition is more beneficial than purely technical approaches. Additionally, there is a call to rethink how modular architectures align with business objectives and the larger context of software development.

Full transcript

[music] >> I want to talk to you about um why I personally think that hexagonal onion architecture are answers to the wrong question and that begs the which question is the right question, right? So, I'm only to work from I've been working on the Spring engineering team for 16 years now. It's my Yeah, my 17 year Primarily done Spring data stuff, then moved on into let's say

more architecturally related work including the creation of the Spring modulus project when I prepared this talk, I found that the next slide is basically been the key slide for many of my talks in the last couple of years, which is that in technology marketing and if you look at the how frameworks in general are advertised these days, we have a strong focus or marketing has a strong

focus on this thing here, right? Here is something to create something pretty quickly. I mean AI generated applications is just the latest flavor of that. Who of you is fortunate enough to actually be busy in their day-to-day work with that kind of work? Creating something for the first time. Lucky you. I mean okay, that's fine. I can I can see that. The mere mortals among us, right?

They're busy with keeping the ship afloat, right? We spend time on changing existing applications and actually taking them from version 1.0 to 1.1 what have you. So, that's kind of the thing we primarily because that's where the most of the work goes, that's the thing that we need to focus on to some degree at least. There's um a book called structured design by Larry Constantine and Edward

Yordan. Who has read or heard of the book before here? No one. It came across my desk when I was looking watching a talk by uh Kent Beck talking about like the cost of change and the cost of software and he basically is cites a couple of sections from the book. Uh the the core thesis of the of the book here is that the cost of software

is the cost of change, which is kind of directly related to what I've just what I've just shown you. So, the question of that then is like what's the cost of change? How do you estimate the cost of change? And Yordan and Constantine come to the realization that essentially the amount of coupling in your code base is equivalent to the cost of change. So, what does coupling

mean in the first place in in their definition? I mean, there's all like there's metrics around it, but they ultimately define coupling in a figuratively web of elements in your software system like classes, functions, what have you, things are coupled if you need to impose a change on one of these elements and that requires you to change other related elements of that code base, right? So, according

to that definition like these red bubbles here are coupled to each other. And that has an unfortunate side effect because it's not something that you can decide statically. You cannot say this code is coupled or this code is not although a lot of metrics actually try to imply that because the um whether code is coupled depends on the actual change that you have to make to the

code base. It's most easily understood by thinking of let's say your e-commerce application um and one feature request being we need to add a new form to the customer registration or a new field to the customer registration form is one kind of change and there's a particular elements of your code base that need to be touched to achieve that change or there's another requirement coming in saying

we want to exchange our JDBC data access layer with let's say MongoDB, right? It's a totally set of related elements that you need to touch to accommodate that change. So, if coupling is creating the cost in my software system so, what do we do? We decouple, right? So, we introduce new elements to our chain of code to be changed and by that create like more things or

like more elements that we need to keep in our heads, relationships that we have to to remember. Um so, um yeah, that's kind of the we basically add new elements to that to that chain here. Of course, with the benefit of of us allowing to let's say change the direction of one of these arrows like the breaking dependency change and creating shorter change shorter chains, but generally

introduce more elements, there's a lot of talk about like coupling and like decoupling elements one of the more let's say under discussed terms I think in our industry is cohesion and I'm going to puzzle you a bit probably cohesion is coupling. If you think about it, right? So, it's exactly it's the coupling in the places that you want it to to be, right? And we're going to

see what that actually means in a in a second. So, ultimately if we're zooming out a bit, I mean I'm already pretty awake, but zooming out a bit more, the entire like act of software design is basically creating elements of strong cohesion that are loosely coupled to each other. So, what does what does it mean to our to our graph here? So, we don't want to deal

with this just like unorganized mess, but we want to find groupings of that we can basically we Yeah, can can surround with some kind of border >> [snorts] >> and then hopefully we find ourselves in a place that a change actually stays within that within that Let me take a step back. We want the animation got in front of ahead of me. So, uh Jesus. So, we

want to stay here, right? We want that change to stay in our in the element that we actually designed, right? So, we want that thing here because that means that the blue circle is actually forming a cohesive cohesive element. So, things are coupled to each other, but in a way that we can actually that they support our changes. This is where this slide is supposed to to

lead to, right? Because we we kind of take a bet on like what things we have to change in the future, whether it's more the business people asking us to change add new features or whether it's someone from the technical side of things coming to us asking us for to replace our data access layer. And you can probably think for yourselves on your projects what's what's more

likely. All right. So, um with with that arrangement, let me just take a brief look here. we try to contain the changes in the elements that we design, right? But as of now these blue circles do not even form a system because there's no relationships between them, right? And there's this systems theorist Russell Ackoff. Has anyone heard of Russell Ackoff? Only a few. Just type Russell Ackoff

into YouTube and I >> [laughter] >> that you have a great evening. Just just a giant rabbit hole of of great talks. It's basically TED Talks before they even were TED Talks. But he says and I think I'm pretty sure you've heard the quote in some form or another that the system is not the sum of its parts, but the product of their interactions. It's usually the

latter part that gets slightly um uh changed, but it's more than the sum of its parts. That's what you hear >> [clears throat] >> or have heard probably. So, that means we need to actually establish relationships between the elements that we designed in a way that they can actually or these actually deliver the value that we want actually to see in our in our software system, right?

So, we deliberately have to expose elements from our like arrangements and let them act as kind of entry points into uh into our let's say modules or logical units in the first place. That's kind of the the theoretical fundamental for everything we're going to talk about because um next thing we're going to do is take we're going to take a look at separation of concerns architectures, which

is the term that I've kind of selected to choose be um to summarize many of the approaches that you're going to see. So, hexagonal architecture of ports and adapters is um Cockburn. What's his What's the first name? Alistair Cockburn. I'm bad with names. I'm sorry about that. Um is from 2005 and the idea here being it's so it's basically strategies on how to um yeah, how to

arrange your your code in a code base, how to logically assign code bases to architecture elements. He argues that there's an application core. So, every bit every bit of business logic has to reside in the application core and the interaction with the outside world is taking place in so-called adapters, right? So, whether it's inbound adapters like an HTTP controller or um uh message listener or what have

you and there's like databases or file system access or any kind of infrastructure connection is happening in there. And the connection being or the the parts are connected by the application core exposing dedicated ports, right? looks like okay, looks similar to what we want actually, right? We have these these ports, selected elements of our code base that we expose, and then we have implementations that allow us

to connect to databases and um Um in 2008, uh the onion architecture was coined. It takes a similar but slightly different approach. Um again, the domain is at the center of our application. Uh basically, domain abstractions um surrounded by application abstractions. There's already like a bit of debate of what goes where, but it's usually the like the processes that that surround the domain elements. And then there's

again the infrastructure uh ring that contains all the elements that we've seen in ports and adapters uh in the hexagonal architecture. So, they look similar. Um One key difference maybe is that Alistair differentiates between the inbound or driving uh adapters that's and the uh secondary or driven adapters. So, it's basically they differentiate between stuff that's controllers, so stuff that gets calls, versus stuff that reaches out, right?

Which which uh Jeffrey Palermo, I think his name was, didn't really bother to do because to him it was kind of the same. And I've I've studied these these approaches quite a bit, and I was like looking for literature, and you find the book by Alistair, and then it was like, "Okay, they don't seem very different, um but there's so much buzz around it. Like, what's the

point, right?" And I was thinking, "Well, if you think of layered architecture, which is a similar style, um we have these like individual blocks here, just calling like something presentation, some UI thing, the business logic piece, and uh some some part in which persistence code lives, right? And the um general dependency direction is from from top to bottom, right? So, and business logic depending on persistence feels

a bit like to everyone working with hexagonal architecture and onion architecture, feels a bit like odd. Interestingly, even the uh blue's domain-driven design book by Eric Evans originally uh describes the layered architecture that way. So, in in the DDD book, believe it or not, uh business code depends on persistence code. Something that you would never see somebody doing or uh um promoting DDD uh would even like

suggest. And if you look at hexagonal and onion as forms of layered architecture or altered forms of layered architecture, you decide that, well, it's kind of the same with one little detail. One little detail change. So, it's that thing here, we turn that around, and then we for hexagonal architecture, we introduce dedicated interfaces in the form of ports on the business logic thing. That's it. Welcome to

my TED Talk, right? So, um and that's been like the okay, we there's like entire series of books written about this, and I was like, "Hmm, it's it doesn't feel like it there's there's much much in there or not not as much as it warrants a new, let's say, claiming to be a new architecture really." Even worse, I guess you all like have seen a Spring uh

in your in your careers already. If you had started like Spring when it was coined in 2004, maybe even a bit later, you've probably been exposed to some kind of structure that kind of we promoted for you to organize your code in in the first place, right? So, if you build a standard web application, then you create some controller classes, there's @Controller annotation, and then you dependency

inject um a service, right? Where they there's debates of whether you use an interface for that or not, and then there's some kind of repository abstraction, originally manually implemented, then along came Spring Data, but it's kind of the structure that you've used when you build Spring applications, no matter what architectural style in the first place. And the great thing is, you've done all three um architectural styles

at once with this, right? So, let's put our layered architecture head on, then it's this, right? So, with controller it's belongs to the presentation layer, depends on the business layer, depends on the persistence layer. Flip our layered architecture head, put on our hexagonal architecture head. We have our driving adapter, right? Because we're fancy now, and then we just create an interface in the application thing. So, we

have to like introduce the interface, so that's becoming our port. The repository interface now belongs to the service layer. That's okay, that's the that change in in arrows that we've seen, right? And then we have our repository implementation um being a driven adapter. Right? So, that's that's fine. And finally, if we like want to see or interpret this stuff as onion architecture, we kind of have our

infrastructure components, controller and repository, and then our application / domain thing. So, it's all kind of the same thing, right? Um which is fine. It just feels like quite a bit of buzz around something that's If you you can argue like you've done like uh hexagonal architecture before it was even invented, right? in 2004. accepting that it might not be as a fancy thing a fancy thing

as we it's usually discussed, it's still worth looking at where do these things come from and what do they want to achieve, right? So, because that's especially for hexagonal architecture, um you can clearly see, remember it was what was it? 2008 or something? Let me just briefly jump back 2005, right? 2005 was the time when we were deploying EAR files to WebSpheres. Is anyone old enough to

remember? Oh, poor you. Uh poor me. Um right? So, when in a time in which you basically run some code on your on your machine, and it builds for 5 minutes, and then then you throw it over the fence to some admin, and they're running it, and and it takes another 15 minutes for the thing to even to test a piece of functionality that you've just written,

then this is kind of the core thing that you want to design your code around, right? That's that's definitely the case. Um but at the same time, if you think about the history of of Spring Framework, dependency injection in particular, it's always promoted a programming style in which you ended up with code that you could easily unit test in the first place, right? So, the way you

write code allows you to test the code without all the infrastructure uh in um behind it, no matter whether that's a WebSphere or whether that's a integration test, which might take some time to bootstrap as well, right? So, that's one thing. So, we can we can ask the question of, "Okay, should we be as focused on the testability thing, or should we be should we be focused

on testability in the same way that we were focused on it in 2000 5? I forgot it already again. So, the other thing that um is a great thing to pursue is the so-called technology-free domain, proponents argue that you don't you must not use JPA annotations on your domain classes, right? Because then you have tied your code to JPA. what does that even mean, right? I mean,

technology-free domain is in the in if you remember the days when we were using Joda Time because Java was lacking a proper date time API, is using Joda Time in your domain objects, does that still do you consider that still a technology-free domain? I mean, we've decided to encode our domain in Java, so we've already decided for a programming language. Um it's a slippery slope, that's what

I'm what I'm arguing. And even with like JPA annotations, these classes are are usable without JPA in the first place, even without JPA on the class path in the first place, because missing annotations do not actually cause class loading errors when you use the types as they are. And you can still write unit tests for your JPA annotated entities. I'm not saying that's a good idea in

every case. I'm just saying, right? It's not as black as white as you as you as you think. And my pet peeve um being these architectures being called domain-centric architectures, right? Um and that usually or that comes from the fact, of course, that in both hexagonal and onion architecture, the is actually at the heart of the diagram that you draw, the your visual your mental mental picture.

Unfortunately, as non-domain-centric as they claim to be domain-centric, because just because the thing is in the middle of your attention, it's also the case for snipers, right? If they shoot you. But um the thing is that in the applications that I see, decomposing the domain individu- in into individual parts is the primary architecturally driving factor. And none of these architectures leave a word on how you would

approach this, right? If you have multiple of these domains, how do you even like is it like do you create multiple hexagonals? Do you create multiple onions? And I think the the most repeated phrase in Alistair's book is, "We don't have an opinion on that." Thanks for being not so helpful, right? So, um while we're kind of what analyzing all of this, I just thought, okay, what

about like what do you do with onions? Like you cut them, you slice them, right? So, I thought, why not just like starting uh what would the picture look like if we slice the onion? And then it turned out there's these nice little edges on the application ring that are now open to the sides, basically, which allows us to put sliced onions next to sliced onions. And

then it it kind of reflects the way that at least I think about like Spring applications and structuring them. It it fits quite the mental model quite quite well because we can then wrap something around that, call that basically our application, and then have our sliced onions as representations of these vertical slices that I that I want to see in uh in my uh or that I

think of in my logical uh decomposition idea. And those slices then can expose either domain events that's there's something in Spring called the application event bus uh that you can like publish an event and then um some other slice uh of onions could actually uh listen to those or you could expose Spring beans, which is basically a reference to some object of some some foreign module. And

if you think about um you realize that what's going on within the vertical slices is kind of secondary, right? Because [snorts] the the thing that you need is the if you remember the blue circles from the beginning, right? It's the it's these it's these boundaries that expose selected elements to other blue uh circles. And then what you do on the inside really, I mean, that's the whole

point, right? Of a module. You encapsulate decisions. You encapsulate the decision of whether I mean, you just call a a bloody JDBC template from a controller or whether you integrate with some third-party API and you really want to introduce some abstraction for that. Like the technical complexity is not to be not supposed to drive the entire thing, but the actual business relationships between the individual elements, right?

Keep that in mind. We're we're we're going to make this a bit bit more concrete. I've seen like that's um I need to go to this in immediately. What's coming when I usually go to to customers and um ask to look at the code bases, I can guess what kind of book the architect has read most recently, right? So, because it it's it's usually these technical architectures,

especially the technical architectures, uh reflected in the code base. So, like 15 levels of package index of adapter in adapter out, yada yada yada. Yes, so you see when you look at the code base, you see the technical even though like the if you it's a I think on the on the backside of of Alistair's book, it's the the money quote is um we had so many

people that got lost in technical details and they wanted to focus on the domain. Then you open up an an an an code base that's supposed to be written with hexagonal architecture and all you see is adapters and port and yada yada yada. So, you don't see anything of the domain in the But so, what what's the problem with with the technical decomposition strategy being heavily uh

expressed in in especially package structures? Let's go into this, right? To make it a bit more practical. Let's start again with our layered architecture. That's like a an advanced version of it where we're already like using interfaces for the individual layers, right? That's kind of like you can argue whether that's needed or not, but let's just stick for the sake of it um stick with that, right?

We have the dependency going down to the to the abstraction of the interface and there's some implementation class on the like underneath or contained in it, probably hidden by some means. We can get to that. What happens if we put that second slice thing, so our our additional functionality that we have orders, we want to add like functionality to manage customers next to it? We basically replicate

the pattern, right? Because it's foreseeable, it's easy. That's also a reason why developers are usually drawn to this kind of things because it's a cookie-cutter thing, right? AIs love that, right? You can just replicate the new thing and more code. Wow. Um the problem with that is and we actually have we even have decoupling going on here, right? So, the order service only depends on the repository

and whether it's JDBC or not. So, decoupling, great. there's no cohesion anywhere here, right? So, none of these service implementations has anything to do with the others or the order repository implementation doesn't have anything to do with the customer repository. So, when we need to change a thing, like a business-driven thing, add a new form field to the customer registration form, we need to touch all of

the things, but we're not doing layered architecture, right? We're we're doing we're we're going to do like what is it um hexagonal onion architecture. So, we start with that and what did we we wanted to change said one arrow here, that this this thing in the in the in the in the lower area here. So, we moved the repository interface uh to our domain package. So, it's

becoming a port And by that, um everything gets better magically. Does it? Nah. We can generate a lot of like similar-looking code, that's fine, but it's still we end up with that low cohesion thing. So, it doesn't doesn't really help, actually. Um except like we've achieved that we can probably test the domain thing uh slightly better because of that interface, right? So, that's that's good. So, what

do we do instead? Um I mentioned that we uh were uh that internal structure doesn't really matter. So, what if we just started with like a single package in the first place? And then we can actually yeah, use the same approach within that package. So, how does that that approach make things more modular in the first place? Well, the first or the first two columns here, in

either approach, both or the interfaces always have to be public, right? Because there's a new namespace if it's I mentioned in the legend in in the beginning of the slides, there was this it could also be built modules, right? Like it's a Maven modules or or Gradle modules. You have to expose these interfaces to the relatively other concept and to make it accessible, right? So, for the

JDBC order repository to implement the repository, it needs to be public, which means it's also public to everyone else in the system, And it doesn't have to be for the single package approach here, right? Because we can just make everything package private or if you use Spring Modulith, then you could put the code that um um is supposed to be hidden in in subpackages. Generally speaking, find

some way you could even use JPMS Java the Java module system and then have basically not don't export anything. So, what does that that approach look like if we now add this customer functionality like we like we did before? I mean, it's still kind of the same let's say it's the same complexity. We we still create the same structure. We can still use our AI to copy

the the create the new code, but the only thing that needs to be public is some dedicated interface on the target side, right? So, we can as I described in that theoretic part before, we can we actually designate the customer service interface to become one of the blue bubbles on that on the blue rings, right? So, we dedicatedly design our modules or code structure in with regards

to what we expose to others and we can still hide everything else internally, Um so, we basically come in this case like we could argue that our controller and repository are part that could be a could be again interpreted as as onion architecture, but essentially, as I said, it doesn't really matter, which means that we could also for let's say an additional domain that doesn't require that

complexity, that guess what? And don't tell anyone. I'm glad it's not recorded. Um we can have our controller inject the bloody JDBC template and then just call select from yada yada yada. If that does the trick, right? Because nobody else is affected by that and we can let's say for some reason we get a new requirement and things become more complex, we can introduce that indirection, that's

technical decomposition approach later when we need it, That's that's kind of that's the idea. All right. Um you hopefully saw the this kind of schematic thing here reflected in the uh in the in the package structure. And um we actually hopefully get to a point. That's kind of the design goal for us to come up with these blue uh actually contain the changes that we need to

our system or as many changes as possible. It's never going to be like only these kinds of changes versus the other kinds of changes in in our system, >> So, this is this slightly slightly more advanced um let's say more elaborate description of what I hopefully got across here, >> right? We need to find a decomposition strategy that supports the changes that we need to make. yeah,

to to summarize what I've just been talking about basically is it's an yeah, I hope that got across, right? The interesting observation I think I made is that when you design for cohesion, so you try to build cohesive elements, you automatically get to decoupled elements it just naturally falls into place. I've seen tons of teams being focused on trying to decouple things from that build hexagonal architectures

around because like the repository interfaces with the help of Spring Data, they in their minds become oh, this are Spring Data repository interfaces, right? So, that they're not technology dependent and to get to a technology free domain, we need to have a repository port on our application core and then have an implementation that then delegates to the Spring Data JPA interface, which is kind of like I

really getting getting weird, right? So, right? So, we want we want to get to these to these circles. Functional decomposition over technical decomposition. I guess I I got that. I and that's kind of what I what I wanted to get across with the title. It's not that the technical decomposition doesn't have any value at all. It's quite the the opposite. It's just that I've seen I see

so many teams being like we build our application as a hexagonal architecture application. It's kind of a non-starter. It's basically saying like saying oh, we build our application with JDBC. So, it's it's one aspect of a thing, but it's completely missing like all the other things that that you need and that are uh especially important in your in your overall architectural approach, right? Especially because I mean

I in the examples to keep them simple, I I usually talk about a single system composed into individual elements, but that's usually not the way it it is in in your real-life applications. You probably know that. Uh I've never seen a monolith like a system that doesn't talk to any other system in a in a company, right? Even if you build a rather monolithic system, there's usually

that other thing that you need to notify or some some message that you need to to send to or call some other third-party service, very important the intrinsic complexity of the vertical slice defines how much accidental complexity you have to apply, right? If you if you have fine subdomains or very simply structured, they are just like we just need to read some data from the database, turn

it into JSON and provide that as an API or to to my other there's no need for an elaborate all adapter for yada yada yada. Just start simple. That's what I'm trying to get across like this here, right? And the other thing being and it's also coming from that kind of arrangement or that that train of thought here is that we need to make sure that we

use the elements that we um have gotten from our language that are supposed to provide means of encapsulation use them as means of encapsulation and not only as means of organization. I'm going to get to that get back to that with a with a some some kind of example, it's kind of this thing here, right? Um I see people create um to oh, all my controllers go

here and all my exceptions go here and my all my repositories go here, which is understandable because or the the analogy I usually use for that is that it's like if you at home in your flat, you were putting all of the chairs in one room and all of the tables in another and all of the the closets and wardrobes in a third room, which is incredibly

convenient if you spend your entire day answering the door because of one of your neighbors comes like can I borrow a chair? And then you oh, I need to go into this room to grab one. But it's incredibly inconvenient if you want to have friends around and dinner with them, right? Because right? You you you need to bring these things together to perform as Ackoff said, to

make the connections and then have a higher value than just a chair and a table like pieces of wood basically combined. there's one more thing and I briefly hinted at that in the keynote. Um there is this um how do I start this? Um the way I I we we talked about um architectural elements here in forms of in in the form of adapters or layers or

onions. It's kind of it they all have serve one purpose is to build our mental models or yeah, the mental models of about our code base. The way we think about our code base, the way we think about our software design um is shaped by these approaches, right? That's why they exist and they exist because they allow us to reduce the complexity um or be as as

abstract as possible, but as concrete as needed. When we talk when we all have an a shared understanding of hexagonal architecture, I can say adapter and everyone in the room knows what I mean actually knows about the traits of the thing that I'm talking about, right? It's things that are allowed to connect to a certain technology. They are not allowed to reference the domain in particular, what

have you. So, we use these abstractions and pattern languages to build and shape our mental models, our understanding of the piece of software that we work on. And then we go back to our computers, open up our IDEs, and get presented with source main Java, right? Folder structures that are kind and it's it's folder structures essentially and there's a thin layer of Let me where do I

need to go? Here? And then slide over here. There's a very thin layer of abstraction over the actual file system, right? Because in this case it's VS Code, it knows let me scale that up a bit. It knows about the notion of a source folder, right? It basically knows the Maven or the build system abstractions and it groups them accordingly. It then knows that everything underneath that

is a package, so it doesn't present us with like folders to navigate, but like a combined thing of I don't know, the packages. But that's a very like again technology-centric abstraction. It's not totally not on the level of abstraction that these architectural pattern languages talk about, right? They talk about adapters and ports and aggregates and what have you. And there is this other side project that I'm

a bit involved with called J Molecules, which intends to allow you to express these stereotypes and architectural design elements in your code base. So, that if you navigate to uh for example, >> uh you have this order thing here and there's a order type. There is a type-based type-based basically yeah, pattern language called the aggregate root. Is a hover here? See that's org.jmolecules.ddd.types. So, there's a basically

a set of JAR files in which you can in the contains JARs types that you can that you can then use to assign these roles similar to what Spring does with at controller and at service to these elements in in your in And I've worked with the with the tools team, the Spring Tools team to actually bring that abstraction uh to your IDE, right? So, that you

actually can go ahead and see that in the in the lower left here already. So, this the IDE recognizes this is a Spring Modules project in this case. So, it uses all the structural information in the code base to to present like the logical modules in here. If you created a new package basically in in in parallel to order, that would automatically create a node here, Um

and there is like it automatically analyzes which of the J Molecules libraries you use on the on the class path and groups your coding elements according to the stereotypes. So, that you don't have to create packages named repository, named configuration, named what have you, you probably see this here in there's like the initializer, there's a projection in order. This is basically Spring Data projections. You find that

down here, And there's again you you might not realize, but again it's functional decomposition first, functional groupings and then everything else like the design languages like domain driven design or technical stuff like spring configuration classes is here as well. And guess what? I've done like there's a bunch of this project in which I go ahead and say I want to use hexagonal architecture as the technical decomposition

approach which means that I actually say that my payment web There we go. My payment controller is a primary adapter. >> You could argue like why would I have to do that in explicitly because we could like kind of derive that a controller is an adapter just as I presented before but let's let's stick with the with the idea of we we make this explicit now. Then

there is If you just enable the hexagonal architecture stuff here, you basically get this thing turned into a much more readable in the back here. Let me zoom this up a bit. Right? You get these abstractions, these architecture specific abstractions folded into the tree so they essentially form a sub level of grouping here so you can see okay and all my prime The primary adapters consist is

some request mappings, here's some controllers and there's something coming from Spring HATEOAS like representation model processes, whatever that is, right? An abstraction that's specific to the web player in this case, right? And this is not only for predefined annotations, you can go ahead and I think I've done that That's been like like in slightly more advanced step of the exercise is that we created Wait a second.

Nope. I think it's here, right? So what I what I did here is I created an interface DTO in this particular project a DTO is a concept. Is a thing that I exchange about with my team. We all know what it means, we know what what characteristics are stick with it and you probably have these things in your applications as well. Things that have not made it

into books because someone wrote about them but they are kind of not maybe not domain specific but company specific. You could just create these abstractions, annotate them at with at stereotype and there should be There's not Why is there not? Let me let get this out of the way. There should actually be there is a payment form thing going on. It's hard to navigate this way. Sorry

about that. But payment form I clicked it. In the payment controller boy. Oh boy. I love it when the shortcuts don't work. There should be a payment form implements DTO and it should actually show up in the payments slice down here. Does it do? Yeah, it does. The pluralization is a bit broken. It should not be DTOs but You see that just because you added the stereotype

into your project, you add the annotation to it. There's some annotation processor running and then the IDE automatically picks that up. So you don't need to ask or wait for the tools team to integrate with with the your abstractions but you can actually introduce these abstractions in a way that the IDE will pick them up and and present them to you and allow them both to think

and navigate the code base in in those terms. Available in everything that's Spring Tool Suite based so VS Code and Eclipse. I've been just talking to the guys over It's going to be something for IntelliJ That's actually all I have for now. So we have like 5 minutes for questions. Thank you very much. >> [applause] >> Any questions? If you're too shy, I'm the short guy with

a hat. I'm easily discoverable despite my lack of height. Excuse me? Oh, there were ask them in the app. That's a good one. Good point. Yeah, please leave feedback. If you liked stuff, if you didn't like stuff, that's that's that's fine. I can I love feedback. Where do I find the stuff? Agenda domain centric There's a couple of likes. There's four questions. Oh boy. How do you

see modules relating to bounded contexts? My take is that ideally they overlap but there are reasons why they should not. If you follow the domain driven design school then a bounded context consists of one or more modules. So if they are modules are a a means to subdivide bounded contexts into different like again functional parts. The What's associated with the with the bounded context is usually a

bit of like technical work in terms of like anti-corruption layers and and yeah, being defensive about what you can hand in or hand out. So it's not a bad idea to start with a one-to-one mapping so but you don't necessarily need to be as strict in terms of like being receiving data or what have you. Would you share models across the module boundaries? Why or why not?

I would try to avoid that as much as possible accepting that it's not always possible. Right? So try to the these kind of core packages, they always exist or you two things. I usually rename them to kitchen sink and then people are less likely to put stuff in there. When to use modules and when separate microservices? Hard question. I would definitely need to take a look at

the circumstances of the project. There's two main drivers. One is like technical aspects like scalability. Although you can achieve a couple of things even within a monolith with with terms of caching. scalability If you need to use other programming language platforms like I don't know, there's a special thing that's only available in Go then of course you need to build that as a separate application. The other

thing a non-technical thing is organization. So Conway's law applies. a lot of teams that need to work on the same code base that still works on a well-structured monolith so you can you can still do that and I hope I this morning in the keynote I made a a case for these teams even being able to roll changes quickly but it totally makes sense to look into

does it maybe build a separate application just to give them their their own space. On the other hand, I always get a bit like weird or bit concerned if I see a team managing 15 different applications that are actually logically one, right? That's that's what I would would or is at least a smell. Um models Yes. Do you have any tips or suggestions for adopting a modular

architecture? I'm currently using a Gradle multi-module setup to separate responsibilities. First thing is your you apparently are um aware of the problem. You found a means to actually solve your problem and if in doubt I would stick to that, right? So don't change things for the sake of changing things. Sometimes it's possible to get rid of a couple of these especially if I've just been with a

customer. They had like a an OSGi based application from the ancient past. 500 OSGi bundles and from these 500 OSGi bundles they composed three different kinds of applications like a core application and then these kinds of satellite things and we actually reduced them to the exactly these three kinds of not three or it was four or five actual because they didn't need the composition in in that

fine in that fine grained way, right? Whenever it's you produce artifacts, it also means that you expose the the decomposition to external parties which might not be a problem in itself but if they then have to reassemble these things, it might just be more complicated. It's actually also a balancing act for us in the Spring Framework, right? So Does Spring would be easier to consume Spring if

if it was just one jar, right? But at the same time you would want not want to deploy like I don't know, 15 megabytes of of code that's not needed. So there is this balancing act between the amount of artifacts that you produce and the the size of the artifacts. And if in doubt, stick with the with the with the modules with the build modules and you

can still use Spring modules for integration testing, for generating documentation. That would still work, right? Even with if you use like something like JPMS for the actual low level module system. What are your thoughts on a BFF? I think that's back end for front end module. I often find that end user needs aggregated data from multiple modules. Yeah, so that's kind of the um That's actually a

hill I'm willing to die on is that I think that this split of front end application and back end applications is the weirdest thing that I'm not sure who came up with that, but I guess developer or tech technological operation um technology companies are centered around we do Java and we do JavaScript and that's why we we form separate tribes and we don't want to talk to

each other. and I think most teams would be better off if there was no such split because if you think about it, if you have a front-end team and the back-end team, none of the two teams can actually ship a feature in the form that it's valuable to a customer. The front-end team cannot because it has to wait for the back-end team. If the back-end team ships

stuff and there's no front-end for it, no customer is actually going to use it, right? So, um it feels like a continuation and and an extension uh of the kind of horizontal split thing. So, I would want to avoid that. It doesn't mean that we we shouldn't have like experts on the particular technologies um >> in the teams, but if it if in doubt, I'd probably start

from that assumption and there's probably valid reasons in in in many cases for that split then to happen still, but you've got to be aware of the the downsides that that brings, right? How much time? I'm I'm over I'm over That's We had that already We had that That's a bit of a little compli- complicated one. It also needs a more unweighted answer. I'll be around all

day today uh tomorrow. Catch me if you can, huh? It's fine. Thank you very much. Thank you for your time.

From event

Spring I/O

13 Apr 2026 – 15 Apr 2026

All event videos
Back to Watch