IFRCGo / cbs

Red Cross: Community-Based Surveillance
https://cbsrc.org/
Other
101 stars 110 forks source link

Properties on event - all or only those you need? #232

Closed karolikl closed 6 years ago

karolikl commented 7 years ago

From a discussion in PR #231:

When processing events in a bounded context, we might only need a subset of the properties that the event has. What is best practice in this case?

1) Create an event within your bounded context with all properties (leaving all events across bounded contexts identical) 2) Create an event within your bounded with only the properties you need.

roarfred commented 7 years ago

Looking forward to some insight on this! I thought these event classes might be something that came distributed, as classes in an assembly, but that would make dependencies between the services. We could at any time just look at the spec, and create our classes accordingly, but that's also just a (more manual) dependency. @einari told me there are some ways to implement versioning, which I guess is the solution here.

I am unable to see if creating classes with a full set or just a subset of properties will make any change. The proposed solution should solve the problem of changing event definitions

einari commented 7 years ago

The question has multiple concerns:

  1. Properties - size / weight of events
  2. Versioning of events
  3. Dealing with events between bounded contexts

Properties Events are to be considered atomic operations - representing the actual state changes of your system - in this case; within the bounded context. The state change are often governed by the aggregate root itself, as it is modelling the actual transactional boundaries. The things that naturally belong together as a state change would go together.

Versioning doLittle has a concept of event migration - it is being revised at the moment as we're introducing a schema system for events and versions. You can look at the legacy on how these were written here - keep in mind this is from the Specs of the project, so they're not very real. Versioning of events is something that you typically only need to do if they change characteristics. For systems being developed you'll see that its not always about versioning an event, but often you'll find yourself introduce new events rather than version it. The reason for this is that you're really bringing in new knowledge to the domain - not necessarily changing knowledge. This often means a new state change.

Going between bounded contexts doLittle will introduce a concept of a mediator - you can see it mentioned in this article. The purpose of it is to let two bounded contexts be blissfully unaware of each other and have this third party act similar as an Anti Corruption Layer between them. ACLs are often referred to in the context of legacy systems, but we consider them conceptually as important between any systems and even bounded contexts. In doLittles spirit, we will most likely make this very much a convention based thing. We've been discussing just declaratively setting up the relationships between the bounded contexts - typically a "this bounded context is interested in X,Y,Z events from this other bounded context". By default it would find the properties that match and integrate them together like this. That means that every bounded context can create their own representation of exactly what they need, without worrying about including stuff they don't really need. One learning that was really cool to get from the codeathon was that most teams identified external events as a thing and put it in a namespace of its own. We've discussing talking about formalising this one further and either introduce a special type of event for this, or look at metadata produced from the mediator. Once you've marked your event as an external event, your bounded context would not be allowed to produce it. With a mediator in place, we could also implicitly have this metadata.

With mediators you would then be able to move bounded contexts forward, combining it with migration you would be able to move systems forward and provide compatibility. From all the metadata given in the mediator setup, the system can actually know which events to support.

Part of the system is also the governance of event stores and possibly migration of these, to get rid of old version definitions of events and not having to go through migrations for a playback. A self optimisation if you will. Something we're also discussing on solving in the future.

So in conclusion; the events don't have to look the same across bounded contexts. Let every bounded context be as naive as possible on this - pull only the things you need into the event, even more so for the external ones.