Part 12 of 16 · Day 2 · schema versioning, upcasting
A message change breaks someone else's service
Problem and experience
We change a field and someone else's service crashes
Who is responsible for making sure a message change does not break subscribers? The producer, or those who read it?
- Producerincome → monthlyIncome
- Message v2
- Riskexpects “income”
- NaN
From practiceWhen did a change to someone else's message or API stop your own service?
TakeawayA contract change is a change for everyone who reads it.
What it means
Messages outlive code and are read by teams the producer does not know.
Why we use it
Without rules, every change becomes a crisis.
When it makes sense
As soon as someone other than the producer reads the message.
Where it breaks
- Changing the meaning of a field while keeping its name.
- Removing a field that someone still reads.
- Not knowing who reads the message.
Imagine
Annual income used to be stored; now it is monthly. An old subscriber reads the monthly value as annual.
A contract is a promise we must keep even after the code changes.
Principle, application and exercise
Versions, upcasting and compatibility rules
We version the message. Old shapes are converted on read, and compatibility rules define what the producer may do.
Upcasting
- IncomeChanged v1income: 1 200 000
- Upcaster÷ 12
- IncomeChanged v2monthlyIncome: 100 000
- Aggregatecorrect value
Rules
- Add a field: yes
- Change the meaning: never
- Remove: by agreement
Trade-offSupporting older versions takes work. Let's decide how long we will keep it and who owns the conversion.
TakeawayWe do not rewrite history. We teach the code to understand every shape that has ever existed.
What it means
An event carries a schema version. An upcaster is a pure function that converts an older shape to the current one. Deterministic replay requires that apply uses neither time nor randomness, and that the event carries the stored result and the algorithm version.
Why we use it
We must be able to read immutable events even years later. What we once promised the client must not be overwritten by a new formula.
When it makes sense
With every change to a shape or to rules that already exist in production data.
Where it breaks
- Rewriting old events in the store.
- A missing upcaster: an annual value silently becomes nonsense.
- Recalculating old events retrospectively with a new algorithm.
Imagine
The bank promised an instalment based on V1. After V2 is deployed, a different amount must not appear on load.
The old shape stays. We convert it on read.
Training for your team
Would you like this training for your team?
We run the training on your code and your domain problem. We agree the scope, dates and format with you.
Discuss the training →