Skip to content
About
Main content

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

How far apart are the three analysts' counts of active customers in September?

Run it

  1. 1Install uv once. It fetches Python and the lab's packages for you.

    Terminal
    curl -LsSf https://astral.sh/uv/install.sh | sh
  2. 2Get the script. It is the whole lab: read it, then download it.

    the-definition-variant-experiment.py62 linesDownload
    View 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)
    
  3. 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
Knobs
Knob · defaultWhat 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

Three answers to one question
DefinitionActive customers
Analyst A: any order, UTC calendar month46.3K
Analyst B: exclude refunds and test accounts, UTC44.9K
Analyst C: exclude test accounts, local time (UTC-8), BETWEEN on dates45.6K

The edge cases each one settled

The edge cases each one settled
Edge caseABC
refunded orderscountexcludecount
test accountscountexcludeexclude
time zoneUTCUTCUTC-8
end of periodbefore 1 Octbefore 1 Oct1 Oct included
Reference runApple M2 · 8 cores · 8 GB
Output · uv run the-definition-variant-experiment.py
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,930
macOS 26.6.2 · Python 3.13.3 · duckdb 1.5.6 · run 2026-10-20

What 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 (, identity, time, boundary), not a difference in code.

'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.