cswork / libraryOpen practice workspace

Interview guides · Drivetime

Drivetime Data Scientist Interview Questions & Guide 2026

Drivetime data scientist prep on data pitfalls: selection bias, target leakage, and checking an outlier's provenance before you drop it.

The 60-second brief

The role of a Data Scientist at Drivetime is pivotal in harnessing data to drive decision-making and enhance operational efficiency. As a Data Scientist, you will be tasked with analyzing large datasets to extract meaningful insights that influence product development, user engagement, and business strategy. Your work directly impacts how Drivetime tailors its offerings to meet the needs of customers and improves internal processes.

Scope your preparation by the data you would actually touch, because the title will not tell you. A seat that lives in event logs and weekly readouts rewards fluency in aggregation and metric definitions; a seat that owns a model in production rewards fluency in train/serve skew, retraining cadence and drift monitoring. The fastest way to find out which one you are interviewing for is to ask what the team shipped last quarter and what it gets paged about.

Focus areas

  • Correct discovery slates for position bias
  • Define a qualified stream and defend it
  • Separate release-calendar spikes from underlying trend

Overview

In this dynamic environment, you will collaborate with cross-functional teams, including engineering, product management, and marketing, to solve complex problems using data-driven approaches. Whether it's optimizing the customer experience or forecasting trends, your analytical skills and innovative solutions will be critical to Drivetime’s success. The role is not only challenging but also rewarding, as you contribute to projects that shape the company's future and enhance the driving experience for users.

The Drivetime interview process

Drivetime candidates report 2 rounds · ≈ 2-4 weeks. The stages below are what candidates describe, not a published process.

Phone Screening

A screening call is a matching exercise run by someone who will not evaluate your statistics. They are checking that the work described on your resume is work you personally did, and that its scope matches the level the role is written for. Logistics get settled in the same half hour so nobody spends an interviewer's afternoon on a mismatch. The answer that fails is the one narrated in the plural. If every sentence is 'we built' and 'the team decided', there is nothing specific to write down about you. Name the piece that was yours, the decision you made inside it, and what changed after.

What to demonstrate

  • Whether the ownership implied by your resume survives one round of follow-up about who actually did which part
  • Whether your described scope (data size, stakeholders, what shipped) matches the seniority the role is written at
  • Whether timeline, location and compensation expectations make the rest of the loop worth scheduling

How to prepare

  • Rewrite your top three resume bullets in the first person singular, each with the decision you made and what moved afterwards, then say them out loud once so the 'we' does not return under pressure
  • Attach one number to each project: the baseline, the change, and the window it was measured over. Where impact was never measured, say that plainly rather than inventing a figure
  • Settle your compensation range before the call and give it as a range with a reason behind it, such as current total comp or a competing timeline, instead of deflecting the question twice

Technical Interviews

This round decides whether someone can hand you a schema and a question and trust the number that comes back. Correctness under a clock is the bar, not clever syntax. The habit that separates strong from weak answers is checking the grain: after every join, know how many rows you expect and whether the count moved. Most wrong answers in this format are not wrong logic, they are a fan-out from a key that turned out not to be unique, or a filter applied before an aggregate when it belonged after. Say what you expect before you run it.

What to demonstrate

  • Whether your row counts survive each join, and whether you notice on your own when they do not
  • Deliberate handling of rows that fail to match, including whether the question needs an inner join or a left join with the non-matches kept and counted
  • Whether NULLs are treated on purpose, given that a NULL compares equal to nothing and that COUNT of a column skips it
  • Reaching a defensible answer inside the window instead of a refined one after it

How to prepare

  • Take a two-table schema, write a join that fans out on purpose, then fix it by collapsing the many-side to one row per key before joining. Repeat until the fix is reflex rather than recall.
  • Write a funnel as one query and print the distinct user count at each stage, then confirm each stage is a subset of the one above it rather than assuming it
  • Do a few timed runs in a plain text box with no autocomplete and no formatter, since assessment editors often have neither

Where candidates lose points

Counting plays without a qualification threshold, or changing the threshold without restating history.

Playback arrives as heartbeats, so a play only exists once you decide what counts, and the common 30-second convention is not a neutral analytics choice: in music it is also the boundary at which a play becomes payable, which makes the warehouse definition a payout definition. The threshold interacts violently with content length, so a catalogue of three-minute tracks and one of forty-minute episodes move in opposite directions when you change it, and a skip-heavy surface can add plays while adding no hours. Any metric mixing pre-threshold and post-threshold counts, or pooling short-form and long-form on a per-stream basis, moves by double digits for reasons that have nothing to do with the product.

Treating the account as the person, or the profile as the person.

A household account carries several people, profiles frequently are not switched, and shared-screen, car and speaker playback often lands on a default profile with no user behind it. Personalisation trained on a profile therefore learns a mixture, retention regressions attribute one member's behaviour to another, and a per-account taste statistic describes a household composite. The practical consequence is that apparent personalisation wins can be device or context effects, so any identity-level claim needs a stated unit and an acknowledgement of what that unit actually aggregates.

Accepting a metric definition without asking about the denominator

Pin down the denominator, the eligibility filter and the time window before computing anything: conversion rate per session, per user, per eligible user and per new user are four different numbers with different behaviour. Restate the definition in one sentence and get agreement before you analyse.

Crediting a treatment for regression to the mean

Selecting a group because it is extreme (lowest-engagement users, accounts having their worst month, the bottom decile of a score) moves that group's expected next-period value back toward the average even under no treatment, by exactly as much as the selecting measure is imperfectly correlated with its own later value. Compare against units that met the same selection rule and went untreated, or use two pre-periods so the bounce-back is visible before the intervention starts. A pre-post number on a group chosen for being extreme measures the selection rule, not the treatment.

Questions & practice

Write a function to calculate the mean and standard deviation of a list of numbers.

Medium · statistics and probability

Approach

  1. Say what the estimate is of, and over what population it generalises.
  2. Quantify uncertainty explicitly rather than reporting a point estimate alone.
  3. Translate the result into the decision it informs, in one plain sentence.

Follow-up

  • Which assumption here is most likely to be violated in practice?
  • How would you explain this result to someone who does not know statistics?

Attribute streams to prior impressions without merge_asof

Medium · pandas · joins · attribution

You have impressions (impression_id, profile_id, content_version_id, rendered_at, surface, slate_position, viewport_visible_ms) and streams (stream_id, profile_id, content_version_id, started_at). Attribute each stream to the most recent impression of the same profile and content version with rendered_at at or before started_at, a gap of at most 30 minutes, and viewport_visible_ms above zero; break ties on rendered_at by the smaller slate_position. pd.merge_asof and any groupby-apply over individual rows are off limits. Return streams with impression_id added, plus the attributed share by surface.

Approach

  1. Filter impressions to viewport_visible_ms above zero first. A row that never scrolled into view is not an exposure, and leaving it in lets an unseen impression win the as-of match over a seen one.
  2. Stack both frames into one long frame with a ts column and an is_stream flag, then sort by (profile_id, content_version_id, ts, is_stream, negative slate_position) so that at an identical timestamp impressions sort before the stream, and among tied impressions the smallest slate_position sorts last.
  3. Forward-fill the candidate impression_id and rendered_at with groupby(['profile_id','content_version_id']).ffill(). The grouping is what stops the fill leaking across profiles; a global ffill on a sorted frame is the usual wrong answer.
  4. Apply the 30-minute window as a post-filter on the filled candidate, and let a stream that fails it go unattributed rather than falling back to an older row. Every candidate precedes the stream, so the gap grows monotonically as you walk backwards: if the nearest in-view impression is more than 1800 seconds old, no earlier one is inside the window either, and null is the correct answer. The window cannot be pushed onto the impressions frame beforehand in any case, because "within 30 minutes" is defined against a particular stream's started_at and one impression is a candidate for many streams. Dropping impressions rendered more than 30 minutes before the earliest stream is a safe prune, but it is an optimisation, not the rule.
  5. Slice the stream rows back out and compute the attributed share by surface, stating that unattributed streams (resume, direct link, radio seed) are not a surface and belong in their own bucket.

Follow-up

  • The same item was rendered in two slates inside the window. Your tie-break picks one. What does that do to per-surface credit, and what would a fractional rule change?
  • How would you validate this against the impression_id already carried on fct_stream, and what would a systematic disagreement tell you?
  • At 2 million impressions and 500 thousand streams this fits in memory. What changes at 200 million?

Qualified hours per active account-week from its written definition

Easy · pandas · metric-definition · aggregation

You are given fct_stream as a pandas frame (stream_id, account_id, started_at in UTC, played_seconds, is_qualified) and dim_account (account_id, is_test_account), plus an as-of timestamp. Implement this metric exactly: the numerator is sum(played_seconds)/3600 over qualified streams started inside the window; the denominator is the count of distinct (account_id, ISO week) pairs with at least one qualified stream in that week; the window is the four most recent ISO weeks that are complete as of the given timestamp. Exclude test accounts. Return the scalar and the four per-week rows.

Approach

  1. Drop test accounts first, then filter to is_qualified. The denominator is defined on qualified streams, so filtering after grouping quietly lets an account-week in on the strength of an unqualified stream.
  2. Derive the ISO key with started_at.dt.isocalendar() and keep BOTH iso_year and iso_week. The week number alone collides every January and silently merges two different years of a week into one cell.
  3. Fix the window from the as-of timestamp rather than from max(started_at): a week is complete only when its Monday 00:00 UTC plus seven days is at or before the as-of instant, which is what excludes the partially observed current week.
  4. Aggregate once: sum played_seconds for the numerator, and take the number of unique (account_id, iso_year, iso_week) tuples for the denominator, not the number of unique accounts.
  5. Emit the four per-week rows as well, and confirm the scalar equals the account-week-weighted mean of the four weekly ratios.

Worked solution (20 min)

  1. Join is_test_account onto the stream frame, drop the test rows, and keep only is_qualified == True.
  2. Build iso_year and iso_week from started_at with .dt.isocalendar(), and a week_start timestamp (Monday 00:00 UTC) for the completeness test.
  3. Select the four distinct (iso_year, iso_week) keys with the largest week_start whose week_start + 7 days is at or before the as-of timestamp.
  4. Numerator: played_seconds.sum()/3600 over those weeks. Denominator: drop_duplicates on (account_id, iso_year, iso_week) and take the row count.
  5. Group by the ISO key for the four per-week rows (hours, account_weeks, ratio), and divide the totals for the scalar.

Expected result: One float equal to total qualified hours divided by the count of distinct (account_id, iso_year, iso_week) pairs, plus a four-row frame whose hours column sums to the numerator and whose account_weeks column sums to the denominator.

Verify it yourself

  • The scalar equals the account_weeks-weighted mean of the four weekly ratios, and does not equal their unweighted mean unless every week has identical account_weeks.
  • The denominator is at most four times the number of distinct qualified accounts in the window, with equality only if every such account streamed in all four weeks.
  • A stream started on 2025-12-30 lands in iso_year 2026, iso_week 1. If it lands in 2025 week 1, the year column was dropped somewhere.
  • Leaving test accounts in raises the numerator and the denominator together, so the ratio barely moves. Verify the exclusion on the two counts, not on the ratio.

Follow-up

  • A profile-level version of this metric reads lower per unit than the account-level one. Which would you use for a personalisation readout, and what does each unit actually aggregate?
  • Offline playback is uploaded in bulk days after it happened. What does that do to the most recent complete week, and how would you decide when a week is safe to publish?
  • How would this metric move if the qualification threshold rose from 30 to 60 seconds, separately for a short-form-heavy and a long-form-heavy catalogue?

Explain the difference between a merge sort and a quicksort. When would you use each?

Medium · sql and data manipulation

Approach

  1. Compute rates by summing numerator and denominator separately, never by averaging rates.
  2. Say which table is the grain you start from, and join outward from it.
  3. Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.

Follow-up

  • How would you verify this result without re-running the same query?
  • What breaks if events arrive late or out of order?

Weekly engaged accounts from qualified streams on distinct days

Easy · aggregation · active accounts · qualification threshold

fct_stream has one row per playback with account_id, started_at (UTC), played_seconds, is_qualified (true when played_seconds >= 30) and event_date, a date partition key derived from started_at. dim_account has account_id and is_test_account. Write one query returning, for the seven days ending 2026-03-31 inclusive, the count of weekly engaged accounts: distinct non-test accounts with at least one qualified stream on two or more distinct UTC dates inside that window. Return a single row. Count at the account level, not the profile level.

Approach

  1. Filter fct_stream on event_date BETWEEN '2026-03-25' AND '2026-03-31' and is_qualified = true. Filtering on started_at alone leaves the engine no partition to prune, so it reads every day the table holds; event_date is the partition key and is what belongs in the predicate.
  2. Drop test accounts before the date count, with a join or semi-join to dim_account on is_test_account = false. Excluding them afterwards is too late, because a test account that streamed on two days has already been counted as engaged.
  3. GROUP BY account_id and take COUNT(DISTINCT event_date) AS active_days. The distinct is the entire metric: an account with forty qualified streams inside one calendar day has one active day.
  4. Filter HAVING COUNT(DISTINCT event_date) >= 2, then wrap in an outer COUNT(*). The group-by has already made account_id unique, so an outer COUNT(DISTINCT account_id) adds a sort for nothing.
  5. Sanity-bound the answer before reporting it: it must be no larger than the count of distinct non-test accounts with any qualified stream in the window.

Worked solution (20 min)

  1. Compute the ceiling first: COUNT(DISTINCT account_id) over non-test accounts with any qualified stream in the window.
  2. Build a CTE of (account_id, COUNT(DISTINCT event_date) AS active_days) over the filtered rows.
  3. Select COUNT(*) from that CTE where active_days >= 2.
  4. Re-run the final filter at >= 1 and >= 3 to see the shape of the distribution and confirm the metric is not being carried by accounts sitting exactly on the boundary.

Expected result: A single integer. It must satisfy count(>=3) <= count(>=2) <= count(>=1), where count(>=1) is the ceiling computed in step one.

Verify it yourself

  • The three thresholds are monotone: raising the active-days requirement never raises the count.
  • Removing the is_test_account filter raises the count or leaves it unchanged, never lowers it.
  • No account_id appears more than once in the pre-aggregate CTE.

Follow-up

  • If you counted distinct dates per profile and then rolled up to the account, would the number rise or fall, and which unit does the metric actually want?
  • An account plays one 40-second track at 23:58 and another at 00:03. That is two distinct UTC dates and therefore engaged. Is that the intent, and what would you change if not?
  • Offline plays upload in bulk several days late with started_at backdated. Which part of this query silently changes when they land?

How do you prioritize tasks when working on multiple projects?

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Fix the population and the time window before naming any metric.
  3. Decompose the metric into the rates that drive it, and say which one you would check first.

Follow-up

  • Which segment would you cut first, and what would that rule out?
  • How would you detect that the metric is being gamed rather than genuinely improving?

Given a dataset of customer transactions, how would you identify potential areas for revenue growth?

Medium · product sense and metrics

Approach

  1. Fix the population and the time window before naming any metric.
  2. Restate the decision this analysis has to support, and who acts on the answer.
  3. Name one primary metric, then the guardrail that stops it being gamed.

Follow-up

  • Which segment would you cut first, and what would that rule out?
  • How would you detect that the metric is being gamed rather than genuinely improving?

How would you design an experiment to test a new feature for the Drivetime app?

Medium · a/b testing and experimentation

Approach

  1. Name the guardrails that would stop a launch even on a positive primary result.
  2. State the primary metric and the minimum effect worth shipping, then size the test.
  3. Say whether units interfere with each other, and switch design if they do.

Follow-up

  • What would you conclude if the result is positive but the test is underpowered?
  • How would you handle interference between treated and control units?

How do you ensure the validity of your statistical models?

Medium

Approach

  1. Clarify what is being asked and what a complete answer would contain.
  2. State your assumptions explicitly before working the problem.
  3. Work from the decision backwards to the evidence you would need.

Follow-up

  • How would you know your answer was wrong?
  • What assumption would you test first?

Read a test that won early and faded late

Medium · peeking · sequential testing · novelty effect

A ranker test was declared for 21 days at 80 percent power for a 1.0 percent lift in qualified hours per account-week, alpha 0.05 two-sided, with every eligible account ramped on day one. The team watched a daily dashboard. It crossed p < 0.05 on day 3 reading plus 2.9 percent, read plus 1.7 percent at p = 0.002 on day 9, and at day 21 reads plus 0.6 percent at p = 0.09. The same dashboard reports weekly slices of plus 2.1, plus 0.4 and minus 0.7 percent. Reconcile the cumulative readings against the slices and against the declared power before interpreting either, say what the day-21 p-value is worth given the daily looks, and say what you would run next.

Approach

  1. Reconcile the dashboard against itself before interpreting anything on it. With a day-one ramp, exposure is roughly flat across the window, so each cumulative estimate must be the day-weighted average of the slices beneath it, and the declared MDE pins the standard error at the horizon. Both the point estimates and the p-values are checkable arithmetic; a cumulative that does not match its own slices is computed on a different population and neither number is usable.
  2. Separate the arithmetic from the decision. Because the test ran to its pre-declared 21-day horizon and nobody stopped, the day-21 p-value is a valid fixed-horizon p-value needing no correction. What the daily looks damaged is the decision rule, not this number.
  3. Quantify what stopping would have cost. Under the null, repeated significance testing on accumulating data at alpha 0.05 gives a true error rate near 14 percent at five looks, 19 percent at ten and roughly 25 percent at twenty, so shipping on day 3 was a bet at those odds.
  4. Recognise the day-3 estimate as conditioned on having crossed. An effect read at the moment it becomes significant is selected for being large, so it is biased upward before any decay argument is made.
  5. Re-index the effect on days since each account's first exposure rather than on calendar date. Novelty appears as a per-account effect decaying with exposure age; a calendar decay that vanishes under re-indexing is a release or a mix shift.
  6. Separate novelty from primacy by tenure. Accounts created after the change never saw the old surface, so a genuine novelty effect is absent or much smaller in them, while primacy has the opposite sign and grows with exposure.
  7. Distinguish the cumulative from the steady state. A cumulative estimate over a decaying profile is an average of a launch effect the product delivers once and a post-novelty effect it delivers forever. Neither is the other, and the second is the one a ship decision needs.
  8. Conclude at the declared horizon: not significant at 0.05, a cumulative effect around plus 0.6 percent whose post-novelty component is not separable from zero, and any further looking requires an alpha-spending boundary fixed in advance.

Worked solution (25 min)

  1. Reconcile the cumulative readings against the slices. Day 9 = (7 * 2.1 + 2 * 0.4) / 9 = 15.5 / 9 = 1.72 percent, matching the reported plus 1.7. Day 21 = (2.1 + 0.4 - 0.7) / 3 = 0.6 percent, matching the reported plus 0.6. Back out the within-week-one profile too: days 1 to 3 at plus 2.9 forces days 4 to 7 to average (7 * 2.1 - 3 * 2.9) / 4 = 1.5 percent, so the per-day path is 2.9, 1.5, 0.4, minus 0.7, monotone decay.
  2. Reconcile the p-values against the declared power. 80 percent power for 1.0 percent at alpha 0.05 two-sided fixes the day-21 standard error at 1.0 / 2.802 = 0.357 percent, so z = 0.6 / 0.357 = 1.68 and p = 0.09. Scaling the standard error as 1 / sqrt(t) gives 0.545 percent at day 9 (z = 3.12, p = 0.002) and 0.944 percent at day 3 (z = 3.07, p = 0.002). Every reported number falls out of the design; none of them has to be taken on trust.
  3. Recompute the day-21 estimate outside the dashboard with one row per account and the pre-registered cap, and confirm plus 0.6 percent at p = 0.09 reproduces.
  4. Rebuild the series indexed on days since first exposure per account rather than calendar day, and plot the treatment effect against exposure age 1 to 21.
  5. Split the day-21 estimate by tenure at assignment: accounts created after the change versus accounts with 90 or more days of history.
  6. Check the release and rights calendar inside the window, and confirm the week-one lift is not one arm's share of a release landing.
  7. Estimate the steady state from the week-three slice alone: minus 0.7 percent with a one-week standard error of 0.357 * sqrt(3) = 0.618 percent, so z = minus 1.13 and p = 0.26. It is not separable from zero, and it is the quantity the follow-up must be powered on.

Expected result: Every reported figure reconciles: the cumulative readings are the day-weighted averages of the slices, and the p-values fall out of the declared 0.357 percent standard error at the horizon. The day-21 p = 0.09 therefore stands as a valid fixed-horizon test because the declared horizon was honoured, so the ship decision is no, and roughly 25 percent is the false-positive rate the team was exposed to across 21 daily looks. The 2.9 / 1.5 / 0.4 / minus 0.7 per-day path re-indexed on exposure age is the novelty signature. Powering a re-run for plus 0.6 percent needs (1.0 / 0.6)^2 = 2.78 times the sample, about 58 days, and is the wrong design: plus 0.6 percent is an average over a decaying profile, not an effect the product will keep delivering. Power the post-novelty slice instead. Reaching a 0.7 percent MDE on a one-week slice whose standard error is currently 0.618 percent needs (0.618 / 0.250)^2 = 6.1 times that slice's exposure, about 43 days of measurement after novelty has decayed, on top of a burn-in at least as long as the decay observed here.

Verify it yourself

  • Each cumulative reading must equal the exposure-weighted average of the slices beneath it, to within rounding. A gap means the cumulative and the slices are computed on different denominators or different populations, and the dashboard is reporting two incompatible experiments.
  • 1 / sqrt(t) is a floor on the standard error, because within-account correlation across days makes precision accumulate more slowly than independent sampling would. The reconstructed early z-scores are therefore upper bounds. If the dashboard's own error bars are tighter than 1 / sqrt(t) implies, it is treating account-days as independent observations.
  • Re-indexing on exposure age flattens a release-driven decay and preserves a novelty-driven one, but only if the ramp was staggered. With everyone exposed on day one, exposure age is collinear with calendar day and this cut cannot separate them; the tenure split is then the only available separation.
  • Accounts with no exposure to the old surface should show a smaller early lift than tenured accounts if novelty is real. Equal lifts in both argue against it.
  • An A/A run over the same 21 days should cross p < 0.05 at least once on roughly a quarter of replicates, which is the direct demonstration of the peeking rate rather than an argument about it.

Follow-up

  • Specify a boundary that lets the team look daily and still ship at 5 percent. What does an O'Brien-Fleming boundary cost in final-look MDE compared with a Pocock boundary?
  • The team proposes re-running the test powered for plus 0.6 percent. What is wrong with that target, and which quantity should the follow-up be powered on instead?
  • What would primacy look like on this dashboard, and which metric would register it first?

Slate click rate jumped overnight with no ranker change

Medium · pipeline-failure · rate-denominator · logging

Home-row click rate — was_clicked over rendered rows in fct_impression (impression_id, slate_id, surface, slate_position, rendered_at, viewport_visible_ms, ranker_version, was_clicked) — rose from 4.1% to 6.8% on a single day and held there. ranker_version is unchanged across the step. Streams attributed to home_row in fct_stream (impression_id, start_source, started_at) did not rise. Using impression and stream data only, find the cause and state what you tell the ranking team, who have already claimed the improvement in a review deck. Deliverable: root cause plus the correctly restated series.

Approach

  1. Ask which side of the ratio moved. A rate that steps while the downstream count is flat is almost always a denominator event, so plot clicks and impressions as separate absolute series before touching the ratio again. Do the arithmetic first as well: with the numerator fixed, a rate going from 4.1% to 6.8% pins the denominator to 4.1/6.8 of its former size, so you know the size of the impression loss to look for before you open the first query.
  2. If impressions fell, locate the fall: group by surface, slate_position band and viewport_visible_ms = 0. Loss concentrated in high positions and in never-visible rows is the signature of a client or collector dropping below-the-fold renders, which removes mostly non-clicked rows and lifts the rate arithmetically with no behaviour change.
  3. Prove rows are missing rather than never rendered. Left-join fct_stream rows with start_source = 'algorithmic_slate' and non-null impression_id back to fct_impression and count the ones that no longer resolve. Orphaned attributions date the breakage to the hour and are hard to argue with.
  4. Look at impressions per slate_id, and require it to reconcile with the rate step. A twenty-item row now logging twelve is a truncation bug in the renderer or collector, and it accounts for the loss exactly if the distinct slate_id count is flat; a stable per-slate count with fewer slates is a sampling or partition drop upstream. The two have different owners and different backfill stories, and any per-slate figure that implies a larger loss than the rate step requires means a second thing is also wrong.
  5. Restate the series on a basis the defect does not touch — clicks per slate_id, or the rate restricted to slate_position <= 8 where logging is intact — and take the dated evidence to the ranking team before the number reaches the review, not after.

Follow-up

  • Impressions in the truncated tail are missing for six days. Can an experiment that ran in that window still be read, and under exactly what assumption?
  • What monitor catches this within an hour, and what does it cost in false alarms on a normal release day?

Suggested practice checklist

Instead of guessing where the week should go, day one measures it under a fixed rubric and allocates the remaining hours in proportion to the gaps. The method is deliberately rigid: the allocation is written down before any studying starts and is not renegotiated when a topic turns out to be unpleasant.

Day 1 — Diagnostic, scored before you study anything

  • Sit a 100-minute timed diagnostic in four blocks: 30 minutes of SQL across three prompts, 25 minutes of short-answer statistics, 25 minutes on one modelling or case prompt, and 20 minutes delivering one behavioural story aloud.
  • Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct, and 0 is stuck, grading the output rather than how the attempt felt.
  • Allocate the hours for days two to five roughly in proportion to 3 minus the score in each block, write the allocation down, and commit to not revising it midweek.

Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.

Day 2 — Largest gap: find the boundary rather than the subject

  • Break the weakest area into five named sub-skills (for query work: grain control, window frames, date arithmetic, set logic with NULLs, and reading a query plan) and rate each one, so the rest of the week targets a sub-skill instead of a subject.
  • Solve three problems chosen to sit just above where the rating drops off, and for each write the first move you failed to make.
  • Re-solve one of them from memory four hours later, on paper, with nothing open.

Deliverable: A five-item sub-skill map with the two blocking sub-skills circled.

Day 3 — Largest gap: drill the blocking sub-skill

  • Do eight short repetitions of the same shape rather than eight different problems, so what you practise is the pattern and not the puzzle.
  • Write the rule you now hold in one sentence, then test it against a case built to break it: a ranking function over a column with ties, or a two-sample test on observations that are obviously dependent.
  • Have someone else read your one-sentence rule and find the precondition you left out.

Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.

Day 4 — Second gap, plus maintenance on your strongest area

  • Run the same sub-skill map and boundary protocol on the second-largest gap, compressed into half the day.
  • Spend 25 timed minutes on your strongest area to stop it decaying, choosing the hardest problem you can still finish rather than an easy warm-up.
  • Compare how the two areas fail: whether you lose time on recall, on setup, or on arithmetic, because the fix differs for each.

Deliverable: A second sub-skill map plus a one-line diagnosis of how each area fails you.

Day 5 — The gap that is not a skill

  • Record yourself answering one technical and one behavioural prompt, then count two things in the playback: how many seconds before your first clarifying question, and how many sentences you started without knowing where they ended.
  • Rewrite your three most-used stock phrases into shorter versions, and practise saying "I do not know, here is how I would find out" without softening it into a guess.
  • Deliver one answer again with a hard 90-second limit to force structure before detail.

Deliverable: Two recordings with a counted improvement in time-to-first-question.

Day 6 — Retest under day-one conditions

  • Sit the same 100-minute diagnostic structure with new prompts of comparable difficulty and score it on the identical rubric.
  • Compare block by block, and for any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
  • Write which single block you would still lose the offer on.

Deliverable: A second scored rubric placed next to the first, with one named remaining risk.

Day 7 — Full loop under interview conditions

  • Run a 60-minute mock covering the two blocks that moved least, with an interviewer instructed to interrupt and change direction.
  • Write your recovery script for the moment you go blank: restate the question, state your assumption, name the first thing you would check.
  • Reduce the week to the rule statements you wrote, each with its preconditions attached, then say every one of them out loud without reading it and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive being interrupted.

Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.

Explaining a method to someone who will not follow the maths

Half of this section is about translation. Be ready to describe how you explained a result to someone who did not want the method, only the implication, and what you did when the simplified version started being repeated in a way that overstated it. Correcting your own simplification is a strong beat.

Describe a challenging project you worked on. What was your role, and what was the outcome?

Medium · behavioural and stakeholder questions

Approach

  1. Quantify the outcome, including what you would not claim credit for.
  2. Pick a story where you drove the decision, not one where you observed it.
  3. Close with what you would do differently, concretely.

Follow-up

  • What did you decide not to do, and why?
  • What would you do differently if you ran that project again?

How do you approach conflict resolution within a team?

Medium · behavioural and stakeholder questions

Approach

  1. Quantify the outcome, including what you would not claim credit for.
  2. State the situation in two sentences and spend the rest on your reasoning.
  3. Close with what you would do differently, concretely.

Follow-up

  • What did you decide not to do, and why?
  • What would you do differently if you ran that project again?

Disagree with a product manager about a completion metric

Medium · disagreement · metric design · influence

A product manager proposes making duration-normalised completion rate the team's primary metric for the quarter, and wants a plain global unweighted version "so it's simple enough to put on a wall." You expect the unweighted version to move several points on catalogue mix alone, with no change in how satisfying anything was. You have one meeting, they own the roadmap, and you will work with them for years. Deliverable: the argument, the evidence you bring, and the fallback you accept if they still want the simple version.

Approach

  1. The probe is whether you can lose the decision without damaging either the metric or the relationship. Bring the failure already reproduced: recompute the unweighted global rate over the last two quarters and point at the weeks it moved several points where the only input that changed was which content people played.
  2. Decompose the variance instead of objecting. Attribute the movement in the unweighted rate to between-cell mix — (content_type, duration decile) — versus within-cell movement. A decomposition is an argument; an assertion that mix matters is a preference.
  3. Concede the real cost honestly: the mix-weighted version is harder to explain and harder to recompute. Bring the mitigation rather than dismissing the objection — weights fixed from a stated reference month, published once, so anyone can reproduce the number without redoing the weighting.
  4. Offer the fallback deliberately and in advance: ship both, with the unweighted rate labelled a diagnostic and the weighted one as the decision metric, and pre-agree the one observation that would mean the simple version has misled the team.
  5. Leave the decision with them, with the consequence written down before it happens. That is what makes a later correction a shared prediction coming true rather than a retrospective argument about who was right.

Follow-up

  • They ship the simple version and it moves four points during a heavy release week. How do you raise it without saying you told them so?
  • Is there a case where the unweighted rate is genuinely the right primary metric?
  • Suppose you are wrong and the mix effect turns out to be small. What would you change about how you argued this?