A primer on data contracts between teams
Data contracts between teams from the start, for a room that contains both engineers and the people who'll live with it.
Most write-ups of this start in the middle. We'll start earlier than strictly necessary, because nine times in ten the confusion comes from a word two people are using differently, not from the mechanism.
The moment one team reads another team's tables directly, that schema is a public API without anyone agreeing to it. The producing team can't refactor and doesn't know it. Every painful data migration we've been called into started here.
THE ACCIDENTAL API
It starts reasonably. Someone needs a number, the data's right there, and a read-only credential takes five minutes. Six months later four dashboards, a nightly job and a machine learning pipeline depend on a column, and the team that owns it has no idea.
The consequence isn't a crash. It's paralysis. The owning team stops making changes they should make, because they can't establish who'd break, and "we can't refactor that table" becomes a permanent fact about the system.
WHAT A CONTRACT ACTUALLY CONTAINS
Less than people fear. The fields, their meaning in words, what's guaranteed non-null, how fresh it is, and how you'll be told when it changes. A page is usually enough. The value isn't in the ceremony, it's in there being a named surface that's smaller than the whole schema.
The freshness clause matters more than teams expect. "Yesterday's data by 6am" is a promise you can hold someone to; "roughly current" causes an argument during every incident about whether the number was even supposed to be right yet.
Made concrete: a credit file passes through several pairs of hands, and each of them believes it owns the record. What's above is how you let all of them be right without letting any of them silently overwrite the others.
MAKING IT STICK
A contract nobody tests is a document. Assert it where the data leaves. Check that the fields exist, that the nulls are where you promised, that the row count is in a sane range, and fail the producing team's build, not the consumer's dashboard.
Then take away the direct database access. Leaving it available means the contract is optional, and an optional contract is the same as no contract on the day someone's in a hurry.
Picture a specialist asset lender at around 2,500 applications a month. The naive version works perfectly in testing and falls over the first day two underwriters touch the same credit file in the same second.
WHERE IT GOES WRONG
- A contract with no assertions, so the first sign of a breach is a wrong number in a board pack.
- A read-only credential granted in five minutes, becoming an unversioned public API within a quarter.
- The owning team unable to refactor because nobody can enumerate the consumers.
- A freshness guarantee of "roughly current", relitigated during every incident.
If another team reads it, it's an API. Name it, promise something, and test the promise.
THE SHORT VERSION
None of this is advanced. It's ordinary practice that gets skipped when a date is close, and then paid for with interest by whoever's on call.