Lakshya

Data Platform & Analytics · Chapter 4 of 16

Data quality that is not a dashboard

Most quality programmes produce alerts nobody actions. This is about the small number of tests that earn their place.

4 min read0 diagramsAll 16 chapters

The failure mode is familiar: hundreds of tests, thousands of alerts, and a team that has learned to ignore them — which means a real failure is now invisible inside the noise, exactly as with a badly tuned SIEM — a Security Information and Event Management system, which centralises logs from everywhere and alerts on them.

Four checks worth having on everything important

CheckCatchesWhy it earns its place
FreshnessThe pipeline did not runThe single highest-value test. Most incidents are absence, not corruption
VolumeRow count outside the expected bandCatches partial loads, which are worse than failures because they look successful
Uniqueness on the keyFan-out from an upstream changePrevents silent double-counting, the hardest bug to notice
Null rate on required fieldsA producer changeUsually the first symptom of a broken contract

Almost everything beyond those four is either a business rule that belongs in the model or a test somebody added after an incident and nobody has revisited since.

The metric to report, and the one to avoid

Report: the proportion of incidents found by a check rather than by a human, and the median time from breakage to detection. Those tell you whether the programme works.

Avoid: number of tests, or test coverage. Both reward adding tests, which is the behaviour that produced the noise. A team with 900 tests and a 40% alert-to-action rate is worse off than one with 60 tests and a 90% rate.

Lineage is what makes an incident survivable

When something breaks at 07:00, the question is not what broke — it is what depends on it, so you know who to tell before they find out themselves. Column-level lineage turns a half-day of investigation into a query, and it is also the thing that lets you delete anything with confidence.

Where to put the checks

Quality checks are cheap to write and easy to put in the wrong place. The rule that survives: test at the boundary you do not control, and at the grain you promise.

PlaceWhat belongs thereWhat does not
On ingestion, at the source boundarySchema conformance, required fields, referential sanity, row-count plausibilityBusiness logic — you do not yet know the business meaning of raw data
On the model you publishGrain uniqueness, not-null on keys, accepted values, referential integrity to dimensionsAnything that duplicates an ingestion check — you will maintain it twice
On the metricReconciliation against an independently-known totalRow-level assertions; the metric is an aggregate
In monitoring, not testsFreshness, volume bands, distribution driftAnything with a definite right answer — that is a test, and it should block

The distinction in the last row is the one worth internalising. If there is a correct answer, assert it and fail the build. If there is only a normal range, monitor it and alert. Teams that alert on things with definite answers get alert fatigue; teams that test things with only a normal range get a red pipeline every time the business has a good day.

The check that catches the most and costs the least

A uniqueness test on the grain key of every published table. If it is one row per order, assert order ID is unique.

It is one line. It has no false positives — the grain either holds or it does not. And it catches the entire class of silent fan-out from a join to a one-to-many table, which is the most expensive quiet failure in analytics because the numbers stay plausible.

No statistical monitor can catch that class, because after a fan-out every row is a real row, the schema is unchanged and the distribution barely moves. Volume rises, but by an amount that looks like growth.

Second on the list, and nearly as cheap: reconciliation to an independently-known total. If finance has a revenue number produced by a different system, compare to it on a schedule. It is the only check that validates meaning rather than shape, and it is the check that finds the errors everything else was structurally unable to see.

Check yourself

Where do business-logic checks belong?On the model you publish, not on ingestion — at ingestion you do not yet know the business meaning of raw data.
When should something be a test rather than an alert?When there is a definite right answer. Definite answers block the build; normal ranges get monitored.
What is the cheapest high-value check?A uniqueness test on the grain key. One line, no false positives, and it catches silent join fan-out that no statistical monitor can see.
What is the only check that validates meaning?Reconciliation against an independently-known total from another system.
← Data contracts, and who gets pagedStreaming, and when you actually need it →