The definition-variant experiment
Simulate a modelNeeds Python with DuckDB
Problem
A metric is a definition, and most definitions are never written down. "Active customers in September" leaves open whether refunded orders count, whether test accounts count, which time zone September is in, and whether its last boundary is inclusive. Each analyst settles these silently, in SQL, and each choice is reasonable, so three people asked the same question produce three numbers, and no check fails.
Give three colleagues the same one-sentence request, "count active customers in September", and the same tables. Do not discuss it. Compare their numbers. Then list every difference in their SQL (refunds, test accounts, time zone, period boundaries). Finally, write one metric definition and have all three reuse it.
The script cannot ask colleagues, so it writes three analysts' reasonable answers as SQL, each settling the four edge cases differently, over one generated orders table in DuckDB.
The question. How far apart are three reasonable answers to "active customers in September", and which unwritten choices explain the gap?
Predict
Expect different numbers, and expect each difference to be an edge case nobody wrote down.
Run it
1Install uv once. It fetches Python and the lab's packages for you.
Terminal curl -LsSf https://astral.sh/uv/install.sh | sh2Get the script. It is the whole lab: read it, then download it.
View the codeHide the code
the-definition-variant-experiment.py # /// script # requires-python = ">=3.10" # dependencies = ["duckdb"] # /// # Copyright (c) 2026 Aayush Sharma · SPDX-License-Identifier: MIT # https://thedataengineering.com/lab-code/LICENSE.txt """The definition-variant experiment. "Count active customers in September", answered by three definitions that each settle the unwritten edge cases differently: refunds, test accounts, time zone and the period boundary. The chapter's experiment uses three colleagues; here each colleague is a set of reasonable choices, so the differences can be counted one by one. Then one shared definition. """ import argparse, json import duckdb p = argparse.ArgumentParser(description=__doc__.splitlines()[0]) p.add_argument("--customers", type=int, default=50_000, help="Customers.") p.add_argument("--orders", type=int, default=400_000, help="Orders over three months.") p.add_argument("--seed", type=float, default=0.42, help="Random seed for DuckDB (between -1 and 1).") p.add_argument("--json", help="Also write the results to this JSON file.") args = p.parse_args() con = duckdb.connect() con.execute(f"SELECT setseed({args.seed})") con.execute(f"""CREATE TABLE customers AS SELECT i AS customer_id, random() < 0.02 AS is_test FROM range({args.customers}) t(i)""") con.execute(f"""CREATE TABLE orders AS SELECT i AS order_id, (random() * {args.customers})::INT AS customer_id, TIMESTAMPTZ '2025-08-01 00:00:00+00' + INTERVAL (random() * 92 * 86400) SECOND AS ordered_at_utc, random() < 0.04 AS refunded FROM range({args.orders}) t(i)""") # the three colleagues' reasonable but different choices variants = { "Analyst A: any order, UTC calendar month": """ SELECT COUNT(DISTINCT customer_id) FROM orders WHERE ordered_at_utc >= TIMESTAMPTZ '2025-09-01 00:00:00+00' AND ordered_at_utc < TIMESTAMPTZ '2025-10-01 00:00:00+00'""", "Analyst B: exclude refunds and test accounts, UTC": """ SELECT COUNT(DISTINCT o.customer_id) FROM orders o JOIN customers c USING (customer_id) WHERE NOT o.refunded AND NOT c.is_test AND ordered_at_utc >= TIMESTAMPTZ '2025-09-01 00:00:00+00' AND ordered_at_utc < TIMESTAMPTZ '2025-10-01 00:00:00+00'""", "Analyst C: exclude test accounts, local time (UTC-8), BETWEEN on dates": """ SELECT COUNT(DISTINCT o.customer_id) FROM orders o JOIN customers c USING (customer_id) WHERE NOT c.is_test AND CAST(ordered_at_utc - INTERVAL 8 HOUR AS DATE) BETWEEN DATE '2025-09-01' AND DATE '2025-10-01'""", } rows = [] for name, sql in variants.items(): n = con.execute(sql).fetchone()[0] rows.append({"definition": name, "active": n}); print(f"{name:<70} {n:>7,}") diffs = [{"edge_case": "refunded orders", "A": "count", "B": "exclude", "C": "count"}, {"edge_case": "test accounts", "A": "count", "B": "exclude", "C": "exclude"}, {"edge_case": "time zone", "A": "UTC", "B": "UTC", "C": "UTC-8"}, {"edge_case": "end of period", "A": "before 1 Oct", "B": "before 1 Oct", "C": "1 Oct included"}] spread = max(r["active"] for r in rows) - min(r["active"] for r in rows) print(f"spread between the three answers: {spread:,} customers ({spread / rows[0]['active']:.1%})") shared = con.execute(variants["Analyst B: exclude refunds and test accounts, UTC"]).fetchone()[0] print(f"one written definition, reused by all three: {shared:,}") if args.json: with open(args.json, "w") as f: json.dump({"tables": {"definitions": rows, "differences": diffs, "summary": [{"spread": spread, "spread_pct": spread / rows[0]["active"] * 100, "shared": shared}]}}, f)3Run it in the folder you saved it to, with the defaults first. Then change a knob from the table below and run it again.
Terminal uv run the-definition-variant-experiment.py uv run the-definition-variant-experiment.py --help # every knob
| Knob · default | What it changes |
|---|---|
| --customers50,000 | Customers. |
| --orders400,000 | Orders over three months. |
| --seed0.42 | Random seed for DuckDB (between -1 and 1). |
Our run
Three answers to one question
| Definition | Active customers |
|---|---|
| Analyst A: any order, UTC calendar month | 46.3K |
| Analyst B: exclude refunds and test accounts, UTC | 44.9K |
| Analyst C: exclude test accounts, local time (UTC-8), BETWEEN on dates | 45.6K |
The edge cases each one settled
| Edge case | A | B | C |
|---|---|---|---|
| refunded orders | count | exclude | count |
| test accounts | count | exclude | exclude |
| time zone | UTC | UTC | UTC-8 |
| end of period | before 1 Oct | before 1 Oct | 1 Oct included |
Analyst A: any order, UTC calendar month 46,290
Analyst B: exclude refunds and test accounts, UTC 44,930
Analyst C: exclude test accounts, local time (UTC-8), BETWEEN on dates 45,637
spread between the three answers: 1,360 customers (2.9%)
one written definition, reused by all three: 44,930What we found
The three definitions gave three different counts, 1,360 customers apart (2.94%), as expected. Every difference traced to one of the four edge cases: refunded orders, test accounts, the time zone that decides which orders fall in September, and whether 1 October is inside the period. None of the three is wrong. Once all three used one written definition, they all reported 44.9K.
Read it
If two numbers disagree and no check fails, look for a difference in meaning (grain, identity, time, boundary), not a difference in code.
Normalization's cost moves to definition drift: the more places a metric can be recomputed, the more definitions of it exist. A metric layer, or simply one owned definition per metric with its edge cases written next to it, is what makes the three numbers one.