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?

  1. Producerincome → monthlyIncome
  2. Message v2
  3. Riskexpects “income”
  4. 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.

More on this topic

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

  1. IncomeChanged v1income: 1 200 000
  2. Upcaster÷ 12
  3. IncomeChanged v2monthlyIncome: 100 000
  4. Aggregatecorrect value

Rules

  1. Add a field: yes
  2. Change the meaning: never
  3. 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.

More on this topic

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