Publishing events to Pub/Sub creates a contract with other teams. Anyone in the company can consume these events. Once events are in the data lake, data science teams may depend on them.
Key principle: Design events carefully upfront - you may not get a chance to change them later.
Best strategy: Add new fields without removing old ones.
- Keeps existing consumers working
- Tradeoff: payload grows over time
- Works for most real-world scenarios
Sometimes adding fields isn't an option:
- Event payload is already too large
- Domain logic changed when the event is emitted
- Required fields are no longer available
- Create a new event with new name and format (keep the old one)
- Start emitting new events
- Update consumers to use new events
- Remove old events (may never happen - that's okay)
Note: Finding all event consumers is harder than finding API users. Events are consumed "indirectly" making usage tracking difficult.
Add version suffixes to all event types to support future migrations:
// Instead of:
type TicketBookingConfirmed struct { ... }
// Use:
type TicketBookingConfirmed_v1 struct { ... }Benefits:
TicketBookingConfirmed_v1andTicketBookingConfirmed_v2are treated as separate events- No risk of accidentally using wrong version
- V2 may have different meaning and trigger conditions than V1
For existing systems: Events without version numbers can be assumed to be V1.
Teams often create events with all possible fields (sometimes 50+ fields). This creates maintenance burden when other teams start depending on them.
Better approach: Start minimal, add fields as needed with backward compatibility in mind.