skip to content

How do you keep column definitions and lineage trustworthy for a published analytics model?

level: principalimportance: nice to knowfreq 35%

answer

  1. why does documentation always rot?
  2. put it where a change touches it
  3. some documentation can fail a build
  4. hand-drawn diagrams go stale confidently
  5. who answers questions about this table?

basics

~20 s

Definitions live with the model as reviewed code, every model has a named owner, and lineage is derived from parsed SQL rather than drawn by hand. Tests are the part of the documentation that cannot silently drift.

solid answer

~50 s

Documentation decays for a structural reason: it is written in a place the code does not touch, so a change to the model cannot invalidate it. The fixes all attack that. Definitions live beside the model definition and are reviewed in the same change as the SQL, so "you changed the logic, update the sentence" is a review comment rather than a hope. Lineage is derived from the transformation code itself rather than maintained as a diagram, because a hand-drawn diagram is stale within a quarter and, worse, is confidently wrong. Every published model has a named owner who answers questions about it. And the most durable documentation is the test suite: an accepted-values assertion states the column's domain and *fails* when reality diverges, which no prose can do. What I insist gets written down is the grain, the units, the currency, the timezone, and what NULL means.

code

text · 8 lines
text
fct_subscription_revenue
  grain: one row per subscription per calendar month
  owner: revenue-analytics
  mrr_amount: recognised monthly recurring revenue, USD, net of
              discounts, excludes tax; source billing.invoice_line
  is_active:  subscription had a non-cancelled status on the last
              day of the month; NULL never occurs
  exclusions: internal test accounts (account_type = 'INTERNAL')

go deeper

for a junior

Know what belongs in a column definition — grain, units, currency, timezone, what NULL means — and that a description living in a separate wiki will be wrong within months.

for a middle

Explain why tests are documentation that cannot drift: an accepted-values assertion states a domain and fails when reality diverges, which prose can never do. Keep definitions in the same change as the SQL.

for a senior

Demonstrate the practice: reviewing definitions alongside logic changes, using derived lineage for impact analysis before touching a source, and knowing where that lineage stops — dynamic SQL, external processes, the BI last mile.

for a principal

Own the governance: who is accountable per published model, how small the published surface stays, what gets asserted versus written, and honest behavioural signals of trust rather than coverage metrics.

## Why documentation rots, structurally Every data platform has a catalog full of confident, wrong descriptions. The cause is not laziness. It is that the description lives somewhere the code cannot reach, so changing the model has no mechanical consequence for the sentence describing it. Nothing fails. Nobody is told. Every durable fix follows from that diagnosis: move the documentation into the path of change, or make it executable. ## Documentation as code, reviewed with the change When a model's column descriptions live next to its definition in version control, three things follow. The change to the logic and the change to the description appear in the same review, so a reviewer can see the sentence is now false. The history of the definition is inspectable — "when did we start excluding tax from this measure?" is answerable. And ownership is expressed by the same mechanism that governs the code. This is the point at which teams reach for whatever their transformation tooling offers to attach descriptions to models. The mechanism matters far less than the property: the description must be in the diff. ## What actually needs documenting Most catalog entries fail by describing the obvious — `customer_id` documented as "the customer id" — while omitting everything a consumer would get wrong. The high-value items: - **The grain**, in one sentence: what exactly does one row mean? This is the single most useful line in any model's documentation, and its absence causes the most expensive mistakes. - **Units, currency and scale.** Is `revenue` in dollars or cents? Which currency, and converted at which rate, on which date? - **Timezone and date semantics.** Is `order_date` the customer's local date or UTC? Is a monthly measure calendar-month or a 4-4-5 fiscal period? - **The business rule behind a derived column.** `is_active` is meaningless without "had a non-cancelled subscription on the last day of the month". - **What NULL means** in this column, and whether it is distinguishable from zero or from "not applicable". - **Known exclusions.** Test accounts removed, cancelled orders filtered, internal transfers netted — the same list that makes reconciliation interpretable. ```text fct_subscription_revenue grain: one row per subscription per calendar month owner: revenue-analytics mrr_amount: recognised monthly recurring revenue, USD, net of discounts, excludes tax; source billing.invoice_line is_active: subscription had a non-cancelled status on the last day of the month; NULL never occurs exclusions: internal test accounts (account_type = 'INTERNAL') ``` ## Tests are the documentation that cannot drift This is the strongest single idea in the area. Prose says a column contains one of four status codes; an accepted-values assertion says the same thing and *fails on the day it becomes untrue*. Prose says the table is one row per order line; a uniqueness assertion proves it on every load. So the test suite is a machine-checked subset of the documentation, and it is the subset consumers can actually rely on. That reframes test coverage as a documentation question: the properties a consumer most depends on are the properties that should be assertions rather than sentences. Prose is then reserved for what cannot be asserted — intent, business rules, history, caveats. ## Lineage: derive it, never draw it Column- and table-level lineage answers two questions people ask constantly: *where does this number come from*, and *what breaks if I change this*. Both are load-bearing — the first for trust, the second for safe change. A hand-maintained diagram answers both wrongly within a quarter, and a wrong lineage graph is more dangerous than none because impact analysis based on it is confidently incomplete. Derived lineage — parsed from the transformation code, so it cannot disagree with what actually runs — is the only kind worth relying on for impact analysis. The practical limits are worth knowing. Derived lineage is weakest where the SQL is dynamic or generated, where logic sits in an external process, and where it crosses out of the warehouse into BI tools and spreadsheets — which is exactly where the most sensitive consumers live. Closing that last mile usually means integrating the BI layer's own dependency information rather than pretending the graph is complete. ## Ownership makes the rest work A model with no owner has no one to answer "is this the right table?", no one to update the definition when the business rule changes, and no one paged when its tests fail. Naming an owner per published model, and making that ownership visible wherever consumers discover the model, does more for trustworthiness than any tooling choice. The corollary is to keep the published surface small: a hundred models with owners beats a thousand where ownership is nominal. ## How you know it is working The honest signals are behavioural, not coverage percentages. Do analysts ask in chat what a column means, or do they look it up? When a source changes, does the impact analysis come from the lineage graph or from someone's memory? Does the same metric get recomputed differently in three dashboards? A documentation programme measured by percent-of-columns-described optimizes for filling boxes, which is how catalogs become full of "the customer id".

  • Why do you prefer derived lineage over a maintained diagram, even a good one?
    Because a diagram cannot be wrong loudly. Lineage parsed from the transformation code cannot disagree with what actually runs, so impact analysis based on it is trustworthy. A hand-maintained graph drifts within a quarter and then gives confidently incomplete answers, which is more dangerous than having no graph at all — people stop double-checking.
  • You have limited effort. Which columns get careful documentation first?
    The ones consumers get wrong: derived measures whose business rule is invisible from the name, anything with units, currency or timezone semantics, columns where NULL carries meaning, and the grain sentence for the table as a whole. Identifier columns that mean what they say need almost nothing — describing those is how catalogs fill up with noise.
  • How would you tell whether the documentation effort is actually working?
    By behaviour, not coverage. Do analysts look definitions up instead of asking in chat? Does impact analysis before a source change come from the lineage graph or from someone's memory? Is the same metric recomputed three different ways across dashboards? A percent-of-columns-described target optimizes for filling boxes and produces exactly the catalog nobody trusts.

saying these in an interview costs you the question

  • Documentation in a wiki the code never touches
  • Describing customer_id as the customer id
  • Hand-maintained lineage diagrams used for impact analysis
  • No named owner for a published model
  • Measuring success as percent of columns described

context