Development, Microservice, Application Architecture, API

The 4 Event-Driven Architectures

The phrase "event-driven architecture" has many meanings, and different people have different ideas of what it means to them. That being said there are four well-established architectures that help shape most event-driven architectures.

The most common oneis the event notification architecture. Even if you don't recognize the name, you've likely used it in your code before. A less common architecture is event-carried state transfer, it is similar to event notification but increases performance at the cost of eventual consistency. Finally, there are event sourcing and CQRS which are fundamentally different ways of looking at your service. Unlike the previous architectures, they rely upon the events as the source of truth and embrace eventual consistency.

Event Notification

Event Notification is a pattern in which a system sends an event in order to notify other systems of a change. A defining feature of this architecture is that the system doesn't expect a response from the event at all. There should be a separation between the logic that sends the event and any logic that get triggered by it. This pattern is handy because it makes a lower level of coupling simple. That being said, it can be problematic if there is a logical flow that runs over various event notifications. The problem is that it can be hard to see such a flow as it's not as explicit as traditional architectures. Because it's straightforward, there is a danger that you make a decoupled system with event notification without realizing that you're losing sight of that big picture. This pattern is very useful but it is good to be aware of the trap.

Pros

  • Straightforward to understand
  • Keeps things consistant
  • Easy to decouple systems

Cons

  • Lots of network calls
  • Chains of events not easy to spot

Event-carried State Transfer

The event-carried state transfer pattern is very similar to the event notification pattern. It often shows up when you're looking for less communication between systems. This is achieved by duplicating data across multiple systems. An example is a user system emits an event when a user is updated, and any system which has user data stored will update their databases with the new user data. This is done so these systems never need to communicate with the user system to retrieve information about users.

It may seem like this is a great solution, but there are some downsides. A big one downside is there is an increase in complexity on the event consumers because they have to sort out the state changes. You now also have to worry about data consistency because this pattern relies on eventual consistency. There is also an increase in database sizes which isn't so much a problem these days unless you're dealing with massive amounts of data.

Pros

  • Easy to decouple systems
  • Reduced number of network calls

Cons

  • Consumer complexity handling state
  • Eventual consistency
  • Duplicated data

Event Sourcing

Event Sourcing is my personal favorite architecture out of the four. This pattern is less commonly used but the main idea of event sourcing all changes to a systems state is recorded as an event. You should be able to recreate the current state by replaying all previous events. This is a fundamentally different way of looking at a system because the event store is the source of truth, not the database. A commonly used example for describing this pattern is a version control system like git where each commit is an event.

Now that we've broken down what event sourcing is let's dive into a couple benefits. A highly touted benefit is that event sourcing lends itself well to any sort of auditing system as you know exact what causes each state change. It also allows you to make branches just like version control, which can be useful for testing bugs. There are some downsides to event sourcing, replaying events can become problematic when you're communicating with external systems. Dealing with changes in the schema over time as a system changes can be challenging. It is also not a widely known or used technique so it can add lots of complexity if not implemented correctly.

Pros

  • Reproducibility makes debugging easy
  • Data analysis of Event Streams
  • Auditing is built in

Cons

  • Takes getting used to
  • Much less support

CQRS

CQRS stands for Command Query Responsibility Segregation, and it is an extension of event sourcing. It separates the data structures for reading and writing data to a system. The reason to use CQRS is that in complicated systems a single model to handle both reads and writes can get very complicated, so by separating them it will simplify the system as a whole. Separating the reading and writing portions of the system can be very useful if it has lots of reads and very few writes. They can scale independently of each other. The main downside of using CQRS is that having separate models can add additional complexity if misused or in a wrong situation.

Pros

  • Separation of concerns
  • Data analysis of Event Streams
  • Auditing is built in
  • Reproducibility makes debugging easy

Cons

  • Takes getting used to
  • More complicated

Conclusion

There are many definitions of an event-driven architecture, but they all have parts of these four architectures. Each of them has their place, and when used properly can make a system run smoothly. With the trend of microservice continuing to pick up steam these architectures will become more popular and widely used. Whether it's adding event notifications to an existing system or making complex systems with event sourcing or CQRS, it is good to understand the basics of these architectures and have them in your toolbox of skills.

Author image

About Ryan McCue

Hi, my name is Ryan! I am a Software Developer with experience in many web frameworks and libraries including NodeJS, Django, Golang, and Laravel.