Clean Architecture with Java 11


Software architecture has been one of the most important topics in the last couple years when it comes to software engineering. Robert C. Martin (aka Uncle Bob) deeply developed his vision of a clean architecture in his book, that I highly recommend. But when it comes to implementation, things get difficult and many questions appear. Where do I start? How do I structure my project? How do I apply Uncle Bob’s principles to the technology I want to use? I will try to answer those questions from the point of view of a Java web developer that would like to use Java 11 and Jigsaw modules from Java 9. This will give you a more concrete vision of Uncle Bob’s clean architecture.

Clean architecture

Before diving into the implementation, let’s have a look at the architecture:

Image for post
Image for post
  • Entities: These are the business objects of your application. These should not be affected by any change external to them, and these should be the most stable code within your application. These can be POJOs, objects with methods, or even data structures.

The key concepts here are:

  • Any layer can only reference a layer below it and know nothing about what’s going on above.


Setup of the project

We are going to use Gradle multi-project and Java Jigsaw modules to enforce the dependencies between the different layers.

The application we are going to build is very simple and the architecture will probably appear overkill for such a project, but this is the best way to understand how this all works.

The features of the application will be:

  • Create a user.

To do so, we will start with the inner layers (entities/use cases), then the interface adapters layer, and we will finish with the outer layer. We will also demonstrate the flexibility of the architecture by changing the implementation details and switching between frameworks.

Here is a view of the project:

Image for post
Image for post

Let’s dive into the implementation.

Inner layers

Our entities and use cases are separated in two sub-projects, ‘domain’ and ‘use-case’:

Image for post
Image for post
Domain and Use-case

These two sub-projects represent the heart of our application.

The architecture must be very explicit. By having a very quick look at the example above, we know right away what kind of operations exist and where. If you were to create a single UserService instead it would be difficult to tell what kind of operations exist within that service, and you would need to dive into the implementation to understand what the service does. In our clean architecture, we just need to have a quick look at the usecase package to understand what kind of operations are supported.

The entity package contains all the entities. In our case we are going to have only one, a User:

The usecase sub-module contains our business logic. We are going to start with an easy use case, FindUser:

We have two operations, and those two operations need to retrieve users from a repository. This looks pretty standard in a service oriented architecture. UserRepository is an interface that is NOT implemented within our current sub-project. This is considered a detail in our architecture, and details are implemented in outer layers. Its implementation will be provided when the usecase is instantiated (via Dependency Injection for example). This provides some advantages:

  • Whatever the implementation is, the business logic remains the same.

Note that the interface is also known as a port, as it makes the bridge between the business logic and the outside world.

Let’s now build a first iteration of our CreateUser use case.

In the same way as the FindUser use-case, we need a repository, a way to generate an ID, and a way to encode a password. These are also details and not business rules, and will be implemented later in outer layers.

We also want to validate that the provided user is valid (contains correct data), and that it does not exist already. This leads to our final iteration of the use-case:

If the user is not valid or exists already, a custom runtime exception is thrown. Those custom exceptions should be handled by other layers.

Our last use-case, LoginUser, is pretty straight forward, and is available in GitHub.

Finally, to enforce boundaries, both sub-projects use Jigsaw modules. Jigsaw modules allow us to expose to the outside world only what needs to be exposed, so no implementation details are leaked. For example, there is no reason to expose the UserValidator class:

To summarize the role of the inner layers:

  • The inner layers contain domain objects and business rules. This should be the most stable and tested part of the application.

Outer layers


Now that we have our entities and use cases, we can implement the details. To be able to demonstrate that the architecture is very flexible, we are going to create several implementations and use them in different contexts.

Image for post
Image for post

Let’s start with the repository.


UserRepository implementation with a simple HashMap:

Another implementation with Hazelcast can be found on GitHub.

Other adapters:

Other adapters are implemented the same way just by implementing the interface declared in the domain. You can find them on GitGub:

Putting everything together

Now that we have our implementation details, we need to assemble them together. To do so, we need to create a config folder that contains the configuration of the app and an application folder that contains code to run the application.

Here is one of the configs:

This config initializes the use cases with relevant adapters. If you wanted to change the implementation you could easily switch from one adapter implementation to another without having to modify the use-case code.

The following is the class that runs the application:

Web Frameworks

What if you want to use a web framework like Spring Boot or Vert.x? It’s pretty easy — we just need to:

  • Create a new configuration for the web app.

Here is what the Spring controller looks like:

You can find the full example of this application in GitHub using both Spring Boot and Vert.x.


We tried in this article to show how powerful Uncle Bob’s clean architecture is. Hopefully it’s a little bit clearer for you.


  • Power: Your business logic is protected, and nothing from the outside can make it fail. Your code does not depend on any external framework “controlled” by someone else.


  • Learning curve: At the beginning, the architecture can be overwhelming, especially for junior developers.

The project on GitHub provides more details about how to handle the web frameworks. I would encourage you to checkout the code and play with it if you are interested.



Image for post
Image for post

Slalom Build

The Build Blog is a collection of perspectives and…

Carl-Philipp Harmant

Written by

Software Engineer

Slalom Build

The Build Blog is a collection of perspectives and viewpoints on the craft of building digital products today, written by the technologists that build them. By builders, for builders.

Carl-Philipp Harmant

Written by

Software Engineer

Slalom Build

The Build Blog is a collection of perspectives and viewpoints on the craft of building digital products today, written by the technologists that build them. By builders, for builders.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store