Writing Ports and Adapters for an Hexagonal Architecture
Dec 29, 2014 10 minute read
Domain Driven Design (DDD) is all about the domain. It is challenging on the number of abstractions which needs to occur to protect the domain at all costs; the concepts which is challenging to the programmer who comes from a layered n-tier application.
Micro-services seem to be the up and trending opinion on how applications should be built to deliver nimble, yet very powerful solutions to the business domain; which compliments the DDD mantra very well.
The technical principle from micro-services and DDD is simple: only focus on the properties of the supplied inputs and desired outputs of the process, and leave the implementation details to be filled in where and when required. So much so, DDD has a concept of Context Maps which has the sole purpose to determine what things go where, but not how those things are operated.
I have been doing a lot of thinking about applying that same principle into the Ports and Adapters when sending inputs to the the domain, and expecting a certain response. Some less desirable concerns always needed some level of implementation detail to be handled by the developers, such as the following list.
Mixing asynchronous and synchronous operations.
Converting between primitive types.
The ability to compose new operations, without being required to build a whole new domain service.
Whilst thinking about the above problems, my appreciation for the UNIX philosophy grew. Simply pass stream into stream with each micro-program performing an operation so that larger programs could be wielded together.
First Skunk Works
My first stab at creating a pattern which reduces the upfront implementation concerns heavily relied on the Mediator pattern which would query the Dependency Injection framework for the details. From a high level, an IHandler<TInput, TOutput> interface was implemented by the various “micro-programs.”
We then ran into a few issues with the above approach.
Application start-up was slow. Scanning all the assemblies for the relevant types were slow.
There was a massive explosion of micro-classes within the subsystem.
It never solved the mixing of asynchronous and synchronous code.
Introducing SemanticPipes 1.0
I tried to locate a library which would address the stated desired characteristics, but my search seemed to have zero results. Since it was an itch that I needed to solve, and explore the problem, I started to code SemanticPipes under the MIT license.
The SemanticPipes code base has reached a version which, in my view, is suitable for others to start adopting it in their own production environments. So the version number has ticked over to 1.0.
Quick Start Example
Below is an extract of the example which has been placed in the README file.
Here is a quick start guide in a form of a unit test. The code is written to be read from top down, and the comments describes what is being demonstrated.
Take note that the test will run in about 1 second, and not n*1sec where n=7 (parallel execution). This is because when the view model pipe scatters the various domain requests as a parallel task. Upon the gather of the List<PingServerDomainResponse>, an implicit gather is made. So how about that? Implied parallel processing loops without the programmer thinking about it.
And here is the code listing.
Justin Lovell is an engineer at heart, and loves building things
through software development.