Towards Hexagonal Architecture - Separating Data-Access- and Business Concerns
Depending on database entity classes in business logic can lead to a big ball of mud over time. Here I will show how to do a clean separation between the two.
In the last article, I showed how to separate presentation from business concerns in a codebase. The next step to move towards a business-centric architectural design pattern like Hexagonal Architecture is to separate data-access-concern data structures from business concerns, which I will show here.

I will continue with the same codebase on the branch separating-presentation-concerns. You can also find all the step-by-step modifications in the video below. If you don’t want to miss future articles on this topic, simply subscribe here:
Choosing Appropriate Names for DB Entities
Let’s start by investigating the two entities present in the model package, ParkingReservation
and ParkingSpot
. Both are actually SQL table rows represented as Java objects:

They are part of the data-access framework we use and should not be part of the application service. Neither should they contain any business rules.
Instead, they should be seen as simple anaemic data containers with respective getters and setters that represent the cells in a SQL row.
Thus, to better mark these entities as the SQL rows they actually represent, I choose to rename them to:
ParkingReservationDBEntity
ParkingSpotDBEntity
.
This will make it easier to distinguish them from application-specific data structures we’ll introduce later. Additionally, I rename the corresponding repositories accordingly to:
ParkingReservationDBEntityRepository
ParkingSpotDBEntityRepository
.
Mapping between Business- and Data-Access Concerns
An important idea to achieve concern separation and thus independence from the data-access frameworks or technologies is to keep as much of their annotations and magic out of the business concern as possible.
This means that we need to map between data-access- and business concern data structures that we exchange between these two layers, and that the data-access-to-business-concern mapping function called by the business concern cannot expose any data-access data structure to that business concern.
So let’s get started :)
Adapting Parking Reservations
As a first step, I create a ParkingReservationRepositoryAdapter in a new data_access package and add the ParkingReservationDBEntityRepository as a field. This is going to be the class that handles mapping between data-access and business concerns.
As a second step, I investigate the application service to see which calls I need to map data to and from.
The first access to ParkingReservationDBEntityRepository is actually the “hasActiveReservation” call. The signature of this method does not have any data-access specific entities, so in theory, it corresponds to the rule that there should be no data-access class in the business service.
However, I want to eventually get rid of any data-access repository, so I will for now simply let the ParkingReservationRepositoryAdapter delegate this method call to the ParkingReservationDBEntityRepository:
Adapting Parking Spots
As a next step, I want to create a similar delegation for the ParkingSpotDBEntityRepository’s findAnyAvailableSpot method. This time, I need to map the DBEntity to a corresponding class of the application service.
Let’s implement it as ParkingSpot and add it to the service package. This class will currently only contain the Long id that it gets from the ParkingSpotDBEntity.
I create a method inside the application service that returns an Optional<ParkingSpot> and map the found ParkingSpotDBEntity’s id to it if it is not null, effectively getting rid of the implicit null check for availability in the application service. I can then move the method to the ParkingSpotRepositoryAdapter and use it in the application service:


Storing a new Parking Reservation
As a third step to remove the framework-dependent data-access repositories, I want to hide to steps to create a new Parking Reservation, i.e. that also a ParkingSpotDBEntity
’s isAvailable
field needs to be set to false.
To do so, I wrap the entire creation & storage of the reservation, together with altering the spot’s availability, in an own method storeReservation:

There is one additional step compared to the previous entangled solution to effectively separate the two concerns: I need to find the ParkingSpotDBEntity once again by id and set its availability to false.
An alternative solution could have wrapped also the search for an available spot, but in my opinion, we would move too much business-relevant logic into the repository adapter.
I want to keep my repository adapter as dumb as possible for now, and fetching the same parking spot twice seems like a reasonable trade-off. However, this initial solution may change in a later article.
If we look at the signature, we see that there are only primitives and the ParkingSpot class present. Even though not optimal, this signature is entirely free of data-access-specific classes, so the separation of business- and data-access concerns is almost complete.
I can finally move the method into the ParkingReservationRepositoryAdapter:
And use it in the application service:

This solution now contains no data-access types like ParkingSpotDBEntity or ParkingReservationDBEntity anymore but only business-concern-specific ParkingSpot and primitive data types, effectively separating business- from data-access concern. You can find this solution on the separating-data-access-concerns branch.
Conclusion
In this article, I have demonstrated how we can separate the business- and data-access concerns by introducing adapters that map between the two.
There is still some work left: even though the methods of the adapter classes already only use application-specific data structures or primitive types, the application service still depends on these adapters, which means that the business concern knows about the data-access concern.
In a next step, therefore, I want to demonstrate how to finally get rid of any data-access dependency and implement a truly business-centric architectural design pattern reminiscent of Hexagonal Architecture. Subscribe if you don’t want to miss it:
Resources
This article is part of a series moving towards a business-centric architectural design. See the following post to get started.
This series of articles is an addition to the From Layered to Hexagonal Architecture in 2 steps article.
We touch on the same topics in our O’Reilly course “DDD, EventStorming, and Clean Architecture”. Check it out to learn how to use Classic TDD to implement DDD Aggregates in Hexagonal and Clean Architecture.
If you want to learn more about effectively separating concerns, you could also have a look at our on-premise, remote or hybrid workshop Modern Software Architecture Design Patterns.