Service-Oriented, Event-Driven Part 1: Events
The real-world does not follow a linear, step-by-step process in order for things to occur. We may rationalize and tell ourselves that things happen in sequence and that ‘c’ won’t happen before ‘b’. We model our systems this way and we code this way because we view the world through this lens. I am beginning to fully believe that we must shatter this lens, because it colors the world with a perspective that doesn’t fit.
The real-world is disorderly, it is chaotic, and it is made up events – notable changes in state – that we must react to. The traffic light turns green, so you go, except the car in front of us isn’t going so now you can’t go. You order coffee and wait, and then the guy behind you gets his coffee first with yours ready a moment later.
Integrating systems using the lens of events is key to success, especially when the systems you are integrating are not yours or they belong to an entire other organization. This is where a firm understanding of the information being exchanged as well as when it will be exchanged becomes key.
Udi Dahan posted an article titled “Don’t Delete – Just Don’t” a few weeks back. In that article Udi explores soft deletes versus hard deletes, but he also raises another interesting thought that I’d like to build on. Our systems maintain the state of records over time. That state can be things like “entered”, “active”, “inactive”, “accepted”, “denied”, and whatever the business case may be. As I have already described events as notable changes in state, so what if we start looking at our systems records and the notable changes in state, what would we see?
Dru Sellers frames this in “Events Are Awesome” where he writes:
“I have also started to think about what it would mean to develop a system ‘event first’, and then you can look at what needs to be done when these events happen. It builds completely different systems, based on some initial drawings.”
Over the last few weeks I have been thinking about the same thing. So let’s hop on the example bus and see where it takes us.
Suppose we run a pizza delivery business and we’re going to automate what has been a manual process. At a high-level, we could see a few processes we need: Customers should be able to place orders, the kitchen needs to be able to be notified of orders so they can cook them, the delivery supervisor needs to know where orders are going so drivers can be scheduled, and the store manager needs to know about the volume of orders so that the financials can be reviewed. Skipping through the normal business analysis that needs to take place, we’ll say that we end up with four systems, each with a distinct job.
- The order system processes, validates, and accepts pizza orders from customers.
- The kitchen management system accepts orders, verifies stock levels, and notifies the cooks so the order can be prepared.
- The delivery scheduling system accepts orders, determines the route, and schedules a driver to deliver the order.
- The financial system accepts orders and records details about the underlying transaction amounts.
If we examine the order system using the events lens we can come up with some notable events: “Customer Submitted Order”, “Order Validated”, “Order Accepted”. With each one of these events a notable change in state has occurred and the information about that order should be communicated. For example, the delivery scheduling system might want to know about orders when they are validated because it takes longer to schedule a driver, whereas the kitchen management system might not want to know about orders until they are accepted so that ingredients are not used too soon in the process.
You may argue that this is not much different than procedural thinking. We could just code something to the effect of:
if (order.status == validated) {SendOrderToDeliverySystem(order);}
While that one line of code may be the simplest thing that could possibly work, what have we done? In essence, we have now coupled our order system to the delivery system. And this is where procedural thought begins to break down because that line of code is so specific that when we need to change it, the change has an effect that we may not fully understand especially because over time code becomes more complex as systems are expected to do more.
Consider the case where now the Kitchen System wants to know about orders when they are validated instead of accepted. We now have to refactor our one liner to something like:
if (order.status == validated)
{
SendOrderToDeliverySystem(order);
SendOrderToKitchenSystem(order);
}
Now consider if we used the .NET Framework’s notion of events:
public delegate void OrderValidatedEventHandler(PizzaOrder order);
public event OrderValidatedEventHandler OrderValidated;…{ //more code and curly braces }
if (order.status == validated && OrderValidated != null) {OrderValidated(order);}
If all of our systems were implemented as components with references to each other we could hook onto these events and reduce our codebase. But even then we still have a problem – coupling. Using direct references is a form of coupling that ties those components together. We can use Dependency Injection to reduce that, but then we still have the question to answer – what if each of our 4 systems comes from a different vendor?
In Part 2, we will discuss autonomous services and why we want to reduce coupling.
Comments are closed.

