This post is WIP & under iterative development!
At my current client, we’re being coached in the Hexagonal Architecture pattern.
Admittedly, the primary focus is towards the Programmers, but the change in the development strategy has an impact on us Testers so we get a seat a table.
What is this change in the development strategy which will impact us Testers? The pattern considers integration tests as brittle & unneccessarily linking the business logic to the implementation. As such, with this pattern, you want as few integration tests as possible. So the question is:
As a Tester, how confident am I that the removal of (automated) integration tests have not decreased the stability of the code?
In this 3 part series, I hope to learn more about hexagonal architecture, what it does for the teams test strategy & what the impact is for Testers.
The main advocate of hexagonal architecture (as far as I’m aware) is Alistair Cockburn who has written extensively about the pattern. He calls it the Ports & Adapters Pattern.
Thanks to Kevin Rutherford, I now have the means to describe the pattern & how it benefits software development.
Stand up & balance on one leg – how do you feel? stable? This represents the traditional view of software in a stack, with the presentation layer at the top & the data access layer at the bottom.
Its easy to change your facial expressions & add or remove hats without impacting the other layers in the stack (as it is the presentation layer).
If we progress to the next layer, yes its more tricky to change our shirts or jackets but we can still do it without impacting the other layers in the stack.
Now, try & change your shoes. How would you go about without putting your foot down? Tricky eh? You can’t change your shoes (data access layer) without impacting the other layers.
The hexagonal architecture pattern changes this person standing on one leg into a table:
- All the domain objects are built into the table
- The chairs around the table are the adapters
- A person resting on the back of the chair is an example of an external / 3rd party service
The structure of the table doesn’t change – the domain objects remain the same.
It is possible to change the chairs around the table – changing the adapters to suit the external / 3rd party services outside of the hexagon.
The chairs still have to fit under the table – the ports of the adapters still have to match the ports on the domain objects.
Below is an example of a simple hexagonal diagram:
Business logic (aka the business domain) lives in the inner hexagon & should not leak out into the outer hexagon – that is to say the inner hexagon should have no notion of the external / 3rd party services outside of the hexagon – the adapter code acts the go between or middleman for messages into & out of the hexagon.
The outer hexagon is for the adapter code which enables the code in the inner hexagon to talk to the external / 3rd party services outside of the hexagon.
The advantage of this is that it is possible change the external / 3rd party services without impacting the business logic. The business logic is independent from the implementation. For example, you could have a web app which you want to market as a desktop app – with hexagonal architecture, this wouldn’t be a problem as it would only be the implementation which requires changing.
The image below shows the structure of a “typical” web application & the relationships between the classes & interfaces:
I’m going to try and use a simple example of a user logging in to a restricted area of a website to demonstrate flow through the hexagon…
Class A = http LogIn Adapter
Class B = LogIn.java
Class C = Oracle Data Access Adapter
Interface 1 = LogIn
Interface 2 = Data Access
Humour me for a minute while I try & explain interfaces (for my benefit)… An interface is an abstraction, not a tangible thing. We talk of classes implementing interfaces. An interesting metaphor given to me was that of shopping in Argos:
You go into Argos & order your 5 piece towel set. You go to the counter to collect your towels – you ask one of the members of staff (Dave, Linda, Sheila) in particular to get you your towels. The members of staff are implementations of staff (classes). The term “staff” is an abstraction (interface). It is either Dave, Linda or Sheila (whoever is responsible for homeware goods) who fetches your towels, not the staff.
The (http) request containing a (valid) username & password is made from the users browser to the http LogIn Adapter in the adapter layer. http LogIn Adapter can only be used for requests are http.
The http LogIn adapter is an implementation of the LogIn interface & passes username & password combo to LogIn.java without passing any knowledge of the technology of the initial request (in fact, there is no concept of request beyond the adapter). There are 2 sides to Adapters: technology facing & business logic facing – it is here where the knowledge of the technology is removed as the username & password combo is passed into the business logic.
From LogIn.java, the username & password combo is passed onto Data Access interface where it is in turn passed onto the business-facing side of the Oracle Data Access Adapter in the adapter layer.
The technology-facing side of the Oracle Data Access Adapter finally passes on the username & password to the Oracle DB, where the DB says yep, the login credentials are valid & a return message is sent back through the hexagon to the presentation layer.
If we want to use automation rather than a human to send the same HTTP request, we can still use the same http LogIn Adapter as the implementation is the same. Similarly, we can write tests against a ‘fake’ DB (or mock it out) to ensure consistent data. As this a different implementation, we need to create a test Class D (Oracle Data Access Adapter Mock) which knows about the new implementation which implements Data Access interface the same as Oracle Data Access Adapter:
Now we can also swap out the 3rd party / external services. In the example below, the HTTP request is swapped for an FTP request & the Oracle DB is swapped for a MySQL DB. This is achieved by adding adapters & their awareness of the technology & without impacting the business logic:
This has been a brief introduction into my brain & how it is working out hexagonal architecture. Please feel free to challenge my thinking – this is all really new to me!
In the next post, I look at the test strategy for hexagonal architecture & how integration tests are seen as trouble & needed to be dealt with!