Why I Use Events
Events are a relatively simple, but very powerful idea. At its simplest, an event is a statement that something has happened. Usually, it includes some data that further defines what has taken place. Events show up very naturally when doing GUI programming, either for the desktop (think WinForms) or web (JavaScript).
However, that’s not the use case I want to discuss today. Instead, I want to consider the use of events for decoupling business logic.
Boundaries
Lack of boundaries has to be one of the most common problems I see in software systems. Layered architecture has taken a hold in many systems, and often helps bound the UI and business logic (and sometimes too many other things beyond that). However, too often the business domain is seen as one big thing, with no serious effort made to look for and maintain explicit boundaries. Both DDD and SOA are pretty clear that we need to hunt for such boundaries, however.
The argument that tends to crop up next is that one part of the system will often need to know what’s going on in other parts. For example, it’s very well for a travel company to say they’ll bound sales, booking and their transport services into separate services or contexts. However, in reality, if a booking were to be cancelled at the last minute then the sales context should know about this so they can do a special last minute deal, and the transport services context also need to remove the passenger from its lists.
Clearly, the booking context is responsible for handling the cancellation. In a monolithic system, the cancellation logic would mark the booking as cancelled, and then go and handle the notification of the sales team and updating the passenger list. If we are series about boundaries, however, then this simply isn’t going to fly. So what can we do?
Publish Subscribe
We can resolve this problem using a popular messaging pattern, known as publish subscribe. First, we define a BookingCancelled event. Typically, I would just represent this as a simple class.
public class BookingCancelledEvent{
public int BookingID;public List Passengers;}
The booking context would mark the booking as cancelled and do anything that is directly related to bookings. It would then publish this event. Meanwhile, the sales and transport contexts would be subscribed to booking cancellation events. They receive the event, look at the data contained within it and take action as appropriate.
We have now managed to achieve a very loose coupling between the different parts of our business system. The only things that flow over boundaries are events. Should a new context be interested in knowing about cancellations, then it’s trivial to handle; the booking context needs no changes whatsoever, and the new context is just added as an extra subscriber.
It’s all in the past
The naming of events is of great importance. An event should always be in the past tense. This makes it absolutely clear that the event in question has already taken place. There’s nothing a receiver can do to change that it happened; they can only act upon that new reality.
Events should also have a single source. It should never be possible for more than one context to publish the same type of event. This maps down to a deeper principle: every piece of information in your system should have a single owner that is responsible for it. It’s fine for other contexts to maintain their own local copies of the data, or at least the parts they are interested in – but there is only one single authority for it.
Implementation
There are many ways to implement events along with publish subscribe. For a small, single-process system then a relatively simple in-memory message bus or event aggregator isn’t a great deal of code. For larger systems, however, events come in to their own. Using an enterprise service bus – such as NServiceBus – enables a service to publish events and other services to subscribe to them. Such systems use store and forward, providing reliable and asynchronous message delivery.
Learn more
I consider events important, and thus they show up in many courses I’m involved with. Of note, in the C# Masterclass I work through building a simple in-process event aggregator. The Software Architecture course talks about events somewhat. They will also be a core topic in the forthcoming Hands On DDD and CQRS course, where we’ll consider events not only as a mechanism for decoupling, but also as a primary storage mechanism.
/Jonathan Worthington