I had an ‘Ah ha!’ moment just over a year ago when I attended a Greg Young’s CQRS and Event sourcing course with skillsmatter. The ‘Ah ha’ wasn’t about CQRS, or even Event sourcing, it was about how Greg structured his code to work with messages. This approach can have far reaching effects on your software, making it simpler, easier to test and much more flexible. It can even remove the need for an AOP framework (amongst other things).
The basic idea
Rather than tightly couple method calls together by directly calling them, send a ‘message’ and let everyone who needs to react respond to it. This is essentially a pub/sub structure.
We all know tight coupling is bad for maintainability but did you know that coupling occurs not just in the classes dependencies, but also in its integrations. For example, lets assume you are modeling a booking system for a visitor centre. The current system has the following classes, ‘Scheduler’, ‘Management’, ‘Sales’ and ‘Finance’. The current (very nieve) process is:
- ‘Scheduler’ class receives a new booking
- ‘Scheduler’ class informs a ‘Management’ class of the booking
- The ‘Management’ class informs a ‘Sales’ system so it can update their statistics and the ‘Finance’ system so it can send an invoice
Now what happens if we need to add a ‘catering’ class? In order to inform the catering object of a new booking we would need to alter at least one of the classes listed above. In fact each time we add a new class that needs to do something as a result of a booking we are going to have to add a new dependency to one of the classes and a new interaction (which isn’t related to its core function). Now there are lots of ways to straighten out this system but I want to illustrate how we could do it via an internal message system.
Messaging to the rescue
To make this work we need to add a central system to handle and route messages. We will call this central system a message bus. Each of the classes listed above would register their interest in specific types of messages, with the bus. Now all that’s remaining is for the ‘Scheduler’ in this case to publish a ‘Booking Created’ message. Now each of the classes listen in for the ‘Booking Created’ message and can do their thing. Now when we add a new class into the mix we don’t need to change any of the classes, we just register an interest in the messages we are interested in.
Cross cutting concerns
It doesn’t take long before you find yourself adding cross cutting concerns like logging, security, exception handling and health monitoring to name a few of the top of my head. We could add a whole heavyweight AOP framework to weave itself into our system with all the complexity that brings. However, a much simpler approach is to just to take advantage of the message bus. Since our messages all go via the bus and are effectively the basis of all the method calls, we can simply build in our cross cutting concerns into the bus. More about this in a later post.
Using messages to drive our system makes it much easier to test our system. Given a standard AAA (Arrange, Act, Assert) or GWT (Given, When, Then) approach we can setup our state by simply sending in a series of messages. We can then carry out the action we want to test, again by sending in a message and we can then assert based on the messages that come out. The great thing here is that the tests do not rely on the implementation so you can freely change the way your system works without breaking or invalidating your tests. More about this in a later post.
I hope by now you are beginning to see how flexible this system is. We can add new classes in and take old ones away without having to change existing objects, does that sound familiar? How about the SOLID principles? Each class is now responsible for just a single things. Not only that but your classes will be open for extensibility but closed to change. In fact when you think about it your classes will naturally follow all the SOLID principles when structured this way.
I hope you can see how internal messaging can actually bring some significant benefits to any moderately complex system. In later posts I will focus in on how you can actually do some of these things with code example and everything! Stay tuned.