C.W.K.
Stream
Lesson 03 of 05 · published

The Family Series Is Merged, Never Stored

~10 min · computed-state, time-series, merge-on-read, consistency

Level 0Open Gate
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Store the parts you own. Compute the whole when someone asks. A sum you never wrote down can never be out of date."

From scope to time series

You already know Family is a projection of Dad and Mom (Track 1). Now watch it hold under a harder case: history. Keep keeps a daily value time series so you can see how a portfolio's total moved over weeks and months. The naive design would store three series — Dad's, Mom's, and Family's. Keep stores two. The portfolio_value_history table receives one row per writable owner per day — Dad and Mom only. The Family series is merged on read: when you ask for the family history, Keep reads the two owner series and combines them on the fly. It is never written to disk.

Why merge-on-read beats a stored third series

Imagine Family were stored as its own daily row. Now every time the daily job writes Dad's and Mom's rows, it also has to write a correct Family row — and if the job is ever interrupted after two writes but before the third, the Family series silently disagrees with its parts for that day. Merge-on-read removes the failure entirely: there is no third write to get wrong. The family total for any day is defined as the sum of that day's owner rows, computed when read. It cannot drift because it has no independent storage to drift from.

The safest stored value is the one you didn't store. Every derived value you persist is a consistency obligation — a promise to update it whenever its inputs change, and a bug waiting for the one time you don't. Compute-on-read trades a little CPU for the permanent elimination of an entire class of drift.

The one honest cost

Merge-on-read isn't free: reading the family series costs a little more work than reading a stored column, because you're combining two series every time. For Keep's scale — one family, daily granularity — that cost is trivial and the correctness guarantee is enormous. That's the real lesson: this is a trade-off, and you make it consciously. At a billion rows the calculus might flip toward a carefully-maintained materialized view. At family scale, compute-on-read is unambiguously right, and pretending the CPU cost is zero would be dishonest.

Alignment matters when you merge. Combining two daily series means deciding what happens when one owner has a row for a date and the other doesn't — a market holiday, a late refresh. The merge has to define that alignment explicitly (carry-forward the last known value, or treat as absent) rather than silently producing a total that's really only half the family. Merge logic is where 'computed' earns its keep.

Code

Two stored series, family merged on read (illustrative)·python
# The daily job writes ONLY writable owners.
def record_daily_values(as_of):
    for owner in ("dad", "mom"):          # NOT 'family'
        upsert_value_history(owner, as_of, owner_total(owner, as_of))

# Family history is defined, not stored: read the two, align, sum.
def family_value_series(start, end):
    dad = value_history("dad", start, end)
    mom = value_history("mom", start, end)
    return [
        {"date": d, "value": dad.get(d, carry) + mom.get(d, carry)}
        for d, carry in aligned_dates(dad, mom)
    ]

# There is no upsert_value_history('family', ...). By design.

External links

Exercise

Design a small time-series where a 'total' line is the sum of two 'part' lines over dates. Write both versions: (a) store the total as its own daily rows, (b) merge it on read from the parts. For version (a), describe the exact interruption that leaves the total disagreeing with its parts for one day. For version (b), describe the alignment decision you must make when one part is missing a date.
Hint
Version (a)'s bug is a partial write: parts updated, total not. Version (b) can't have that bug — but it forces you to answer 'what does the total mean on a day where only one part reported?' Both designs have a hard question; (b)'s question is at least always in front of you, not hiding in a missed update.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.