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
Skicka en kommentar
Trevligt att du vill dela med dig av dina åsikter! Tänk på att hålla på "Netiketten" och använda vårdat språk.