Experimentation Platforms and Infrastructure Questions
Infrastructure for A/B testing and experimentation: assignment/bucketing, metric pipelines for experiments, guardrail and variance-reduction plumbing, and experiment result storage. Covers building the platform that powers trustworthy online experiments at scale. Distinct from the statistics of experiment analysis.
Design an automated reporting pipeline that computes statistical significance and uncertainty for hundreds of experiments daily and produces a concise 'experiment card' for executives. How do you apply multiple-testing correction before it reaches the card, how do you present uncertainty honestly on a one-page summary, and how do you trade off freshness against compute cost? Include a manual review gate before anything reaches an executive inbox.
Sample Answer
Direct answer
Design the reporting pipeline to compute significance and uncertainty for every experiment daily, apply a multiple-testing correction before anything reaches an executive-facing card, present uncertainty honestly (a range, not a bare point estimate), balance freshness against compute cost by tiering how often different tiers of experiments recompute, and gate anything reaching an executive inbox behind a manual review step, since an unreviewed automated report reaching leadership is a much more costly mistake than the same error reaching an internal analyst dashboard.
Structured elaboration
- Architecture: raw metric computation feeds a scheduled aggregation job that, once a day, applies the org's chosen multiple-testing correction across that day's batch of tests, then a templating layer renders a short, standardized "experiment card" (headline result, confidence range, guardrail status) per experiment.
- Handling multiple-testing correction: since this pipeline is specifically the one aggregating results across many experiments for executive consumption, it's a natural place to enforce the correction consistently, rather than leaving each team's individual dashboard to (inconsistently) decide whether to correct or not.
- Presenting uncertainty honestly: a card shows a range ("we estimate a 2 to 5 percent improvement") rather than a single point number, and explicitly flags when a result is not yet statistically reliable, rather than omitting uncertainty to look cleaner.
- Freshness versus compute cost: recomputing every card in real time for every experiment is expensive at scale; a practical tiering computes high-visibility or high-stakes experiments' cards more frequently (say, hourly) while lower-priority ones refresh once daily, since a stakeholder waiting on a major launch decision has a different freshness need than someone casually checking a long-tail experiment.
- Manual review gate: before a card reaches an executive's inbox (as opposed to sitting in an internal dashboard anyone can browse), a human reviews it, specifically to catch an automated-but-wrong summary (a card that technically computed correctly but tells a misleading story, like showing a "win" the guardrail metrics would contradict) before it reaches an audience less equipped to independently verify.
- Minimizing alert fatigue: the same pipeline, run against hundreds of metrics daily rather than just per-experiment cards, needs its own noise control (scoring how surprising a flagged change is against that metric's own historical variance, not a flat threshold) or the volume of flagged changes trains recipients to skim past all of them, including the real ones.
- A lower-stakes channel for routine updates: not every update needs the weight of an executive card; a lighter-touch automated weekly email to metric owners, summarizing key numbers, significance, and a suggested next step, serves the routine-monitoring need without invoking the full manual-review machinery reserved for genuinely executive-facing summaries.
Worked example
An automated card for a checkout experiment reports "+4% conversion, statistically significant" the same day a guardrail metric (payment failure rate) quietly crossed its own threshold. Without a manual review gate, that card reaches executives showing an unambiguous win while the platform's own guardrail system is flagging a real problem elsewhere; the review step is what catches the mismatch and either holds the card or adds the guardrail context before it ships to that audience.
Trade-offs and pitfalls
A manual review gate on every card doesn't scale if the org runs hundreds of experiments a day; the practical answer is scoping the gate to cards that are actually executive-facing (a small, curated subset) rather than every internal report, and building automated pre-checks (does the guardrail status contradict the primary-metric headline) that flag a card for mandatory review rather than requiring a human to read every single one regardless of risk.
Design a controlled-experiment platform for evaluating performance and reliability changes across regions. Include a safe traffic-splitting mechanism, the statistical power considerations behind your sample size, how you guard against cross-region confounders, and rollback triggers based on reliability metrics rather than product metrics.
Sample Answer
Direct answer
For reliability and performance changes specifically, use a safe traffic-splitting mechanism at the load-balancer or routing layer (not a client-side flag, since a reliability regression should be caught before it reaches application code that might itself be part of the problem), size the sample using the same statistical-power logic as any experiment but calibrated to the metric's natural variance (often lower for infrastructure metrics than for product metrics), guard against cross-region confounders by never comparing regions to each other directly as the treatment/control split, and gate rollback on the reliability metrics themselves, not on a business metric that would react too slowly.
Structured elaboration
- Safe traffic splitting: route a percentage of REQUESTS (not necessarily distinct users, since reliability changes often care about request-level behavior) to the new configuration at the infrastructure layer, so a routing bug or regression is caught before application-level code runs, and so the split itself doesn't depend on a mechanism that could be affected by the very regression you're testing for.
- Statistical power for infrastructure metrics: metrics like latency or error rate often have very different variance characteristics than product conversion metrics (sometimes lower baseline variance for a stable, high-volume service, sometimes much higher due to occasional severe outliers), so the sample-size calculation should be based on that metric's own observed variance, not a generic assumption borrowed from product experimentation.
- Cross-region confounders: never assign control to one entire region and treatment to another, since regions differ in ways (network topology, user behavior patterns, time-of-day traffic mix) that would confound any observed difference; instead, split traffic within each region independently so every region contributes both control and treatment observations.
- Rollback triggers: gate automatic rollback on the reliability metrics directly (error rate, latency percentiles) with a much faster response time than a typical product guardrail, since an infrastructure regression can compound quickly (cascading failures) in a way a slower-to-detect product metric wouldn't catch in time.
- Handling correlated experiments: infrastructure changes often interact (a caching change and a routing change both affecting the same latency metric simultaneously), so the same interference-detection principles used for product experiments apply here, with the added wrinkle that infrastructure-level experiments may need even tighter isolation, given how directly they can compound each other's effects.
Worked example
A team wants to test a new caching layer's effect on p95 latency. Rather than routing all of Region A to the new cache and all of Region B to the old one, splitting traffic within each region independently (say, 10% of requests in every region hit the new cache) avoids confounding the caching change with any pre-existing regional difference in baseline latency, and lets the analysis pool the effect across regions with region as a covariate rather than as the treatment assignment itself.
Trade-offs and pitfalls
Comparing regions directly as treatment versus control is a tempting shortcut (it's operationally simpler to flip an entire region over) but confounds the actual change with whatever pre-existing regional differences exist, and is exactly the mistake this design has to guard against explicitly. The faster rollback thresholds appropriate for reliability metrics also mean a higher false-positive rate on noisy infrastructure signals is more tolerable here than it would be for a product guardrail, since the cost of an unnecessary rollback on an infra change is usually much lower than the cost of letting a real reliability regression run.
Design a set of automated daily validity checks for experiments: sample-size/power check, exposure-imbalance test, metric-instrumentation-drift detection, and SDK error-rate check. For each check, sketch the SQL or pseudocode that computes it and propose an alert threshold and a corrective action.
Sample Answer
Direct answer
Build four automated checks: a sample-size/power check comparing accumulated traffic against the planned minimum-detectable-effect target, an exposure-imbalance (SRM) test, a metric-instrumentation-drift check comparing current event volume against a recent historical baseline, and an SDK error-rate check, each computed in a scheduled daily job with a concrete alert threshold and a defined corrective action.
Structured elaboration
- Sample-size/power check (pseudocode):
current_n = count(exposed_users)
required_n = precomputed_required_sample_size(mde, baseline_rate, alpha, power)
if current_n < required_n * 0.5 AND days_elapsed > planned_duration * 0.7:
alert("underpowered: unlikely to reach target sample size on schedule")
- Exposure-imbalance (SRM) test (SQL sketch):
SELECT variant, COUNT(DISTINCT user_id) AS n
FROM exposures WHERE experiment_id = :exp_id
GROUP BY variant;
-- feed observed counts into a chi-square goodness-of-fit test against the
-- configured allocation; alert if p < 0.001
- Metric-instrumentation-drift check: compare today's event volume per event type against the trailing 7-day median, flagging a drop of more than roughly 20% (a threshold tuned per event type's normal day-to-day variance) as a likely instrumentation break rather than a real behavior change.
- SDK error-rate check: track the error rate reported by each SDK version calling the assignment or exposure-logging endpoints, alerting when any single version's error rate rises meaningfully above its own recent baseline, which isolates version-specific bugs rather than being swamped by normal background error noise.
Corrective actions: an underpowered flag should prompt either extending duration or explicitly labeling the eventual read-out as exploratory; an SRM alert should pause new exposure until root-caused; an instrumentation-drift alert should pause metric reporting (not the experiment itself) until the drift is understood, since the experiment may still be running fine while only the measurement is broken; an SDK error-rate spike should page the owning team for that specific client version.
Worked example
A daily job finds that exposure event volume for one client platform dropped 35% versus its 7-day median, while the other platform's volume is stable. Rather than a real behavior change (which would show up gradually, not as a sudden day-over-day cliff on one platform only), this pattern strongly suggests an instrumentation break specific to that platform's latest release, and the automated action is to flag metric reporting for that experiment as unreliable pending investigation, rather than letting a broken measurement silently continue to feed the dashboard.
Trade-offs and pitfalls
Setting drift thresholds too tight on inherently noisy event types (ones with genuine day-of-week seasonality) produces frequent false alarms; setting them too loose misses real breaks for days. The practical fix is tuning each threshold to that specific event type's own historical variance rather than using one global percentage across every metric, and separating weekday from weekend baselines where seasonality is strong enough to matter.
Design an experiment metadata schema (relational or document) that supports lineage, multiple versions of the same experiment, owners, compliance tags, and status transitions. Show the core fields and explain how an analyst or an auditor would use each one to reconstruct a past experiment.
Sample Answer
Direct answer
Design the metadata schema around lineage, versioning, ownership, compliance, and status, with each experiment record capable of pointing back to prior versions of itself (a re-launch, a configuration change) rather than treating every change as an entirely new, disconnected record; an analyst uses these fields to find what ran and when, and an auditor uses them to reconstruct exactly what changed, who approved it, and why.
Structured elaboration
Core fields: experiment_id (stable across the experiment's life), version (increments on any material configuration change), parent_experiment_id (for a follow-up or re-launch that's conceptually the "same" test), owner, compliance_tags (which regulatory or policy category this touches, if any), dataset_links (which underlying tables/event streams feed its metrics), and status with a full transition history rather than just a current value. Rounding out the fields a reproducible re-analysis actually needs: assignment_seed (the exact value used to hash users into buckets, without which a past random assignment can never be recomputed), sample_allocation (the percentage split that was actually live, which the version field's change_history should preserve alongside every prior value, not just the current one), and code_version (which build of the experiment's code was running), so a backfill job recomputing historical metrics after a bug fix can reconstruct precisely what a user would have experienced at any past point in time.
Lookup patterns: an analyst investigating "what experiments touched this metric last quarter" queries by dataset_links and date range; an auditor reconstructing a specific decision queries the status transition history for exactly when an approval happened and who granted it; someone tracing a re-launched experiment's full history follows the parent_experiment_id chain back through every prior version rather than treating each relaunch as an unrelated, disconnected record.
Worked example
A pricing experiment launches, gets paused after two days due to a guardrail breach, is fixed, and relaunches as a new version two weeks later. Without a parent_experiment_id linking the relaunch to the original, an analyst querying "what happened with this pricing test" only finds the successful second attempt and has no record of the first attempt's guardrail breach, which is exactly the kind of institutional memory loss a lineage-aware schema is meant to prevent.
Trade-offs and pitfalls
Making every configuration change spawn an entirely new, disconnected experiment_id is simpler to implement but destroys the lineage an auditor or analyst actually needs; carrying full version history for every field on every change is more complete but adds real storage and query complexity. Most platforms land on versioning only the fields that materially affect interpretation (allocation, targeting, metrics) while treating cosmetic changes (a description edit) as non-versioned metadata updates.
You need to add a new mutually-exclusive experiment into live production traffic without reassigning users already exposed to other experiments, preserving exposure stickiness. What data structures and assignment ordering would you use, and how do you keep this cheap in state and latency on the evaluation path?
Sample Answer
Direct answer
Insert the new mutually-exclusive experiment into a dedicated traffic layer that only newly-eligible users (those not already committed to another experiment in that layer) can enter, using a priority or first-come ordering recorded per user the first time they're evaluated against that layer, so existing users already exposed to a different experiment are never reassigned.
Structured elaboration
The key data structure is a per-user, per-layer assignment record: the first time a user is evaluated against a mutually-exclusive layer, whichever experiment currently owns that layer slot for that user gets recorded, and every subsequent evaluation for that user in that layer reads the recorded assignment rather than recomputing it. Inserting a brand-new experiment into the layer means: any user with no existing record for that layer becomes eligible for the new experiment (hashed in as usual); any user WITH an existing record keeps it, full stop, regardless of what the new experiment's allocation logic would have computed for them.
To keep this cheap in state and latency, the assignment record doesn't need to be a giant table looked up synchronously on every request; it can be derived on first-write and then cached the same way any other assignment is cached, with the "first eligible slot wins and is sticky" rule enforced at write time rather than checked on every read.
Worked example
A layer currently runs Experiment A at 100% of its slot. A new Experiment B needs to launch into the same layer at a 20% share. New users hashed into that 20% get Experiment B; users who were already recorded as being in Experiment A (even if a fresh hash of their id would have landed them in B's 20%) keep A, because their assignment record already exists. This is what "preserving exposure stickiness" means concretely: existing users' experience doesn't change just because the layer's occupancy changed.
Trade-offs and pitfalls
The subtlety that trips people up is conflating "the layer's allocation percentages changed" with "existing users should be re-hashed against the new percentages." Re-hashing existing users the moment allocations change reintroduces exactly the instability this design is meant to prevent (a user who was in A suddenly finding themselves in B mid-experiment, with no clean causal interpretation of either experiment's result for that user). The cost of correctness here is that a layer's actual traffic split can drift from its nominal configured percentages for a while, since existing users are grandfathered in at their original assignment; this is expected and should be visible in the platform's reporting, not treated as a bug.
Unlock Full Question Bank
Get access to all Experimentation Platforms and Infrastructure interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.