Shared Language of Event Microschemas

Yurii Rashkovskii
Eventsourcing Publications
3 min readJun 7, 2016

In my earlier event sourcing applications, I found myself doing a lot of repetitive work. Namely, creating mundane events that serve the same purpose for different entities. Imagine describing a domain with many types of entities (project, product, group, person, milestone, issue, etc.) where most of these entities would have a property called name. Initially, I started with something like ProjectNameChanged, ProductNameChanged, GroupNameChanged, PersonNameChanged, MilestoneNameChanged… you get it. Not only it felt mundane, it felt silly. The more shared properties you would need, the sillier it felt.

So my natural reaction was to eliminate as much repetition as possible. I thought “what if events could be made polymorphic?” — and collapsed all the events into one NameChanged event. Interestingly enough, I didn’t even need to change anything in its layout. It already had a ID referring to an <Entity>Created event. It already had a new name. So all I really changed was the convention to be able to refer to just about any event instead of one type.

Suddenly, I had a very clean project but my models were starting to have some code duplication, doing the same kind of queries to retrieve their names or other shared bits. That had to go and this is how domain protocols were brought into existence. In a nutshell, the idea is simple: as long as we know model’s ID (by convention, the ID of its “creation” event), the code that would query those polymorphic events is 100% reusable. So I defined a Model interface that provides that ID. Now, I can define protocols that can rely on that property. By using Java’s ability to supply default implementation I can get these “traits” to be included in all relevant models. If I need a model to have a name, I simply add this to the definition:

public class User implements NameProtocol { … }

Voila! Now User implements everything NameProtocol defines so I can retrieve user’s name via the name() method.

This approach worked really well for me. But the more I continued to develop some my of projects, the more repetition I saw (again!). Different independent components started having their own copies of NameChanged and NameProtocol (as well as other events and protocols). That was no good at all! Especially if they were subtly different…

So, a natural step was to consider extracting some of the most common elements to be reused across different components and, perhaps, projects. This way applications and libraries created by different people can form shared expectations, and a shared language.

What really excites me about this is that since we’re only talking about events and protocols (and not models), we are not imposing “closed” schemas onto other users. They can (and should!) cherry-pick parts they need. Imagine if we had a common language for identity management (which I am working on right now, by the way, soon to be previewed on rfc.eventsourcing.com), it would have been really bad if made all schema decisions for everybody (say, user should have a name and be identified by an email, password should be stored as a bcrypt hash, entitlements should be identified by name, etc.)

Instead, by picking appropriate events and injecting respective protocols, other developers can build representations that fit their needs best. As a small example, one can create an entitlement with EntitlementCreated and name it using NameChanged. Now, the software that implements identity lifecycle management, doesn’t need to know about NameChanged, it simply operates with entitlements. A web interface for these, though, can be made aware of the applicability of NameChanged to EntitlementCreated and use these names to render human-readable entitlements. Want to “attach” some kind of resource to entitlement, or do you think entitlements can be given not just to users or roles? Create your own event that represents this.

This way you can have a shared, mutually intelligible, interoperable language with extensions that suit your needs best.

I am currently working on defining the most common language, as well as identity lifecycle management (user management). I want to start working on a data lineage language soon (that stuff is interesting), too.

What other languages do you think should be shared?

--

--

Yurii Rashkovskii
Eventsourcing Publications

Tech entrepreneur, open source developer. Amateur runner, skier, cyclist, sailor.