Over a million developers have joined DZone.

Remembering Clean Architecture

DZone 's Guide to

Remembering Clean Architecture

Before picking a framework or a language, agree with your team on architecture. This sample Spring Boot app walks through a refactoring focusing on clean architecture.

· Java Zone ·
Free Resource

As developers, we can spend considerable periods of time debating and advocating various languages and frameworks.

Irrespective of the pros and cons of a particular language or framework, if the architecture isn’t clear and agreed upon from the beginning, then interest in building new and the ability to maintain existing functionality diminishes. 

Basically, the pride that went into creating it wanes, and what was once fun to work on is now a burden.

Does the loose structure of Fig.1 below seem familiar?

It led me to ask the following questions:

What is the intent of this application? How is that intent fulfilled? Why are there so many packages at the root level?

Image title

Fig. 1

The answers to the above can certainly be found, but it comes across that things were added after the fact without really knowing where they are meant to go.

This seems like a case where the architecture wasn’t clear from the beginning and, as the application grew, it became further unclear.

There is no clear separation between what the application does and how it does it.

Begin With a Clean Architecture

Before even selecting which language or framework to use, determine and agree upon the architecture.

Robert C. Martin and others have provided great material on this subject, and I am going to share my understanding.

Before I even started refactoring the code, I first decided upon the architecture (see Fig. 2 below).

Image title

Fig. 2

See this example repository on GitHub for the intent of each module.

Refactor to a Cleaner Architecture


Image title

The usecase implements the interfaces in the boundary.enter package and uses the ones in boundary.exit.

Depends on: This module has no dependency on any other module. It is also framework agnostic.



This module contains the repositories that retrieve or edit data in the database.

It implements the interfaces defined in the boundary.exit package, meaning that this module has a direct dependency on core.

Depends on: core


This module contains the controllers (e.g. REST API).

This module uses the adapter module to communicate with the core, meaning that it has no direct dependency on the core.

Depends on: adapter


Image title

My original intention of the adapter was to handle all the communication with the core, hence nothing in the periphery would ever depend directly on the core.

However as described above, the data module in the periphery does not use the adapter, it’s only used by the web module (converts the domain objects into the api that the web module expects).

The reason is that I didn’t want any framework knowledge inside the adapter module, and since I am using Spring Data in my data module, there isn’t a way to use the data module without making the adapter Spring Data aware.

Depends on: core


Image title

This module glues everything together.

It contains the MainApplication (in this case a Spring Boot application), all the Spring @Configuration files and the resources needed to make the application work.

Depends on: adapter, core, data, and web

Other Improvements

During the refactoring, I detected that some of the tests were actually integration tests and that they no longer had a home inside any of these new modules.

As a result, I moved all these tests to a new integration-test module.


Although there is no definitive answer on how to architect a software solution, I feel that agreeing upon a clean architecture up front will pay dividends.

Above I have described my journey towards a cleaner architecture and, as an aid, I have created a sample application on GitHub to demonstrate it.

java ,spring boot ,clean architecture ,tutorial ,refactoring

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}