As a Data Scientist at Docusign, you will sit at the intersection of product, engineering, and business strategy, driving the analytical engine behind the world's leading agreement management platform. With over 1.5 million customers and more than a billion users globally, Docusign generates massive volumes of behavioral, telemetry, and transactional data. Your primary mission is to unlock the business-critical insights trapped within these systems to optimize customer journeys, build predictive machine learning models, and scale experimentation.
Depending on your team alignment—such as Growth Data Science or Core Data Science—your work will directly impact how the company retains, upgrades, and supports its massive user base. For instance, in a growth-focused role, you will design the self-serve retention engine, translating product telemetry and customer intent into proactive interventions that prevent active and partial churn. In a core product role, you will build machine learning pipelines and develop new testing methodologies to scale experimentation across different product lines.
This position is highly collaborative and carries significant strategic weight. You will not work in a silo; instead, you will partner closely with product managers, lifecycle marketers, engineers, and senior leadership. The insights you generate and the models you deploy will directly shape Docusign's product roadmap and go-to-market execution, making this an exceptionally high-impact role for analytical professionals who want to see their work translate into measurable revenue and retention outcomes.
Recruiter Screen
reportedData Scientist covers at least four different jobs: experimentation, product analytics, causal work on observational data, and applied modelling that ships into a system. A screening call is the cheapest place to find out which of them is being hired for, and doing that diagnosis openly reads as senior rather than fussy. Ask what the last few pieces of work on the team actually were, and roughly how a week splits between querying, modelling and stakeholder time. Then say which parts of that you have done and which you have not. Claiming the whole range is the fastest way to be caught one round later.
What to demonstrate
- Whether you can distinguish the flavours of the role and locate your own experience inside one of them honestly
- Whether you name what you have not done instead of stretching to cover every line of the posting
- Whether your hard constraints (notice period, location, work authorisation, level) surface now rather than at offer stage
How to prepare
- Map the last two years of your time into rough percentages across query writing, experiment design, modelling and stakeholder work, so a question about scope has a real answer
- Mark every responsibility in the posting as done, adjacent or new, and prepare one sentence for each adjacent item naming the closest thing you have actually built
- Decide which logistics are non-negotiable before the call so you can state them in one sentence rather than negotiating live
Technical and Hiring Manager Assessment
reportedMuch of this round runs on your own history, but the manager is not collecting a project list. They are working out what it is like when something goes wrong on your watch: how late the bad news tends to arrive, and whether a number you hand over has been checked by anyone including you. That is why the strongest material is a project where you can describe the part that did not work and what it cost. A result you cannot take full responsibility for, however clean, gives them nothing to trust you with afterwards.
What to demonstrate
- Whether you volunteer the limits of a result you are proud of, or wait to be pushed onto them
- How errors surfaced in your past work, and whether you or somebody else found them
- Whether the scope you claim matches the level of detail you can still produce about it
- What you did the first time a stakeholder acted on something of yours that turned out to be wrong
How to prepare
- Rebuild one headline figure from memory down to the join and the filter, so a question about the denominator does not stall the conversation
- For each project you raise, write the sentence you would say to someone who had already acted on a number that later turned out wrong
- Mark which parts of a project were yours and which belonged to other people, and state that boundary yourself before anyone asks
Comprehensive Panel Loop
reportedWhere a loop ends with a senior leader, that conversation is rarely another skills test. The technical signal already exists by then, so the questions tend to open up: what you would look at first, where a metric you have heard about could mislead, what you would push back on. The decision being made is scope, which in practice means level and how much you would be trusted to own unsupervised. Treating it as a formality is the usual mistake. An open question late in the day is still being scored, and a vague answer reads as someone who has not run anything themselves.
What to demonstrate
- Whether your view of the business has anything specific behind it, given that you are working only from what is public and are expected to say so
- Whether the scope of work you describe owning matches the scope of the role, instead of sitting a level below it
- Whether you can disagree with something concrete and stay useful about it, rather than agreeing with everything said in the room
- Whether your questions are ones only this person could answer, as opposed to ones the recruiter already covered
How to prepare
- Build one view you could defend for two minutes using only public information: what the funnel probably looks like, which metric likely drives decisions, and where that metric could mislead. Being wrong for a stated reason survives this round; having no view does not
- Write down the largest piece of work you have owned from question to decision, who else touched it, and what you decided alone, then check that it reads at the level you are interviewing for
- Prepare one thing you would want changed if you joined and phrase it as a question rather than a verdict, so it opens a conversation instead of closing one
8 candidate reports. Individual accounts describe a particular role and hiring cycle.
Docusign Account Executive interview with multiple presentations
I went through an Account Executive hiring process that felt average to difficult. It dragged on for months, with several rounds, shifting timelines, and a lot of work for the candidate. The early recruiter conversations seemed promising. I then had additional interviews with hiring managers, followed by separate presentations that I had to prepare and deliver. Those presentations took substantia…
Read full experienceDocusign Account Executive interview focused on a predefined career path
I went through an Account Executive process where the hardest part was the team's consistent focus on specific career-path assumptions and alignment with its sales narrative. In the recruiter screen, I discussed my background and career goals, but the recruiter's expectations were closely tied to a predefined SDR to MDR to AE storyline. In later conversations with managers and leads, I discussed…
Read full experienceAccount Executive interview at Docusign: Post-interview feedback
I had a short, professional interview experience for an Account Executive-related role. It felt easy and respectful, with clear communication and feedback after the interview. I first spoke with HR in a professional online conversation. Then I had a role discussion with an interviewer who was welcoming and set a good tone for the process. Afterward, even though I didn't get the offer, I received…
Read full experienceDocusign Software Engineer interview: API script and HackerRank-style exercises
My process was shorter and heavily front-loaded. It began with a quick recruiter screen, then moved into a panel-style technical evaluation. The questions covered coding and system design, and nothing felt wildly unexpected. They were standard areas they wanted to see me handle calmly. The process continued in a way that felt somewhat drawn out but still organized. I had four interviews in total,…
Read full experienceDocusign Software Engineer interview: hour-long whole-team coding rounds
I had a team-manager kickoff and then moved into a whole-team round with several people interviewing me back-to-back. The scheduling details suggested that each team member would take about 30 minutes, but in practice each conversation lasted closer to an hour. That changed the pacing of the day. The technical conversations focused mainly on coding. Because they ran long, I had fewer natural brea…
Read full experiencePracHub editorial advice for the preparation topics above.
Randomising an experiment at the user level when users share an account
Two problems fire at once. Colleagues in one workspace see each other's work and talk to each other, so a treated user changes the behaviour of a control user in the same account, which violates the no-interference assumption and biases the estimate toward zero. Separately, outcomes within an account are strongly correlated, so the effective sample size is roughly n / (1 + (m - 1) * rho) for m users per account and intra-class correlation rho, not n. With rho around 0.3 and twenty users per account that is a design effect near 6.7, meaning a user-level confidence interval is about two and a half times narrower than it should be and results cross significance thresholds on noise alone. Randomise the account and cluster the standard errors.
Reading consumption metrics before the metering lag window has closed
Usage pipelines land late and correct themselves, which is exactly what is_restated and restated_at record. A dashboard queried on day T sees a partially populated tail for the last several days, so the most recent points always slope downward and always look like a regression. Analysts then explain the artefact, and sometimes ship a change to fix it. Establish the empirical settling time by measuring how much a given usage_date's total moves between first_written_at and its final value, exclude that many trailing days from every reportable figure, and never compare a fresh period against a settled one.
Explaining an aggregate move without decomposing the mix shift
Split the change in the aggregate into within-segment movement and movement in segment weights before you explain it. Every segment's rate can fall while the overall rate rises, purely because volume shifted toward segments that already had higher rates.
Dropping rows with missing values without naming the mechanism
Say whether the values are missing at random, missing by a known process, or missing in a way that depends on the outcome, and handle them accordingly. Deleting incomplete rows silently redefines the population whenever missingness correlates with what you are measuring.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Explain the difference between linear regression and logistic regressi…
Explain the difference between linear regression and logistic regression, and describe a scenario where you would use each.
Approach
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Set a baseline first, so any model has something honest to beat.
- Pick an evaluation metric that matches the cost of each error type, not a default.
Follow-up
- How would you choose the decision threshold, and who owns that choice?
- What would you monitor after launch to know the model is still valid?
Audit daily usage rows for grain and arithmetic violations
You are handed fct_usage_daily as a pandas DataFrame with account_id, workspace_id, sku_code, usage_date, billable_quantity, included_quantity_applied, overage_quantity, list_amount_cents, discount_amount_cents, net_amount_cents, cogs_cents, is_restated, first_written_at and restated_at. The declared grain is one row per (account_id, workspace_id, sku_code, usage_date). Write audit(df) returning a DataFrame with one row per failing check: check name, failing row count, and one example key. Cover at minimum grain duplication, negative quantities or amounts, the identity net = list - discount, billable = included + overage, and rows where is_restated is true but restated_at is null.
Approach
- Check the grain before anything else with df.duplicated(subset=key, keep=False), and count rows rather than groups so a key appearing twice contributes 2 — if the grain is broken every arithmetic count below it is uninterpretable.
- Express each invariant as a boolean Series over the whole frame. The cent columns are integers and compare exactly, so use !=; the numeric(18,6) quantity columns need np.isclose with atol=1e-6 because included + overage is a decimal sum.
- Handle null as its own failure mode. Comparisons against NaN return False, so a check written as rows_that_pass = (a == b - c) silently files every null-amount row wherever the negation happens to land; build each check as violations = ~condition | column.isna().
- Collect the checks as a list of (name, mask) pairs and assemble the output in one pass, so adding a check is one line and every check reports in the same shape.
- Order the output with structural failures (grain, null keys) above arithmetic failures, and report zero-count checks too — a check that silently disappears when it passes is indistinguishable from a check that was never run.
Follow-up
- Which of these should block a dashboard refresh and which should only warn?
- Rows with is_restated = true legitimately change value after first write. How do you make yesterday's audit result reproducible?
- How would you extend this to catch a partition that is missing entirely rather than wrong?
Quantify billable volume created by retries after server errors
From fct_api_request (request_id, account_id, endpoint, idempotency_key, is_retry, http_status, request_at, billable_units), measure how much billable volume in a 28-day window is retry traffic that followed a 5xx. Group requests into attempt chains by (account_id, endpoint, idempotency_key) ordered by request_at; a request is error-driven if any earlier attempt in its chain returned 5xx. Requests with a null idempotency_key cannot be chained, so report them as their own class rather than assuming each is unique. Return billable_units split into first-attempt, error-driven retry, other retry and unchainable, per account.
Approach
- Split the population before measuring anything. A null idempotency_key is not a chain of one, it is an unknown; report its share of billable_units first, because if it is 40% of volume then the headline estimate is a lower bound and the deliverable has to say so.
- Within chainable rows, sort by (account_id, endpoint, idempotency_key, request_at) and derive 'any earlier attempt failed' with arithmetic rather than a per-group lambda: with is5 = (http_status >= 500), the per-chain cumsum minus the row's own value is positive exactly when an earlier attempt in that chain returned 5xx. A groupby-apply gives the same answer and is unusable at five million rows.
- Do not take is_retry as the definition. It is set by the client whenever an idempotency_key is resent, which covers retries after client-side timeouts and after 4xx as well; compute the flag yourself and then cross-tabulate it against is_retry, because the disagreement is a finding in its own right.
- Aggregate billable_units by (account_id, class) and assert the classes sum to each account's total. The spine sets billable_units to zero on 5xx responses, so the failed attempt contributes nothing and the whole inflation sits in the successful retry that follows it.
- Report the per-account share and look at its distribution, not the fleet total. One account in a retry storm dominates any blended figure, which is the same failure that makes a fleet-wide error rate useless.
Worked solution 40 min
- unchainable = df.idempotency_key.isna(); report df.loc[unchainable].groupby('account_id').billable_units.sum() before proceeding.
- keys = ['account_id','endpoint','idempotency_key']; c = df[~unchainable].sort_values(keys + ['request_at'], kind='mergesort'); c['is5'] = (c.http_status >= 500).astype(int)
- c['attempt_no'] = c.groupby(keys, sort=False).cumcount(); c['prior_5xx'] = (c.groupby(keys, sort=False).is5.cumsum() - c.is5) > 0
- c['cls'] = np.where(c.attempt_no == 0, 'first_attempt', np.where(c.prior_5xx, 'error_driven_retry', 'other_retry')); out = pd.concat([c, df[unchainable].assign(cls='unchainable')]).groupby(['account_id','cls']).billable_units.sum().unstack(fill_value=0)
Follow-up
- An account's error-driven share is 22%. Is that the platform's fault or the client's, and what do you look at next?
- How would you define a consumption-based north-star metric that an outage cannot inflate?
- Chains straddle the 28-day boundary. How large is that bias and in which direction?
Walk me through a complex SQL query you wrote recently. How did you op…
Walk me through a complex SQL query you wrote recently. How did you optimize it for performance?
Approach
- State the window function and its partition and ordering out loud before writing it.
- Compute rates by summing numerator and denominator separately, never by averaging rates.
- Say which table is the grain you start from, and join outward from it.
Follow-up
- How does the query change if the join becomes one-to-many?
- How would you verify this result without re-running the same query?
Find paid seats that never called the API
dim_user_membership carries user_id, account_id, seat_type, is_service_account, deactivated_at and last_seen_at. fct_api_request carries user_id, which is null whenever the caller is a service account or an unattended key, plus account_id, request_at and http_status. For a single account, list every licensed_paid seat with is_service_account = false and deactivated_at null that issued no request at all in the trailing 90 days, returning user_id and last_seen_at. A first draft writes NOT IN against a subquery over fct_api_request.user_id. State exactly what that draft returns and why, then write the correct query.
Approach
- Read the column comment first: user_id is nullable on the fact, so the subquery almost certainly contains at least one NULL for any account that runs a service account or an unattended key.
- Work the three-valued logic out loud. x NOT IN (a, NULL) expands to NOT (x = a OR x = NULL); the second disjunct is UNKNOWN, so for any x not equal to a the whole predicate is UNKNOWN and the row is filtered out. The draft returns zero rows, which reads as full seat utilisation.
- Rewrite as NOT EXISTS with the 90-day and status predicates inside the correlated subquery. Putting them in the outer WHERE instead turns the anti-join into a different question and silently changes the answer.
- Correlate on both user_id and account_id. A membership is (user_id, account_id) and one person can hold memberships in several accounts, so correlating on user_id alone marks a seat as active because that human was busy somewhere else.
- Filter the seat side to seat_type = 'licensed_paid', is_service_account = false and deactivated_at IS NULL, and say what the resulting count means next to contracted_seats on the current subscription row.
Worked solution 15 min
- Confirm the hazard with one query: SELECT count(*) FROM fct_api_request WHERE user_id IS NULL AND account_id = :account_id. Any non-zero result proves the draft returns nothing.
- Write the seat side: SELECT user_id, last_seen_at FROM dim_user_membership WHERE account_id = :account_id AND seat_type = 'licensed_paid' AND NOT is_service_account AND deactivated_at IS NULL.
- Attach AND NOT EXISTS (SELECT 1 FROM fct_api_request r WHERE r.user_id = m.user_id AND r.account_id = m.account_id AND r.request_at >= now() - interval '90 days').
- Compare the row count against the same query written as a LEFT JOIN with a WHERE r.user_id IS NULL; the two must agree exactly.
- Divide the active seat count by contracted_seats from the account's current fct_subscription_period row and state the utilisation figure.
Follow-up
- Adding AND user_id IS NOT NULL to the subquery also fixes NOT IN. Why is NOT EXISTS still the form you would leave in the repository?
- last_seen_at looks like a shortcut for the whole query. What does it actually record, and where does it disagree with API activity?
- This is a seat-reduction risk list. What threshold would you attach before handing it to an account team, and what happens to seats below it?
How would you design a predictive model to identify customers at high …
How would you design a predictive model to identify customers at high risk of active churn? What features would you prioritize?
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Name one primary metric, then the guardrail that stops it being gamed.
- Restate the decision this analysis has to support, and who acts on the answer.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- Which segment would you cut first, and what would that rule out?
Explain the concept of causal inference and how you would apply it to …
Explain the concept of causal inference and how you would apply it to understand the impact of a product feature on customer retention.
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Name one primary metric, then the guardrail that stops it being gamed.
- Restate the decision this analysis has to support, and who acts on the answer.
Follow-up
- How would you detect that the metric is being gamed rather than genuinely improving?
- Which segment would you cut first, and what would that rule out?
Imagine you are analyzing customer behavior across three entirely diff…
Imagine you are analyzing customer behavior across three entirely different industries (e.g., Healthcare, Real Estate, and Finance). How would you segment these users to understand their unique agreement workflows?
Approach
- Fix the population and the time window before naming any metric.
- Restate the decision this analysis has to support, and who acts on the answer.
- State what result would change your recommendation, so the answer is falsifiable.
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?
If a key metric like user engagement suddenly drops by 10% week-over-w…
If a key metric like user engagement suddenly drops by 10% week-over-week, what is your step-by-step framework to investigate the root cause?
Approach
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Fix the population and the time window before naming any metric.
- Restate the decision this analysis has to support, and who acts on the answer.
Follow-up
- How would you detect that the metric is being gamed rather than genuinely improving?
- What would you do if the primary metric and the guardrail moved in opposite directions?
What metrics would you track to ensure a lifecycle marketing experimen…
What metrics would you track to ensure a lifecycle marketing experiment is successful without causing negative downstream effects?
Approach
- Say whether units interfere with each other, and switch design if they do.
- Name the guardrails that would stop a launch even on a positive primary result.
- Name the randomisation unit first; it decides the variance and what the test can detect.
Follow-up
- What would you conclude if the result is positive but the test is underpowered?
- What would you do if you could not randomise at all?
How would you design an A/B test to evaluate a new cancel-save flow fo…
How would you design an A/B test to evaluate a new cancel-save flow for self-serve customers?
Approach
- State the primary metric and the minimum effect worth shipping, then size the test.
- Decide the analysis before seeing data, including how long it runs and when you look.
- Name the guardrails that would stop a launch even on a positive primary result.
Follow-up
- How would you handle interference between treated and control units?
- What would you do if you could not randomise at all?
Set the operating point for a capacity-bound renewal-risk worklist
A customer-success team of six can contact at most 40 accounts a week. You have an account-level renewal-risk score and the tables behind it: fct_subscription_period (account_id, term_end_date, arr_cents, amendment_type, booked_at, is_current), fct_support_ticket (account_id, severity, reopened_count, breached_sla, linked_incident_id, opened_at) and fct_api_request. Define the metric that grades this worklist, set the operating point, and state what happens to accounts below the line. The team will not use a score they cannot explain, so say how that constrains what you build.
Approach
- Grade the list the way it is used. The team works 40 accounts a week, so the metric is precision at k = 40, not AUC. A global AUC over thousands of accounts rewards correct ordering among accounts nobody will ever call, which is ordering that cannot change an outcome.
- Restrict the candidate pool before ranking anything: accounts whose term_end_date falls within the next 90 days. An account eleven months from renewal cannot churn in the measurement window, so it can occupy a slot in the list while being structurally incapable of producing the outcome.
- Report two numbers because they disagree. Precision at 40 counts accounts; ARR captured at 40 counts money. A list that catches many small churns and misses one large one scores well on the first and badly on the second, so state which the team is optimising before the ranking is built.
- Audit leakage by timestamp, feature by feature. Every feature must carry a timestamp proving it existed before the scoring date: a downgrade amendment's booked_at, a ticket's opened_at, a churn reason code written at close. Drop anything you cannot date, and be specific that reason codes and cancellation amendments are written after the renewal conversation started.
- Attach a policy to the threshold, because a threshold without one is not a decision. Accounts ranked 41 and below get no contact this week; that is an accepted cost, and the weekly readout must include the churn that landed below the line so the operating point can be revisited rather than assumed. Favour a small inspectable model, because a stronger model the team ignores has an effect of zero.
Worked solution 30 min
- Build the weekly candidate set: accounts from the current fct_subscription_period version whose term_end_date falls within 90 days of the scoring date.
- Assemble features only from rows timestamped before the scoring date: trailing 28-day 5xx rate and successful production request volume from fct_api_request, sev1 and sev2 ticket counts plus reopened_count from fct_support_ticket filtered on opened_at, and seat utilisation from the contract version current at that date.
- Label the outcome as the absence of a successor fct_subscription_period row with amendment_type in ('renewal','upsell','downgrade') within 45 days of term_end_date.
- Backtest week by week: take the top 40, and report precision at 40, ARR captured at 40, and the churned ARR that landed below rank 40.
Follow-up
- Coverage is assigned by this list, so contacted and uncontacted accounts differ systematically in exactly the risk signal that drives the outcome. How would you ever measure whether the outreach worked?
- Annual contracts produce few churn events per quarter. At what point is the honest answer that there is not enough signal to model this, and what would you deliver instead?
Weekly active organisations fell nine percent over one week
A dashboard reports the weekly active organisation ratio on a trailing seven-day window ending each Wednesday. This week it reads nine percent below last week. You have fct_api_request (account_id, environment, traffic_class, http_status, request_at) and dim_account (account_id, billing_country, account_status, is_internal, is_current). Nothing was released. Decide whether usage actually fell, and hand back a corrected series plus a one-paragraph explanation that a non-analyst can repeat without you in the room.
Approach
- Count the holiday-free business days inside each window before comparing them. A trailing seven-day window spans exactly five weekdays wherever it ends, so its business-day count can only fall to four or fewer when a public holiday lands inside it and can never reach six, while usage in this domain follows a hard five-to-two weekday cycle. Two windows holding different numbers of business days are not comparable whatever the product did.
- Count distinct active accounts per calendar day for the last ten weeks and overlay the two windows. A calendar problem shows as a small number of weekdays sitting at weekend level, not as every day being uniformly lower.
- Cut the daily series by billing_country and index each country-day to that country's trailing same-weekday median, which isolates a regional public holiday from a product change.
- Check the denominator on its own: the metric divides by accounts whose account_status was in trial, free or active_paid for the whole week, so a batch suspension or status backfill moves the ratio with no change in the numerator at all.
- Report the series with each window's business-day count and the holiday dates annotated beside it, and state the residual week-over-week change that survives once the calendar effect is removed. Compare against earlier windows holding the same number of business days rather than dividing by business days, since distinct-account counts are sublinear in window length and dividing would over-correct.
Follow-up
- Distinct account counts are sublinear in the number of days in the window. Why does losing one of five business days reduce the count by noticeably less than twenty percent?
- How would you make this metric comparable across countries with different holiday calendars without hand-maintaining a holiday table forever?
For someone who has spent the last year in notebooks, dashboards or modelling work and has not written raw SQL under time pressure. The first four days rebuild query fluency against a fixture you control and can verify by hand; the last three attach that fluency to the rest of the loop.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Build a fixture you can check answers against
- Create a local Postgres or SQLite database with four tables (users, sessions, events, orders) holding roughly 200 rows you generated yourself, so you know the contents well enough to predict every result.
- Deliberately seed the cases that break queries: a user with no sessions, a session with no events, two orders sharing a timestamp, a NULL in one join key, and one duplicated user row.
- Before writing any SQL, hand-compute five answers on paper (how many users placed at least one order, median orders per ordering user, and three others) and save them as the ground truth for the week.
Deliverable: A one-command seed script plus a text file of five hand-computed answers to grade every later query against.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Joins, filters and NULL semantics
- Answer "which users have no orders" three ways (LEFT JOIN with IS NULL, NOT EXISTS, NOT IN) and confirm that the NOT IN version returns zero rows once the subquery contains a NULL, because the comparison is never TRUE.
- Reproduce the LEFT JOIN that silently collapses to an inner join by putting a right-table predicate in WHERE, then fix it by moving the predicate into the ON clause, and record both row counts.
- Create a fan-out bug on purpose by joining orders to order_items and summing the order total, then correct it with a pre-aggregated subquery and explain in one line which table changed the grain.
Deliverable: One annotated .sql file holding the three join traps, each with the wrong result and the corrected result side by side.
Practice prompt ↗Practice prompt ↗Practice prompt ↗03Window functions and frames
- Write three window queries against the fixture: a running order total per user, the rank of each order within its user by value, and the day gap to that user's previous order, then check each against the day-one ground truth.
- Run ROW_NUMBER, RANK and DENSE_RANK over a column containing ties, print all three side by side, and write one sentence on when each is the correct choice.
- Switch one query from the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, which is what you get when ORDER BY is present and no frame is written) to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and explain why the output differs only when the ORDER BY column has duplicates.
Deliverable: Three verified window queries plus a short note explaining the RANGE versus ROWS difference in your own words.
Practice prompt ↗Practice prompt ↗04The four analytical query patterns
- Write a monthly retention grid: first order month per user, then months-since-first as the column, and verify that month zero equals the cohort size exactly.
- Sessionize the events table under a 30-minute inactivity rule using LAG plus a cumulative sum over a new-session flag.
- Build a four-step funnel that counts distinct users rather than events at each step, and state the rule you applied to a user who reaches step three without ever logging step two.
Deliverable: One file with the retention, sessionization and funnel patterns, each carrying a one-line note on the assumption it bakes in.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Write SQL the way you will have to write it live
- Set a 12-minute timer and solve three medium prompts in a plain editor with no execution and no autocomplete, then run them and tally syntax errors separately from logic errors.
- Narrate one solution aloud while writing it, stating the grain of each intermediate result (one row per user, one row per user-day) before you type its body.
- Rewrite your slowest solution as a CTE chain where every CTE name states its grain, and time yourself re-solving it from blank.
Deliverable: A recording of one narrated solution plus an error tally that separates syntax from logic.
Practice prompt ↗Practice prompt ↗06One day for everything that is not SQL
- Write the preconditions of the two-sample t-test from memory, then check them: independent observations, and a difference in means whose sampling distribution is approximately normal, which at large sample sizes follows from the central limit theorem rather than from normality of the raw values.
- Write the difference between an odds ratio from logistic regression and a relative risk, and state the condition under which the two are close (low outcome prevalence).
- Prepare a 90-second answer to "how would you know this model is any good" that names the metric, the baseline you would beat, and the cost of the errors you care about.
Deliverable: One page of notes covering test preconditions, the odds-ratio caveat and the model-quality answer.
Practice prompt ↗Practice prompt ↗07Full loop rehearsal
- Run a 45-minute mock with someone willing to interrupt: 20 minutes of SQL, 15 minutes defining a metric, 10 minutes on a past project.
- Re-solve from blank the two queries you were slowest on this week and compare the times against day five.
- Write a five-line answer to "walk me through a project" that puts a number in the first sentence and names the decision the work changed.
Deliverable: Mock feedback notes plus a timed project narrative you can deliver without reading it.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Work that nobody used is a common and unflattering pattern in data careers, and interviewers probe for it. Have a story about an analysis that changed a decision, and be specific about how you got it in front of the person who could act. Also have one about work that went nowhere, with your reading of why.
Walk me through your resume and highlight a project where your analyti…
Walk me through your resume and highlight a project where your analytical insights directly influenced a strategic product decision.
Approach
- Close with what you would do differently, concretely.
- Quantify the outcome, including what you would not claim credit for.
- State the situation in two sentences and spend the rest on your reasoning.
Follow-up
- What would you do differently if you ran that project again?
- What did you decide not to do, and why?
Allocate one analyst week across three competing requests
Three requests arrive the same morning and you have one week. Finance wants per-account gross margin from fct_usage_daily for a pricing review in three weeks. Sales wants a renewal-risk list for accounts with term_end_date inside 60 days. A product manager wants an experiment readout for a decision being taken on Thursday. Produce your allocation with hours attached, what you say to whoever receives less, and one thing you refuse to do this week, with the reason each decision is defensible to the person it costs.
Approach
- The interviewer is probing whether you prioritise on decision timing and reversibility or on who asked most forcefully. Sort by the date each decision is actually taken and by what the default outcome is if nothing arrives.
- Apply that sort concretely. The Thursday readout has a hard irreversible deadline and no value afterwards. The pricing review has three weeks of slack. The renewal list has a rolling deadline set by term_end_date, so part of it is urgent this week and the rest is not, which means it can be split rather than deferred whole.
- Find the cheapest sufficient version of each request rather than the full version. The readout goes in full. The renewal list ships as a filtered query over renewal-eligible accounts ranked by two inspectable signals rather than as a model. The margin work is scoped to the accounts that dominate the pricing decision, since revenue is heavily skewed and the tail will not change the conclusion.
- Make the trade visible in one written note to all three at once, with dates. Telling each person separately that they are the priority is how an allocation becomes a credibility problem.
- Refuse something explicitly and say why. The model version of the renewal list is the usual candidate, because it cannot be evaluated without a holdout nobody has agreed to yet, and building it this week forecloses that.
- Leave slack. A plan with none is a plan to miss the one deadline that cannot move.
Follow-up
- The sales leader escalates to your manager. What did you already do that makes that a short conversation?
- Which of the three deadlines would you push back on, and what exactly would you ask for?
- What would you change about how these requests reach you so next week is not the same?
Scope an open-ended request to predict account churn
A customer success director asks for a list of accounts about to churn. You know only that the team has six people and that contracts are annual. Available data is fct_subscription_period, fct_usage_daily, fct_api_request, fct_support_ticket and dim_account. Before writing any code, produce the questions you need answered, a proposed definition of about to churn, and the shape of the artefact you would hand back, including the operating point that turns a score into a decision.
Approach
- The interviewer is probing whether you convert a vague request into a decision with a capacity constraint attached. A candidate who starts talking about model families has already failed the exercise.
- Pin the event and the horizon first. Churn is only possible at term_end_date, so the population is accounts renewing in the next 60 to 90 days, not the whole base. Ask explicitly whether contraction and downgrade count as churn or only full non-renewal, because the three have different base rates and different interventions.
- Pin the action and the capacity. Six people times a realistic number of meaningful interventions per week gives k, and k is what the list is ranked to. Evaluate on precision at k rather than a global AUC over accounts that will never be contacted.
- Audit leakage before choosing features. Every feature needs a timestamp proving it existed before the prediction date. A downgrade amendment, a churn reason code, and a ticket opened after the renewal conversation started are all leaks that will make the offline number look excellent and the live list useless.
- Ask for the counterfactual now rather than later. Coverage is assigned deliberately, so without a held-out slice agreed at the start the intervention can never be evaluated, and you will be asked for its impact in nine months regardless.
- Propose the smallest artefact that closes the loop: a weekly ranked list sized to capacity with two or three inspectable reasons per row, plus a stated policy for accounts below the line.
Follow-up
- The director insists all accounts are in scope, not only those renewing soon. How do you answer without simply refusing?
- Historical non-renewals number about 30 a year. At what point do you tell them a model is the wrong tool and a rules list is better?
- Which candidate features would you drop purely because you cannot date them?
- 01
Walk me through your resume and highlight a project where your analytical insights directly influenced a strategic product decision.
- 02
Three requests arrive the same morning and you have one week. Finance wants per-account gross margin from fct_usage_daily for a pricing review in three weeks. Sales wants a renewal-risk list for accounts with term_end_date inside 60 days. A product manager wants an experiment readout for a decision being taken on Thursday. Produce your allocation with hours attached, what you say to whoever receives less, and one thing you refuse to do this week, with the reason each decision is defensible to the person it costs.
- 03
A customer success director asks for a list of accounts about to churn. You know only that the team has six people and that contracts are annual. Available data is fct_subscription_period, fct_usage_daily, fct_api_request, fct_support_ticket and dim_account. Before writing any code, produce the questions you need answered, a proposed definition of about to churn, and the shape of the artefact you would hand back, including the operating point that turns a score into a decision.
Is this an official Docusign interview guide?
No. It is PracHub's own research and practice material for the Data Scientist role at Docusign. Rounds and questions reflect what candidates have reported, not a process Docusign has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗What is the hybrid work policy for Data Scientists at Docusign?
Docusign operates on a hybrid model. Employees are generally expected to divide their time between remote work and their designated office location, with a minimum expectation of being in-office 2 days per week.
PracHub interview research ↗How technical is the interview process for Growth versus Core Data Science teams?
While both teams require strong SQL and Python skills, the Growth team places a heavier emphasis on A/B testing, causal inference, and SaaS business metrics. The Core team tends to focus more deeply on machine learning engineering, predictive modeling pipelines, and software development lifecycle practices.
PracHub interview research ↗How can I stand out during the behavioral rounds?
Focus on demonstrating your business impact. The best candidates do not just explain *what* analysis they did, but *how* that analysis changed the product roadmap, saved revenue, or influenced executive decision-making. Use the STAR method (Situation, Task, Action, Result) and quantify your achievements.
PracHub interview research ↗What should I do if an interviewer challenges my technical choices or past experience?
Remain calm and treat it as a collaborative discussion rather than an interrogation. Clearly explain the constraints you operated under in your previous role, walk through the trade-offs of your decisions, and show that you are receptive to feedback and alternative methodologies.
PracHub interview research ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-22 - 02PracHub Data Scientist practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-22 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-22