</> MAANG.io
system design · 301

Advanced

Master system design interviews with scalable architecture patterns, distributed systems, and real-world design challenges.

0/480 solved 0% complete

Section 12: The Promises Come Due - Follow-up Feature Evolution

Executive Summary: This section answers the interviewer's classic closing move: six months later, the company wants A/B testing, flags reviewed in git, and typed config through the same pipe. Experiments add a per-experiment salt and a sampled exposure log on the same bucketing; git becomes a front-end syncing into the control-plane database while kills keep their instant lane; dynamic config is JSON variations with schema validation at publish. The reusable lesson: a design is evolvable when a new job means a new consumer of existing primitives, not a parallel system.

The whiteboard is full and the design survives failure. The interviewer leans back for the classic closing move: "Six months later, product wants real A/B testing with statistics, the platform team wants flag changes reviewed in pull requests, and the ML team wants to ship ranking parameters through this thing. What changes?" The question audits your earlier self: Sections 1, 2, 3, 5 and 7 each deferred something here — the stats engine, per-user exposure, git review, sticky assignments. Later is now.

Experiments: A New Salt, Not a New System

You: "Almost nothing changes on the serving path. An experiment is a flag with variations worth comparing, an independent cohort, and a measurement pipeline. The platform already has the first two."

The independent cohort is what D3's flip trigger was written for: in murmur3_32(flagSalt + ":" + unitId) mod 10,000, a new salt gives an independent assignment. When Fabrikam tests a new reply-ranking model, the experiment is its own flag with a fresh salt and a 50/50 split (threshold 5,000). Dana's bucket of 1,234 for smart-reply-v2 predicts nothing about their bucket here — and without that independence, the same unlucky 1% is treatment for every launch and effects confound each other.

Why must experiments share the platform's bucketing at all? Because D12's rejected alternative — a second experimentation system with its own hashing — eventually disagrees with the first, and then Dana gets treatment UI on a control backend: chips render, the endpoint behind them is the old model, and both the experience and the measurement are garbage. It's why smart-reply-chips shares smart-reply-v2's salt and unit, and why experiment assignment is the same hash, not a cousin of it.

What's genuinely new is measurement. Section 9's gates answer "is treatment hurting?" in real time; statistics answers "did treatment win?", which needs to know who was in which cohort. Logging every evaluation is the 50M events/s D9 already refused. The honest unit is the first exposure: one event per (user, experiment), emitted when a user first receives a variation — deduped in the SDK's seen-set and again at the collector, because instances restart and users touch many pods.

You: "Volume check: 100M DAU and a handful of concurrent experiments — call it five. Worst case, an experiment ramps to its full population in a day: 100M first exposures, about 1,200 events a second per experiment, tens of thousands a second across five at the 3× peak. Against the 50M evaluations a second that per-evaluation logging would cost, that's over three orders of magnitude cheaper, and the whole log is tens of gigabytes, not a streaming problem."

Each record is (hashedUnitId, experimentKey, variation, snapshotVersion, timestamp) — hashed IDs, never names or emails (D11). For the very largest experiments the collector also samples on top of the dedup — statistical power saturates long before 100M exposures — which is why the ledger calls the log sampled.

Interviewer: "Section 7 punted sticky assignments to you. Experiments need stickiness — why not store assignments after all?"

You: "Because the exposure log records what was served — a fact about the past, for analysis — while assignment stays computed, never stored. The hash is still the assignment table: zero state, zero lookups, D1 intact at 50 million calls a second. If a mid-experiment rule edit would move users between cohorts, the stats engine excludes the movers or we restart with a new salt; we never put a per-user read on the evaluation path."

Downstream sits an offline stats engine, joining exposures to outcome metrics and computing significance — sequential testing so experiments can be peeked at safely, CUPED to shrink variance; name-drops with a boundary attached, because that engine is its own batch system, owned by a data-science team. Guardrails are already built: an experiment's guardrail metrics are Section 9's gate signals — treatment errors above control + 0.5 pp or p99 above 1.5× control, sustained 5 minutes, pause and page.

Key Insight: The split is harm versus wins. Harm detection must be real-time and lives in the platform's gates; win detection tolerates hours of latency and lives offline. Same bucketing, same exposure truth, different clocks, different owners.

Experiment flow on the existing platform: a new experiment gets a fresh salt into the same deterministic bucketing engine, the SDK serves the variation in-process, and only a user's first exposure per experiment — deduped in SDK and collector — reaches the sampled exposure log at tens of thousands of events per second, feeding the offline stats engine (sequential tests, CUPED) and the ship, stop or extend decision, with Section 9 health-gate signals as real-time harm guardrails

Interviewer: "So is this an experimentation platform now?"

You: "No. Assignment and delivery are shared, because duplicating them creates the disagreement bug. Inference is its own system with its own team: experiment design, metric definitions, statistical rigor. My platform promises deterministic cohorts and honest exposure records. It does not compute p-values."

Quick check before moving on:

Sign in to continue reading

The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.

Sign in to read the full lesson

Sign in to MAANG.io

Use your Google or Microsoft account — no password to remember.

Continue with Google Continue with Microsoft

Please accept the terms above to continue.