How to plan smarter for event-driven architecture design
Event-driven architectures provide the benefits of flexibility and scalability. Instead of binding two processes together over a predefined and synchronous request/response connection to do work, in an event-driven architecture, a particular process emits messages to a message broker that are consumed asynchronously by other interested processes. Processes can start or stop consuming messages from a broker on demand. And, any number of processes can listen to a given "inbox" on the message broker for messages. This makes event-driven architectures flexible and scalable.
That's the good news. However, there's a bit of caution to be had. An architect will often go through the effort to clearly specify the broker and the "inboxes" used by the message publishers and consumers but fail to specify the events of the system and their corresponding messages in a way that is meaningful to the purpose of the system. In other words, the architect will make it so that messages can traverse the application well, but the actual messages moving to and fro lack the information that the application needs to do its work effectively.
Identifying events and describing their corresponding messages well are critical aspects of enterprise application architecture design. However, it's not easy. Defining events and messages in a meaningful way requires understanding the purpose of an application at a very conceptual level and then mapping the conceptual framework onto the reality of a system architecture in a very concrete manner.
Allow me to elaborate. But first, you should have some understanding of asynchronous programming and event-driven application architecture. If you need to brush up on the topic, here are few articles that provide the background information you need:
- Event-driven architecture: Understanding the essential benefits
- Architectural messaging patterns: an illustrated guide
- Event-driven architecture for a hybrid cloud blueprint
Identifying events: Moving beyond CRUD
Using events to facilitate communication between processes in a system has been around for a long time. User interface (UI) programmers have been responding to onKeyDown and onKeyUp events since operating systems first supported a keyboard. The onMouseClick, onMouseMove, and button.click events soon followed as graphical user interfaces (GUI) became a standard way to interact with applications running on the web. Events are also common in databases. It's not unusual for a database developer to write a trigger in response to INSERT, UPDATE, or DELETE events, as shown in Listing 1 below.
CREATE TRIGGER production.trg_product_audit
AFTER INSERT, DELETE
SET NOCOUNT ON;
INSERT INTO production.product_audits(
Listing 1: An example of a database trigger that responds to the INSERT, UPDATE, or DELETE events.
While events have been around for a while, their scope has often been limited to those generated by the operating system or a database. As such, the information in an event message was limited. A keyboard event sends out a message that reports the key being pressed. A mouse event sends out messages describing the mouse's location on the screen along with the mouse button being clicked. A database event sends out a message that describes the data being inserted, updated, or deleted.
It's pretty standard fare that doesn't require a lot of thinking on the part of the architect. The operating system, browser, and database are in charge of the content of the messages that get generated for an event. However, when it comes to creating an event-driven architecture, things get tricky because not only is the architect in charge of defining the events an application will raise but also the content of the message that will be emitted when a particular event occurs. This is a big kettle of fish that goes beyond capturing UI input events and data updates. It concerns the very nature of the application itself.
Thus, defining the events and associated messages that a system will generate is critical in application architecture design. It's not something you make up as you go along. Rather, it's both an art and a science that requires forethought and the skill to model application architecture in a very abstract manner.
Let's look at a case in point: transportation systems managing municipal vehicles.
A case in point
Daniel James is a principal software engineer at a company that creates municipal transportation systems. He's a member of a team that focuses on creating systems for public transportation vehicles, particularly the buses that carry passengers about a city's streets.
What makes Daniel's activities interesting at the architectural design level is that he works with a wide variety of situations relevant to municipal transportation. One of the systems that Daniel's company created makes audio announcements when a bus stops. For example, when a bus stops at the corner of Main Street and Sixth Street, a loudspeaker on the bus announces, "Main and 6th Street. Next stop is Union Station."
In addition to bus stop announcements, the system makes public service announcements (PSAs). It can also report interesting landmarks nearby. This may seem like a trivial set of application features, but they're not. There's a lot of data that needs to be captured, correlated, and managed just to blurt out bus stop information.
For the system to work, it needs access to GPS information. Also, it needs to know when the bus is stopped and which announcements to make. This is all determined asynchronously at runtime. And, it all depends on a variety of messages emitted from a variety of devices.
GPS messages report the bus' geospatial location. The bus door has a sensor that emits a message to a computer on the bus when the door opens. This indicates that the bus has stopped.
[ You might also enjoy An Architect's Guide to GPS and GPS Data Formats. ]
That same onboard computer will figure out which announcements need to be made at a given stop. These announcements are represented as strings of text. The message containing the announcements is sent to an onboard text-to-speech device that converts text into audio. This text-to-speech device will broadcast the announcements to the passengers on the bus.
In addition to coordinating the runtime announcements, the system sends messages back to a controller service on the server side that monitors the activities of all the buses. The server-side code also sends messages to all the buses when phrases need to be added or removed from the list of announcements stored on each bus. (See Figure 1 below.)
What makes Daniel's systems relevant to this article is that at a conceptual level, this architectural model covers a broad information landscape, no pun intended. It's a cornucopia of data, and Daniel needs to make sense of it all. This is where event identification and definition come into play. Determining the events that need to be raised within the system and then defining what those events actually look like requires thought and analysis, all of which Daniel discussed in a conversation with Enable Architect.
Planning is essential
A critical aspect of the architectural design process in an event-driven application is actually taking the time to determine and describe the events a system needs to meet its requirements.
Daniel says, "if you don't take the time to plan upfront and you don't collect enough information in your events, and then you need to later collect something new, you can introduce a number of problems."
Planning is essential. Take the case of the bus announcement system. While it might seem trivially obvious, a critical event that needs to be generated in the bus announcement system is a "bus has stopped" event. The system can't announce a bus stop unless it knows that the bus has indeed stopped. Thus, the need for a "busStopped" event as well as a "busStarted" are essential to the system. This raises two questions: How is that event described, and secondly, how is that event raised?
In terms of event description, there is a good argument to be made that including nothing more than a timestamp in the event description will be enough. (See Listing 2 below.)
Listing 2: A simple event definition
Yet, the event definition above in Listing 2 assumes that the "busStopped" event is relevant only to the bus internally. That's a big assumption. What if the event needs to be shared systemwide with a controller that is monitoring all the buses? In this case, not only is the time that the bus stopped essential but so is knowing which bus stopped and its location when it stopped. In this case, the event might best be described as follows:
Listing 3: Describing an event in term terms of geographic location
Either of the event definitions shown above might be useful. But as you can imagine, each comes with tradeoffs that need to be clearly understood. Making a decision about which one to use requires thinking and analysis that is typically done when planning a system, even before a data model is created, even before a line of code is written, even before a network diagram is created.
Once events are identified and defined, you need to figure out how to raise them. Again, it might seem trivial, but it's not.
Going back to the announcements system, how do you actually know the bus has stopped? Is there an "eye-in-the-sky" aerial device that is always observing the bus? Do you monitor the events in the bus's onboard diagnostics (OBD) system to figure out some sort of "bus is stopped" state? Do you create a special sensor for the bus door that reports when the door is open and closed, thus inferring that an open door indicates that the bus has stopped? (FYI: monitoring the state of the bus door is what Daniel's system does.)
Any of the solutions might work; some might not. As with defining the event, determining how to implement its generation depends on careful analysis and planning.
[ A free guide from Red Hat: The automation architect's handbook ]
Putting it all together
In the good old days of enterprise architecture, many, if not most, events were predefined. Architects pretty much worked with what they were given. But, as the internet grew, so did the proliferation of event-driven architectures, particularly for those systems intended for previously inaccessible business domains.
Whereas in the past, it took a lot of proprietary technology and know-how to create an application intended for something as special as a municipal transportation system, today, companies can stitch together open source software and publicly available hardware to create clever solutions that address the most perplexing problems. As a result, there are a lot of opportunities out there. But, these opportunities come with an added expense.
Modern, distributed enterprise applications have moved way beyond working within the confines of mouse-click and keystroke events. These architectures depend on a thoughtful, planned approach to determining and defining events. Assuming otherwise is perilous.
The long and the short of it is that you can't improvise your way into an event-driven architecture. Proper planning is essential. Determining and defining events is a critical element in a well-designed event-driven architecture.
Navigate the shifting technology landscape. Read An architect's guide to multicloud infrastructure.