I just learned this simple thing about Hexagonal Architecture
I'm on the TGV between Paris and Lyon. I'm to see my mum who I have not visited for a while. I was not at home in the extreme west of France this week so it tightens the distance. It's easier. I'm grateful to my wife for managing the kids and the home while I do the trip.
OK, why was I in Paris this week, far from home? I gave a training course about Hexagonal Architecture, Clean Architecture, and Domain-Driven Design. I truly had a blast during the session, trying to explain concepts in understandable ways with a lot of live coding.
I've bought and read the book Clean Architecture by the famous Robert C Martin AKA Uncle Bob. I've not bought it before, because I read his blog posts and heard his talks about the topics before he wrote the book. It seemed to be a synthesis of Hexagonal Architecture, Domain-Driven Design, and Onion Architecture, so I thought there was nothing new. I was not completely right and I adopted a new practice, which I find particularly effective: encapsulate domain objects interaction in a use case object.
![Clean Architecture diagram](CleanArchitecture.jpg)
Until now, when I was adopting a classical DDD approach with repositories and aggregates in a web app, I simply retrieved needed aggregates using associated repositories from within the controller's methods. My aggregates are unit tested (TDD fashioned) and my controllers are tested against a test database with an acceptance test. When data has to be returned to the caller, it's generated directly by the aggregate. It may be heavy in statically typed languages like Java or C# but not a big deal in Python or Javascript.
While this approach works well, it shows 2 issues:
- There is a lack of encapsulation as the controllers have to know about how aggregates and repositories interact together.
- The controller needs a larger acceptance testing coverage: I have to test all the possible paths of interactions between my domain objects.
When using a use case object from the domain, I can rearrange the interactions between domain objects and repositories interfaces without impacting my controllers.
I can write isolated integration tests against the use case object to validate their interactions, which allows me to reduce the acceptance test volume. I like doing so because such tests take more time to execute and can easily become flaky if I have an issue with the database. Don't get me wrong though, they are necessary as they ensure that the parts of the applications correctly talk to each other.
There is more to write about this, but my train is arriving at the station. It will be for another day.
You liked what you read? I'm Romain Touzé. I do consulting, project management, programming, and now training. I'd be glad to help you with your projects so drop me an email.