How I think about Vaadin application architecture today

During the past year, my main task at work has been to come up with and publish a recommendation for how business applications should be built with Vaadin. This is an ongoing task that won't end as long as Vaadin remains in business. It's also a task that involves sifting through lots of patterns, practices, and opinions. Everybody has their own preferred way of building business applications with Vaadin - including myself. You may already have read my articles about domain-driven design. It's still an approach I keep close to my heart, but I also realize there are many cases in which other approaches are more appropriate. I could say the same about the ports-and-adapters/hexagonal architectural style. Well, It Depends When I was still working as a consultant, helping customers with various Vaadin (and sometimes non-Vaadin) related problems, my first answer to many of their question was "well, it depends". Then, as we gathered more information about the problem, we could narrow down the options until we were confident to make a decision. When making an architecture recommendation, there's no size that fits all. The best you can do is to come up with a recommendation that hopefully scales. You start out with something simple that you can expand later, if needed. You have to future proof just enough, avoiding painting yourself into a corner while also not over-engineering anything. My approach to this problem was to go back to the various designs and architectures I've used in my career, and my favorite books on the subject. However, instead of just selecting one at face value, I wanted to pick them apart to find the fundamental ideas behind each, and build something from that. I wanted to find something that would resonate with most developers (including myself), use terms that were familiar to most developers, and that could be converted into the most common architectural styles without too much effort. Backend or Frontend? I soon ran into my first terminology problem. A traditional web-app consists of a frontend and a backend. The frontend contains the UI and runs in the browser; the backend contains the business logic and runs on the server. However, this is problematic in a Vaadin application. For a Hilla UI, the frontend-backend distinction still applies. For a Flow UI, a big chunk of the user interface actually lives and runs on the server. I decided to introduce the terms presentation layer and application layer. The presentation layer contains everything related to the user interface, regardless of whether it's running in the browser or on the server. The application layer contains "the rest of the application", that is, business logic, persistence, integrations to other systems, and so on. Thus, instead of talking about frontend and backend, I try to talk about presentation layer and application layer. I'm still doubting whether I should have called the presentation layer the UI layer instead... Starting in the Presentation Layer Since Vaadin has always been about the user interface, I decided to start there. If I stand in the presentation layer and look at the application layer, what do I see? A big, black box with API:s that I can use. Some API:s may be more generic in nature, others may have been especially crafted for me alone. Now what to call these API:s? Ports? Endpoints? Facades? Boundaries? Services? Controllers? I decided to settle for application services, inspired by the book Implementing Domain-Driven Design by Vaughn Vernon. I figured most developers would be OK with the idea of having a user interface call services to do what it needs to do. Looking at the Application Services So what does the implementation of the application services themselves look like? Well, that depends... For instance: They could send SQL queries to a database directly. I would not recommend this for anything but really simple, throw-away applications, but it is possible. They could implement business logic and delegate to DAO:s or repositories to interact with the database. They could orchestrate workflows with a deep domain model. Regardless of how the application services are implemented, I think they should always handle two main responsibilities: manage transactions and enforce security. Transactions If an application service method touches a database, I believe that method should run inside its own transaction. The application service itself should be responsible for starting the transaction, and either committing it or rolling it back before returning. Security I've always considered security in the user interface as improvements of the user experience rather than real security. Even when writing Flow UI:s, I've always protected my application services with method-level security. This means that even if I forget to hide or disable a button in the UI, a user can't perform an unauthorized operation. This is also th

Mar 27, 2025 - 15:36
 0
How I think about Vaadin application architecture today

During the past year, my main task at work has been to come up with and publish a recommendation for how business applications should be built with Vaadin. This is an ongoing task that won't end as long as Vaadin remains in business. It's also a task that involves sifting through lots of patterns, practices, and opinions. Everybody has their own preferred way of building business applications with Vaadin - including myself.

You may already have read my articles about domain-driven design. It's still an approach I keep close to my heart, but I also realize there are many cases in which other approaches are more appropriate. I could say the same about the ports-and-adapters/hexagonal architectural style.

Well, It Depends

When I was still working as a consultant, helping customers with various Vaadin (and sometimes non-Vaadin) related problems, my first answer to many of their question was "well, it depends". Then, as we gathered more information about the problem, we could narrow down the options until we were confident to make a decision.

When making an architecture recommendation, there's no size that fits all. The best you can do is to come up with a recommendation that hopefully scales. You start out with something simple that you can expand later, if needed. You have to future proof just enough, avoiding painting yourself into a corner while also not over-engineering anything.

My approach to this problem was to go back to the various designs and architectures I've used in my career, and my favorite books on the subject. However, instead of just selecting one at face value, I wanted to pick them apart to find the fundamental ideas behind each, and build something from that.

I wanted to find something that would resonate with most developers (including myself), use terms that were familiar to most developers, and that could be converted into the most common architectural styles without too much effort.

Backend or Frontend?

I soon ran into my first terminology problem. A traditional web-app consists of a frontend and a backend. The frontend contains the UI and runs in the browser; the backend contains the business logic and runs on the server. However, this is problematic in a Vaadin application.

For a Hilla UI, the frontend-backend distinction still applies. For a Flow UI, a big chunk of the user interface actually lives and runs on the server. I decided to introduce the terms presentation layer and application layer.

The presentation layer contains everything related to the user interface, regardless of whether it's running in the browser or on the server.

The application layer contains "the rest of the application", that is, business logic, persistence, integrations to other systems, and so on.

The presentation and application layers in Flow and Hilla

Thus, instead of talking about frontend and backend, I try to talk about presentation layer and application layer. I'm still doubting whether I should have called the presentation layer the UI layer instead...

Starting in the Presentation Layer

Since Vaadin has always been about the user interface, I decided to start there. If I stand in the presentation layer and look at the application layer, what do I see? A big, black box with API:s that I can use. Some API:s may be more generic in nature, others may have been especially crafted for me alone.

Now what to call these API:s? Ports? Endpoints? Facades? Boundaries? Services? Controllers? I decided to settle for application services, inspired by the book Implementing Domain-Driven Design by Vaughn Vernon. I figured most developers would be OK with the idea of having a user interface call services to do what it needs to do.

A diagram illustrating the presentation layer calling an API of the application layer

Looking at the Application Services

So what does the implementation of the application services themselves look like? Well, that depends... For instance:

  • They could send SQL queries to a database directly. I would not recommend this for anything but really simple, throw-away applications, but it is possible.
  • They could implement business logic and delegate to DAO:s or repositories to interact with the database.
  • They could orchestrate workflows with a deep domain model.

Regardless of how the application services are implemented, I think they should always handle two main responsibilities: manage transactions and enforce security.

Transactions

If an application service method touches a database, I believe that method should run inside its own transaction. The application service itself should be responsible for starting the transaction, and either committing it or rolling it back before returning.

Security

I've always considered security in the user interface as improvements of the user experience rather than real security. Even when writing Flow UI:s, I've always protected my application services with method-level security. This means that even if I forget to hide or disable a button in the UI, a user can't perform an unauthorized operation.

This is also the main reason why I never recommend people call DAO:s or repositories directly from their user interfaces. Although you can protect a repository with method-level security, it makes other things more difficult. One good example is writing background jobs, where the a background thread needs to access the database without a valid security context.

Layers vs. Components

I wanted to get away from the traditional layered way of thinking (UI layer, business layer, domain layer, entity layer, infrastructure layer, whatever-you-want-to-call-it-layer). I believe this is too limited, especially if you're only allowing dependencies from an upper layer to a lower one. This makes some things more difficult than they need be.

Instead, inspired by the C4 model of visualizing software, I've explored a component based approach, where an application consists of multiple components that interact with each other. These components aren't classified into any particular layer (except, maybe the presentation layer and application layer).

In my mind, a component has the following qualities:

  • It can have an API that can be called by other components.
  • It can have an SPI that can be implemented by other components.
  • It can be instantiated.

The problem here is that component is a saturated term in our industry. There are components everywhere and they all mean slightly different things. For instance, in Vaadin Flow, you compose your user interfaces by combining UI components.

In Spring, you can make a bean by annotating it with @Component.

Java as a language has no concept of a component at all.

So what is a component then? Is every application service a component, or do they form a component together? Is the domain model a component, or does it consist of components? What about integrations to other systems? Background jobs? Event listeners? Utility classes?

Enter analysis paralysis.

Naming is Difficult

My first attempt was to distinguish between system components and UI components, but I'm about to abandon that. I don't like terms that require a prefix for people to understand what they mean. Having application service and domain service as separate concepts is bad enough.

I've talked with colleagues and various LLMs about alternative naming, but nothing has really stuck. I'm now looking at identifying the typical building blocks of a business application and calling them what they are: entities, services, background jobs, repositories, and so on. I no longer try to force them into being components; however I do think many of them have the component qualities I listed earlier.

I've also started to look closer at Spring Modulith to see if I can get some inspiration from there, though at first sight, I think its application modules are more coarse-grained than what I'm looking for here. Or maybe not.

Next Steps

I plan to explore what a modern, data-driven Vaadin application could look like, and what a modern, domain-driven Vaadin application could look like. I'm hoping to get new insights and ideas that will make developing business applications in Vaadin even easier in the future.

If you have any comments, thoughts, suggestions, or counter-arguments I would very much like to hear from you!