Plan Ahead to Maintain Compatibility in Event-Based Architectures

An event-based architecture is great for decoupling services, but it can be tricky to maintain that decoupling when you inevitably need to make changes to existing event definitions. You can ease this pain by planning for changes from the start.

Event Versioning

No matter how meticulously you plan out the events in your system, they will eventually need to change. Part of the advantage of using events is that publishers and subscribers (often operated by completely independent teams) can adapt to change at their own pace. This means that publishers can’t just change the definition of an event in a way that would also require changes by its subscribers.

One simple solution is to define a new event whenever a change is needed. This could be an event that incorporates a version in its name (like “my-event-v2”) or an event with some kind of version field in its payload.

But doing this for every change would cause an explosion in the number of events flying around. Just because you defined version 2 of an event doesn’t mean you can stop sending version 1. Subscribers to version 1 may not have updated to handle version 2 yet.

To tame this chaos, it is useful to allow some backward-compatible changes. What this looks like depends on whether you’re a publisher or subscriber.

Publishers of Single-Origin Events

A single-origin event is one exclusively sent by a single service. That service has full control of the event semantics.

All publishers should maintain backward compatibility. This means avoiding changing any event definition that would require coordination with subscribers.

Consider how a change will impact:

  • the shape of the event (the names and types of fields in the payload)
  • the intention of an individual field (even if its name and type remain the same)
  • conditions that trigger the event

If a change would affect any of these things, define a new event (or event version) rather than changing the event. Additive changes should be okay, as long as subscribers are prepared in advance. Depending on your data models, additive changes could include adding a new field, adding another case to an enum, etc.

Publishers of Multi-Origin Events

A multi-origin event may be sent by any number of publishers. All publishers must agree on the event semantics.

These are often the hardest to change simply due to the number of affected parties. It’s probably best to just define a new version of the event. But you might get away with limited additive changes, like adding an optional property. The changes you can make are more limited because you have to consider not just subscribers but also all the other publishers.

Subscribers

Subscribers should maintain forward compatibility. They can prepare in advance to accept certain types of changes without having to coordinate with event publishers. Generally, subscribers can ignore anything they weren’t expecting to receive — those additive changes like extra fields, extra enum cases, etc.

Even if you have reliable event definitions, runtime validation will ensure that you received what you expected and filter out anything you didn’t. Doing all this in a validation layer that applies to all events will save individual event handlers from dealing with it.

Anticipating Change

Change is hard to predict! But known unknowns are easier to handle when you’re prepared.

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *