the use of symmetry in the hexagonal approach
*) Note - these are some preliminary notes, I am attempting to document an implementation of the Hexagonal Architecture as a design pattern.
When building a system using hexagonal architecture, you want to acheive symmetry of the various external subsystems (transformers). Lets suppose, as in most cases, that you have three external subsystems (UI, Network, and DataAccess). In order to acheive symmetry, need to do three things.
1) Create a public class that acts as a front end to the subsystem. Alistair calls these “Transformers”, so I will stick with his terminology. They are also similar to Martin Fowler’s “Mapper” pattern. They are also Facades in the GOF literature.
2) Unify the interfaces of all three transforms. In other words create an abstract class (or interface) called Transformer, and then have the UITransform, DataAccessTransform, and NetworkTransform implement it. You may need a ClientNetworkTransform and a ServerNetworkTransform. I also add a TestTransform that helps to refine the interface contract, and that can stand in place of the database during the Network tests. One unusual aspect of this design is that, because it is symmetrical, each transform should be able to provide and consume services. This capability enables us to write distributed applications that support Domain Events. A Domain Event is an event at the domain level (ie, a new Account was created), as opposed to a user interface event (like a click). Your transformer class would look something like this.
public interface Transform
{
//this method would be called when another transform has requested a service.
ServiceResult ProvideService(ServiceRequest request);
//the transform raises this event when it needs to consume an event.
//you want this to be asynchronous.
event ServiceRequested(ServiceRequest request, ServiceRequestResultDelegate delegate);
}
3) At this point we have symmetrical interfaces at compile time. If you are trying to implement domain events, you should go a step farther. You need to acheive symmetry at runtime. This means that you should have a single test suite that runs and passes against all three transforms. This means you have an interface contract that states (for example) that if the CreateAccount service request is received, it should return an Account object along with the ServiceResult. If your database AND your ui transforms implement this contract then you will know that your ui is ready to handle events from the outside world. One of the wonderful things about this design is that you can test the subsystems independantly from one another. And you need not wait for the dba’s to finish before you start testing
. Its very important to have these tests because the interface of the Transform tells you nothing about what types of ServiceRequest can be received, to how they should be processed.
Thats the basics of implementing Transforms in the Hexagonal Architecture. In order to build a working system you still need another piece because (and this is extremely important) YOUR TRANSFORMS DO NOT KNOW ABOUT EACHOTHER. That’s very important. If you ever add static references from one Transform to another, you are back in the world of layered architecture, and all the benefits of this approach are gone.
Ill talk about the communication between the transforms in my next post.