Ashraf Mageed bio photo

Ashraf Mageed

EventSourcing, DDD and Microservices

In Event Sourcing, events have a considerably longer active life within an application. Entire event streams, from the oldest event captured to the newest, are replayed constantly to reconstruct the state of an application. 

This means that at any point in time, we must be able to process all the events in the event stream, which would be trivial if the events’ schemas never changed. 

However, as our understanding of the domain deepens or business requirements change, we need to alter the events accordingly. Leading to a balancing act of not stifling evolvability whilst simultaneously ensuring the event streams’ replayability remains intact. 

How do we achieve this?

By avoiding the following:

  • renaming properties
  • using complex types
  • changing semantic meaning

Note: this post is only relevant for systems already in production. Before that stage, you can simply delete event streams.

Photo by James Orr on Unsplash

Renaming properties

Avoid the urge to rename a property in your events. I have encountered this a few times, and it mainly, in my case, came off the back of realising that there are discrepancies in the ubiquitous language — but there could be other reasons as trivial as simply making a mistake with the naming or a misspelling.

Renaming a property is a breaking change that should be avoided if possible. If you can live with the incorrect name, then just keep it. Alternatively, you could change the property name and use upcasters to upgrade older events — I will discuss this in more detail in my next post. 

Another option would be to add a new property with the correct name that has a copy of the value. And the old property is just never used.

public class OldEvent
{
    public string Name {get; set;}
    public string Surname {get; set;}
}

public class NewEvent
{
    public string Name {get; set;}
    public string FirstName {get; set;}
    public string Surname {get; set;}
}

However, duplicating properties this way can lead to a proliferation of properties bloating your events. Upcacters provide a better option.

Using complex types

While using complex types in your events may be tempting, this comes at a price. Complex types here can be one of two: dedicated types for event use only and value objects reused from the domain when using event sourcing with DDD.

Event-specific complex types: this may introduce accidental breaking changes. It could be a rename all using a refactoring tool or a junior developer not understanding the purpose of those types and the consequences of changing them. I have seen types like these created with an accompanying warning not to alter them as they are part of the event contract.

Value Objects: adding value objects to the events should be avoided as this sets them in stone. That stifles your ability to change those value objects in response to changes in the domain or requirements.

Changing semantic meaning

Semantic meaning should never change between different versions of an event as there’s no way for consumers to detect such changes, and that could lead to hard-to-trace bugs. 

One example is changing currency. Say you were publishing events with an implicit EUR price. But at some point decided that you needed to publish them in YEN instead. There’s no way downstream systems can detect this change or understand how to correct their interpretation of this data.

I have seen a few places where this is tackled by adding a new property to give the change some context; in the case mentioned above, that would be a currency field. However, that does not solve the problem in all cases. 

If you control the consuming services, you could —alter them simultaneously and redeploy them all together to ensure they process the new prices correctly. There are risks in relying on lock-step deployment, but that’s a discussion for another day. 

In all other cases, you can’t assume services will upgrade at the same time - or any time soon.

How do you version events, then?

In my next post, I will discuss how to deal with the above scenarios and techniques in dealing with event versioning.