Towards Hexagonal Architecture - Separating Presentation Concerns
In this article, I show how we can refactor code such that the presentation concern is untangled from the business concern, an important step towards Hexagonal Architecture.
In a previous article, I illustrated how to identify different concerns in a codebase. Here I will demonstrate how to separate the presentation concern effectively from this (small) Ball of Mud using the refactoring techniques presented in the following post.
Presentation Concern And Application Services
The presentation concern has three major tasks:
Mapping incoming presentation data (e.g. a JSON) to an application-service-specific input format.
Invoking the application service’s use case method.
Mapping any potential output from the application service to a presentation output format (e.g. HTTP / JSON).
It’s not necessarily the presentation concern’s task to validate input data. Instead, the service method needs to ensure that only valid data can be used to invoke it and handle cases of invalid data. This could be throwing exceptions or returning an error result.
Let’s get back to the codebase you can find here and move all presentation concerns out of the service and into the controller!
Separating Presentation Concerns from Application Service
There are several places in reserveParkingSpot where presentation data structures are directly accessed and presentation logic is used to create and return presentation-specific results, see the orange parts below.
However, converting input and results to and from the application service should only happen in the presentation concern, meaning in the corresponding ParkingSpotReservationController
, which currently only delegates inputs to the service method without any mapping and directly returns whatever the service produces:

Let’s get started with the separation! You can also watch the following video alongside to see the applied refactoring techniques in action.
Isolate Presentation DTOs
Currently, there are multiple accesses to the request’s startTime, endTime, and reservedBy fields. To access them independently from the presentation’s ParkingReservationRequest
DTO, we can first extract the 3 fields into separate local variables and use them instead of the request’s getters:
We can apply the same to the reservation’s ID at the end of the method when we map back to a ParkingReservationResponse
DTO:
We already achieved some local separation by only using primitive data types like LocalDateTime
or String
that are neither presentation-, nor data-access or business-concern-specific.
Replace Return Types with Exceptions
As a next step, we need to separate HTTP return values from the business rules that cause them.
To do so, I start to throw business-specific exceptions in the service where the responses were returned previously, and then map them to the HTTP ResponseEntity
in the catch clause.
Let’s start by adding the try-catch around the non-presentation part of the reserveParkingSpot
use case method:
We need to also move the Long reservationId
outside of the try-catch as we need to return it from the service and then use it in the ParkingReservationResponse
.
Let’s turn the first error case for “Reservation must be at least 30 minutes long.” into an exception ReservationShorterThan30MinutesException
and handle the case in the catch part.
We should do this for all the exceptional cases. We can additionally introduce the following exceptions in the service package:
EndTimeMustBeAfterStartTimeException
ReservationOutsideOperatingHoursException
ActiveReservationExistsException
NoAvailableSpotsException
And handle them accordingly in the catch clause:
Physically separating business rules further from presentation logic.
Move Presentation Concerns to Controller
Now we can extract the part within the try {}
block into an own method, for example reserveParkingSpot2
:
We can turn this method public and inline the outer reserveParkingSpot method into the ParkingSpotReservationController
, and then rename it to reserveParkingSpot
.
The final service method is free of any presentation concern:
The controller, on the other hand, now does exactly what I initially outlined. It:
Maps incoming presentation data to an application-service-specific input format.
Invokes the application service’s use case method.
Maps any potential output from the application service to a presentation output format (e.g. HTTP / JSON).
There are still other transformations possible, but for presentation concern separation, this is about it! You can find this solution on the following branch: separating-presentation-concerns.
Conclusion
In this post, I demonstrated how to effectively remove presentation concerns from application service by introducing service-specific exceptions and handling them within a try-catch block.
In the next post, I will also encapsulate data access concerns and remove them from the service method, so stay tuned if you don’t want to miss it by subscribing to our blog:
Resources
If you want to effectively discern concerns, see the following post.
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.