What’s in an (event) name?
When Juliet asked Romeo “What’s in a Name?” she was trying to wish away family history—the inheritance, customs, and all the feuding baggage that came with being a Capulet. A name is an arbitrary, agreed-upon label, but it often points to a lineage of events.
To Juliet's credit, being able to let go of systemic baggage allows us to build a new future (and new software without the cruft of the old). But, just as she and Romeo learned, the conventions underpinning two different domains may mean they can't function together without additional work being done. Context is still king.
So, if cooler heads reign when talking about the state of events, what's to be done to help systems evolve and adapt to change? How do we build scalable, interoperable event-driven systems? How do we keep inertia and the cost of change down?
A common syntax between systems and events and behaviors becomes necessary. In this, the Semantic Web can help. And thus the CNCF CloudEvent spec was born. This relatively simple standard goes a long way toward facilitating event conversations between systems. Using open standards can help you scale.
------------------ Message -------------------
Concept Name: identity.user.domain-events
------------------- key ----------------------
Key: 17cce427-2027-4b54-9149-626df8109d00
------------------ headers -------------------
content-type: application/cloudevents+json; charset=UTF-8
------------------- value --------------------
{
"specversion" : "1.0",
"type" : "usersignedin",
"source" : "identity.user",
"id" : "b65d1b31-1f46-4fbe-a7b4-e93f8c96a449", //event uuid
"time" : "2018-04-05T03:56:24Z",
"datacontenttype" : "application/json",
“subject” : “17cce427-2027-4b54-9149-626df8109d00”, //source key
“traceparent”: “60080489-f508-4dfd-a96a-62cb8a382689”, //correlation key
"data" : {
... serialized JSON text ...
}
}
CNCF Structured Content Mode Example
For systems to interact they must have a shared language, roles, and conventions that allow them to work together (sidenote: this is the basis of “culture” in any system). Some conventions make eventing easier and less costly.
Eventing conventions
- Events reflect foundational facts about a system or its parts
- Events are units of notable change within the lifecycle of their parent
- Events are bounded in time—are past-tense and include an element or period of time (e.g.
Time
orStartedAt
andEndedAt
) - Events are atomic, immutable, and orderly
- Events have publishers and consumers as well as some kind of routing mechanism
When building new systems, we often act as well-meaning Juliets trying to share information across systems and break down old and unknown conventions to do so. Sometimes we get things mixed up. We’re human. It happens. We can iterate into being better.
Are you trying to wish away conventions or mutate definitions? Immutability is important—if you’re tempted to edit a past event, you’re likely doing it wrong, and now may be a good time to rethink your system design.
What should be included in an event? Atomicity helps us understand what does and doesn’t belong. Don’t include events inside events—define a new aggregate or entity instead. This can be helpful when modeling or modifying your system.
Events must be accurately ordered in time by the publishing system—make sure the clocks are synchronized and logging correctly. Make sure you can sort, partition, index, and filter. In the systems I work on we’ve standardized around ids, keys, time and date names, and formats.
Events are different from commands. In computing, if they haven't happened yet they aren't an event. People often confuse commands with events or event messages. Models can become conflated. Event-driven isn’t the same thing as event-sourced. Conflation contributes to unclear responsibilities, looping, or even deadlocked systems over time.
As you build, it’s important to document the conventions and constraints. Logic can be automated with certain assumptions taken as truth over time.
Points of interest
These could potentially help you build out your logical base:
- Track and correlate information both inside and across domains
- You can use CNCF extensions like traceparent for distributed tracing
- You can use IDs or keys to build relational sets
- Use events to understand behavior, telemetry, or state
- Events can store state, but they don’t have to—they can be stateless or stateful. Knowing when and why (e.g. read or write models; compaction or notification sets) can help you design better systems
- Events can be logged or ephemeral. Having conventions that determine when and where can help you adapt to changing requirements
- Events are units of flow. Little’s Law applies to them. You can build metrics and measure aspects of fitness through their aggregation
Since events express key pieces of a lifecycle this is something that can help you understand and code your domain.
Here’s an example of events and commands for a Meeting entity in the Meetings domain. Notice how some events are aggregated into a single domain event.
DOMAIN Meetings
EXTERNAL COMMAND GetScheduledMeetings()
EXTERNAL COMMAND ScheduleMeeting(Type, DateTime, Users)
INTERNAL COMMAND AddUsersToScheduledMeeting(ID, Users)
DOMAIN EVENT MeetingScheduled
EXTERNAL COMMAND AddUsersToMeeting(ID, Users)
INTERNAL EVENT UsersAddedToMeeting
DOMAIN EVENT MeetingAdjusted
INTERNAL EVENT DailyMeetingsJobRan
INTERNAL COMMAND StartMeeting()
DOMAIN EVENT MeetingOccurred
INTERNAL COMMAND GetTodaysMeetings()
INTERNAL EVENT DailyMeetingsReportRan
DOMAIN EVENT MeetingsCompacted
INTERNAL COMMAND DeleteMeeting()
DOMAIN EVENT MeetingTombstoned
Your system of record might only capture and publish the DOMAIN EVENTS in the example above. Like zooming in on a map, the frame, or level of abstraction, matters for what messages you choose to publish to your consumers.
As your system becomes more complex, structural evolution (of which versioning is part) of the domain may become important to record in your event store. For that to happen, these changes must be included in the lifecycle record. Like genetic code, adaptation may need to be codified and observed to be propagated in a complex system.
SYSTEM COMMAND RegisterDomain(Meetings)
SYSTEM EVENT system.DomainRegistered
SYSTEM COMMAND AddTopic(Meetings, root, v1.0)
SYSTEM EVENT system.TopicAdded
SYSTEM EVENT system.TopicSchemaRegistered
DOMAIN Meetings
EXTERNAL COMMAND GetScheduledMeetings()
EXTERNAL COMMAND ScheduleMeeting(Type, DateTime, Users)
DOMAIN EVENT root.MeetingScheduled
EXTERNAL COMMAND AddUsersToMeeting(ID, Users)
INTERNAL EVENT UsersAddedToMeeting
DOMAIN EVENT root.MeetingAdjusted
INTERNAL EVENT DailyMeetingsJobRan
INTERNAL COMMAND StartMeeting()
DOMAIN EVENT root.MeetingOccurred
INTERNAL COMMAND GetTodaysMeetings()
INTERNAL EVENT DailyMeetingsReportRan
DOMAIN EVENT root.DailyMeetingsCompacted
INTERNAL COMMAND DeleteMeeting()
DOMAIN EVENT root.MeetingTombstoned
SYSTEM COMMAND VersionTopic(Meetings, root, v2.0)
SYSTEM EVENT system.TopicRegistered
SYSTEM EVENT system.TopicSchemaRegistered
SYSTEM EVENT system.TopicVersioned
Make sure your lifecycle works on paper. You can mock up the stories you want to tell. If your mockup covers all of your use cases or BDD scenarios for your MVP you’ve got a hella good start on your system.
Sometimes events carry state and relations. Sometimes they don’t. They can act an awful lot like Montagues and Capulets. Work to understand the roles and teams that own entities. Find overlap and areas where conventions or standards might help the business communicate. Be aware of relational dependencies. Try not to act as a pass-through for data that is owned by other teams' models. It makes change difficult later on.
Naming conventions
- Event names are human-readable and follow a SubjectObjectPredicate format
- Events must contain a reference to at least one subject —an aggregate, an entity, or a domain
- Topics are nominal phrases or concepts that describe and categorize streams of events
- Events map to system-readable operations (functions or transactions)
- Events are grouped in a traversable domain or entity based on function or type
- Strong naming conventions help you automate systems and scale more easily over time
- Make your Domain Events more descriptive: events with Created, Updated, Deleted are generally lower than the domain level
In order to integrate, to communicate and to interoperate events must convey a shared set of meaning within both human and automated systems. Name your events carefully and well. Build systems that can adapt and evolve with a reasonable amount of shared intention. Communicate regularly with your consumers.
Evolutionary conventions
- Systems that allow small, incremental changes are easier to evolve
- Attributes inside events are part of the default config of an entity or domain
- Attributes can be built, assigned, and retired using evolutionary patterns in a system designed to handle them
- Changes to the structure of schemas or metadata are part of an evolutionary system
- Domain, Topic, and schema registries can help your teams discover important events
- Mutation & Versioning around breaking changes can be automated or semi-automated with evolutionary design patterns
- Build systems where events and entities can evolve and change depending on business requirements
- Include FULL lifecycles—make ways to retire and tombstone systems, entities, and events
We build stories with events; we use them to semantically and syntactically plot, build, communicate, and collaborate.
Take some lessons from Shakespeare’s tragedy. You can create common language and conventions that allow you to inform people about systemic or breaking change. This can help keep the cost of change down. Seek awareness, use descriptive naming standards, register schemas, and share practices around persistent events.
Additional Resources