DoorDash Staff Full-Stack Developer Interview Preparation Guide
DoorDash's interview process for Staff Full-Stack Engineers typically includes an initial recruiter screening, followed by technical phone screens, and onsite rounds consisting of coding/algorithms assessments, system design interviews, behavioral evaluation, and specialized rounds (such as incident investigation or architecture reviews). The process is designed to evaluate deep technical expertise, system thinking, project ownership capability, mentorship potential, and cultural fit. Staff-level candidates are expected to demonstrate mastery across full-stack technologies, architectural decision-making, and the ability to drive technical initiatives across teams.
Interview Rounds
Recruiter Screening
What to Expect
Initial conversation with a recruiter to verify background, experience level, and interest. Includes discussion of your career progression, major projects, team leadership experience, and technical depth. At Staff level, recruiters will probe into how you've influenced technical strategy, mentored senior engineers, and driven cross-team initiatives. They assess fit for Staff-level scope and confirm you understand the technical bar.
Tips & Advice
Clearly articulate your technical leadership journey and the scope of impact you've had. Use specific metrics or outcomes from projects you've led. Explain why you're seeking a Staff role at DoorDash and what attracts you to their technical challenges. Be ready to discuss previous roles and how each built toward Staff-level skills. Prepare a brief narrative of a complex technical decision you made that benefited the business or team.
Focus Topics
Mentorship and Enabling Others
Share concrete examples of how you've mentored mid-level or senior engineers, helped them grow technically, and contributed to their career progression.
Practice Interview
Study Questions
Understanding of DoorDash's Business and Engineering Challenges
Demonstrate knowledge of DoorDash's marketplace model, key technical challenges (logistics, reliability, payments), and why you're excited to contribute to these problems.
Practice Interview
Study Questions
Career Progression and Staff-Level Readiness
Articulate your journey from junior to senior to staff level, highlighting key projects, team growth, and architectural influence. Demonstrate why you're ready for Staff-level scope.
Practice Interview
Study Questions
Technical Leadership and Cross-Team Influence
Discuss specific examples where you drove technical decisions, influenced other teams, or shaped architecture beyond your direct team's scope.
Practice Interview
Study Questions
Technical Phone Screen - Coding/Algorithms
What to Expect
A 60-minute technical phone screen focusing on algorithmic problem-solving and coding proficiency. You'll be given a medium-to-hard algorithmic problem, often with a business context related to DoorDash's domain (e.g., delivery optimization, payment computation, routing logic). At Staff level, interviewers expect not just correct solutions but thoughtful approaches, clear communication of tradeoffs, and potential optimization paths. You may be asked follow-up questions that scale the problem or introduce new constraints.
Tips & Advice
1) Start by clarifying requirements and constraints before diving into code. Ask about scale, edge cases, and performance expectations. 2) At Staff level, articulate your approach before coding; discuss tradeoffs between different algorithms. 3) Write clean, readable code with meaningful variable names. 4) Walk through test cases including edge cases. 5) Be prepared to optimize: discuss time/space complexity tradeoffs and potential improvements. 6) If you get stuck, communicate your thinking process openly and ask for hints if needed. 7) DoorDash values domain-aware solutions—if the problem relates to delivery or payments, consider real-world constraints. 8) Practice on DoorDash-specific problem patterns: batching, time-window optimization, computation of metrics (pay, tips, totals), and routing logic.
Focus Topics
Clear Communication and Collaborative Problem-Solving
Verbalize your approach, explain your reasoning, ask clarifying questions, and engage the interviewer as a thought partner.
Practice Interview
Study Questions
Optimization and Scalability Thinking
For each solution, proactively discuss time/space complexity, identify bottlenecks, and propose optimizations. Think about how to scale the solution if data size increases 10x or 100x.
Practice Interview
Study Questions
Medium-to-Hard LeetCode Patterns (Graphs, Dynamic Programming, Greedy)
Strengthen problem-solving in areas like graph traversal, shortest paths, dynamic programming optimization, and greedy algorithms. Study 50-70 medium and hard problems.
Practice Interview
Study Questions
DoorDash Domain-Specific Algorithms (Batching, Routing, Optimization)
Master problems specific to DoorDash's business: batching deliveries by time windows, routing optimization, dasher pay computation, minimizing delivery time.
Practice Interview
Study Questions
Technical Phone Screen - System Design
What to Expect
A 60-minute system design interview focused on architecting large-scale systems. You may be asked to design systems similar to DoorDash's core services: a real-time driver dispatch system, a scalable payment processing service, a notification system for order updates, or a restaurant search and recommendation platform. At Staff level, you're expected to handle ambiguous requirements, propose end-to-end architectures, discuss tradeoffs between consistency/availability, scalability challenges, and production considerations (monitoring, failover, deployment).
Tips & Advice
1) Ask clarifying questions about requirements, scale (QPS, data volume), and business constraints before designing. 2) Outline your high-level architecture first, then dive into components. 3) For Staff-level expectations, discuss multiple design approaches and justify your choice based on tradeoffs. 4) Consider the full stack: frontend, backend services, databases, caching, message queues, monitoring. 5) Address scalability: database sharding, load balancing, caching strategies, horizontal scaling. 6) Discuss reliability: redundancy, failover mechanisms, data consistency, eventual consistency tradeoffs. 7) Think about DoorDash-specific concerns: real-time updates, low-latency requirements for driver-customer interactions, payment reliability. 8) Practice designing systems that handle millions of concurrent users and high-throughput transactions.
Focus Topics
Monitoring, Logging, and Observability
Design monitoring strategies for production systems: metrics, logs, tracing, alerting. Discuss how to identify issues and debug in production.
Practice Interview
Study Questions
Caching, Message Queues, and Asynchronous Processing
Design caching layers (Redis, Memcached), understand message queue architectures (Kafka, RabbitMQ), and design async workflows for payment processing, notifications, and data consistency.
Practice Interview
Study Questions
DoorDash Core System Designs (Dispatch, Payments, Notifications)
Practice designing real-time driver dispatch systems, scalable payment processing with dasher payouts, notification systems for multi-stakeholder coordination (customer, driver, merchant).
Practice Interview
Study Questions
Database Selection and Optimization (SQL, NoSQL, Sharding Strategies)
Choose appropriate databases (relational vs. document vs. key-value), design schemas, understand sharding strategies, indexing, and query optimization for different data models.
Practice Interview
Study Questions
Distributed Systems Fundamentals (Consistency, Availability, Reliability)
Master CAP theorem, eventual consistency, distributed tracing, consensus protocols, circuit breakers, and failure scenarios. Understand how to choose between strong and eventual consistency based on requirements.
Practice Interview
Study Questions
Onsite Round 1 - Coding Assessment
What to Expect
A 75-minute onsite coding round with a medium-to-hard algorithmic problem, typically involving real-time problem-solving under observation. This round tests coding speed, correctness, and your ability to handle pressure and iterate on feedback. You'll code in your preferred language on a shared editor or laptop. The problem may be similar to phone screen difficulty or slightly harder, designed to push you toward optimization and handling edge cases.
Tips & Advice
1) Manage time carefully: spend the first 10-15 minutes understanding the problem and outlining an approach. 2) Code deliberately; prioritize correctness over speed. 3) Communicate your thinking continuously so the interviewer can provide guidance if you go off track. 4) Test your code with provided examples and think of edge cases before submitting. 5) If you finish early, proactively optimize or discuss further improvements. 6) At Staff level, interviewers may ask 'what if' follow-ups; be ready to adapt your solution. 7) Stay calm and composed; treat the interviewer as a collaborator, not an adversary.
Focus Topics
Iterative Optimization
If you finish the main problem, explore optimizations: better algorithms, reduced space complexity, or alternative approaches.
Practice Interview
Study Questions
Edge Case Identification and Handling
Systematically identify edge cases (empty inputs, single elements, duplicate values, boundary conditions) and handle them in your solution.
Practice Interview
Study Questions
Algorithmic Problem Solving Under Pressure
Practice solving medium-to-hard problems within 75 minutes, including time for testing and optimization. Build speed and accuracy through repeated practice.
Practice Interview
Study Questions
Production-Quality Code Writing
Write code that is not just correct but also maintainable: clear variable names, comments where necessary, modular structure, and proper error handling.
Practice Interview
Study Questions
Onsite Round 2 - System Design
What to Expect
A 75-minute onsite system design round where you'll be asked to design a complex, large-scale system from scratch. This may be a variant of a DoorDash core system or a related platform challenge. Unlike phone screens, you'll have a whiteboard or design tool to sketch out your architecture, and the interviewer will ask probing questions about your design choices, tradeoffs, and how you'd handle failures. At Staff level, expect deeper questions about your architectural decisions and challenges at scale.
Tips & Advice
1) Start by clarifying requirements, not jumping into solutions. Ask about scale (DAU, QPS, peak load), geographic distribution, and consistency requirements. 2) Outline your high-level architecture with major components (services, databases, caches, queues) before diving into details. 3) Discuss tradeoffs explicitly: why you chose SQL over NoSQL, synchronous vs. asynchronous processing, strong vs. eventual consistency. 4) For Staff level, be prepared to redesign parts of your system based on interviewer feedback; show flexibility and strong reasoning. 5) Address production concerns: monitoring, alerting, deployment strategy, disaster recovery. 6) Use real DoorDash challenges as reference points if relevant. 7) Draw diagrams clearly and update them as you refine your design. 8) Engage the interviewer; ask if there are concerns about your approach.
Focus Topics
API Design and Communication Protocols
Design RESTful APIs, gRPC services, or pub-sub systems. Choose protocols based on latency, throughput, and reliability needs.
Practice Interview
Study Questions
Data Consistency Models (ACID vs. BASE, Eventual Consistency)
Understand when to use strong consistency (ACID transactions) vs. eventual consistency (BASE). Design conflict resolution strategies and manage consistency tradeoffs.
Practice Interview
Study Questions
Microservices Architecture and Service Boundaries
Design service-oriented architectures with clear boundaries. Discuss when to split services, how to handle cross-service transactions, and communication patterns.
Practice Interview
Study Questions
Scalable Architecture Design (Horizontal Scaling, Partitioning, Load Balancing)
Design systems that scale horizontally. Understand load balancing algorithms, database partitioning/sharding strategies, and how to distribute load across services and data centers.
Practice Interview
Study Questions
High-Availability and Disaster Recovery
Design for resilience: redundancy across data centers, failover mechanisms, replicas, backup strategies. Discuss how your system survives zone failures or component outages.
Practice Interview
Study Questions
Onsite Round 3 - Incident Investigation and Debugging
What to Expect
A 60-minute round where you're presented with a real or realistic incident scenario (e.g., payment processing delays, incorrect dasher pay calculation, driver dispatch latency spikes) and asked to investigate root causes, propose solutions, and discuss prevention. This round assesses your debugging methodology, understanding of distributed systems, and operational mindset. At Staff level, you're expected to think holistically about the system, consider multiple potential causes, and propose both immediate fixes and long-term improvements.
Tips & Advice
1) Start by asking clarifying questions: when did the incident start, how many users were affected, what metrics triggered alerts, what changed recently? 2) Build a hypothesis about root cause based on the symptoms, then systematically gather evidence. 3) Consider multiple layers: frontend, backend services, databases, infrastructure, external dependencies. 4) At Staff level, discuss both the symptoms and the underlying architectural weaknesses that allowed the incident to occur. 5) Propose immediate mitigation (if the system is still failing) and a permanent fix. 6) Discuss monitoring and alerting improvements to catch similar issues faster. 7) Think about resilience: how could the system have degraded gracefully instead of failing completely?
Focus Topics
Resilience and Graceful Degradation
Discuss how systems can be designed to fail gracefully, maintain partial functionality during outages, and recover without data loss.
Practice Interview
Study Questions
Database Troubleshooting (Query Performance, Connection Issues, Data Consistency)
Debug database issues: slow queries, connection pool exhaustion, replication lag, data corruption. Know how to read query plans and optimize.
Practice Interview
Study Questions
Distributed Systems Debugging (Tracing, Logging, Monitoring)
Use distributed tracing, logs, and metrics to debug issues across multiple services. Understand how to correlate events across the system and identify bottlenecks.
Practice Interview
Study Questions
Root Cause Analysis Methodology
Systematically narrow down root causes by forming hypotheses, gathering evidence, and eliminating possibilities. Understand the difference between symptoms and root causes.
Practice Interview
Study Questions
Onsite Round 4 - Behavioral and Technical Leadership
What to Expect
A 60-minute behavioral and leadership-focused round with questions about past experiences, decision-making, conflict resolution, collaboration across teams, mentorship, and how you've driven technical initiatives. At Staff level, this round assesses your ability to operate independently, influence others without authority, mentor engineers, and contribute to technical strategy. Interviewers will ask about specific projects where you made architectural decisions, resolved ambiguous requirements, overcame challenges, and grew as a leader.
Tips & Advice
1) Prepare 5-7 detailed stories using the STAR method (Situation, Task, Action, Result) that showcase different dimensions: problem-solving, leadership, collaboration, failure and learning, impact at scale. 2) At Staff level, stories should demonstrate: owning ambiguous problems end-to-end, influencing technical decisions across teams, mentoring mid-to-senior engineers, navigating organizational challenges, and contributing to technical strategy. 3) Use metrics and concrete outcomes (improved performance by X%, reduced latency by Y%, shipped feature on time, mentored N engineers to promotion). 4) Prepare stories about disagreements or conflicts and how you resolved them constructively. 5) Discuss how you've grown from mistakes and what you learned. 6) Be authentic and reflective; avoid exaggerating your role. 7) Ask the interviewer questions to show genuine interest in DoorDash's challenges and culture.
Focus Topics
DoorDash Culture Fit and Values Alignment
Research DoorDash's culture and values. Relate your experiences to their focus on execution, reliability, customer obsession, and impact. Show genuine interest in their mission.
Practice Interview
Study Questions
Learning from Failure and Continuous Improvement
Share examples of significant mistakes, what you learned, and how you changed your approach. Discuss systems or processes you've improved based on failures.
Practice Interview
Study Questions
Navigating Ambiguity and Making Technical Decisions
Describe situations with unclear requirements or multiple valid technical approaches. How did you gather information, evaluate options, and make decisions? What was the outcome?
Practice Interview
Study Questions
Ownership and End-to-End Project Leadership
Demonstrate how you've taken ownership of ambiguous, complex projects from conception to completion, navigating technical and organizational challenges independently.
Practice Interview
Study Questions
Mentorship, Coaching, and Enabling Others
Discuss how you've mentored mid-level and senior engineers, helped them grow technically, resolved their blockers, and contributed to their career progression.
Practice Interview
Study Questions
Cross-Functional Collaboration and Influence Without Authority
Share examples of how you've worked effectively with other engineering teams, product managers, and stakeholders without direct authority. How did you align interests and drive decisions?
Practice Interview
Study Questions
Frequently Asked Full-Stack Developer Interview Questions
A bug only appears under heavy load and cannot be reproduced locally. Describe how to build a deterministic experiment or test harness to reproduce the issue: synthetic traffic generators, seeding state, concurrency controls, time manipulation, and deterministic schedulers. Explain how to minimize noise and prove causality.
Sample Answer
A bug that only appears under heavy load needs a test harness that can manufacture load deterministically, since waiting for production traffic to happen to trigger it again is not a repeatable investigation.
Building the harness
- Synthetic traffic generation at a controlled, repeatable concurrency and request mix (a load-testing tool driving realistic request shapes, not just raw throughput).
- Seed shared state deterministically (fixed starting data, fixed random seeds where the system uses randomness) so the only varying factor between runs is scheduling/timing, not also data variance.
- Concurrency controls and deterministic schedulers where available, to bias the interleaving toward the suspected contention point rather than relying purely on load volume to eventually hit it.
- Time manipulation (accelerating or controlling clock-dependent logic) when the bug involves timers, TTLs, or scheduled work, so you don't need to wait real-world hours to observe a time-triggered condition.
- Minimize noise, prove causality: run the same load profile with and without the suspected contributing factor (a specific code path enabled/disabled, a specific config toggled) and compare failure rates statistically rather than trusting a single run either way.
A concrete run
Suppose the suspected bug is a cache-eviction race that only shows up under heavy concurrent writes. Running the harness at a fixed seed (seed=42) and concurrency=20 reproduces the race 0 times in 50 runs; the same harness at concurrency=200 reproduces it in 12 of 50 runs, a clear, statistically meaningful signal that concurrency level, not chance, drives the failure, and a concrete number, 12 of 50 at 200 versus 0 of 50 at 20, a reviewer can rerun and check rather than take on faith.
Applying this without dedicated load-test infrastructure
A single server that fails intermittently under heavy load, or that can't reproduce in staging, benefits from the cheaper version of the same idea: increase load safely on that one host (careful, bounded synthetic load) while capturing fine-grained logs/traces, rather than waiting for the next natural production spike.
Trade-offs and pitfalls
Synthetic load rarely matches production traffic shape exactly (arrival patterns, payload variety, cache warmth); the harness's value is in reliably reproducing the class of failure for iteration, not necessarily reproducing the exact production timeline, so a fix validated only against synthetic load still needs confirmation against real traffic before being called durable.
Explain idempotency: what it means for an HTTP API or a distributed-systems operation, and why it matters for safely retrying after a failure. Give concrete examples of idempotent versus non-idempotent operations (for example, a PUT that sets a field to an absolute value versus a POST that increments a counter or charges a payment). Describe at least two simple techniques to achieve idempotency (an idempotency key with a stored response, a unique constraint or dedup at the database level) and their trade-offs (storage cost, key expiration, concurrency).
Sample Answer
Direct answer
An operation is idempotent if executing it once has the same observable effect as executing it two or more times with the same input; this matters because a network failure can leave a client genuinely unsure whether its request succeeded, and idempotency is what makes 'just retry' a safe default answer instead of a risky one.
Structured elaboration
- Idempotent examples:
PUT /users/5 {name: "Alice"}(setting a resource to an absolute value: repeating it produces the same end state); aDELETEof an already-deleted resource (still ends in 'resource gone', whether it's the first or fifth delete call); a read (GET) is trivially idempotent since it changes nothing. - Non-idempotent examples:
POST /orderswith no protection (each call creates a NEW order, so retrying after an ambiguous network failure risks a duplicate order);PATCH /accounts/5/balance {increment: 10}(each retry adds 10 again, unlike aPUTthat sets an absolute value). - Achieving idempotency for a naturally non-idempotent operation: (1) an idempotency key the client attaches to every retry of the SAME logical attempt, with the server storing and replaying the result of the first execution; (2) a unique constraint or deduplication check at the database level (a unique index on
order_request_id) that rejects a duplicate insert outright; (3) redesigning the API itself to be naturally idempotent where possible (an absolutePUTinstead of a relativePATCH increment).
Trade-offs and pitfalls
Idempotency keys and dedup stores cost storage (every key needs to be retained at least as long as a client might plausibly retry) and add a lookup on every request; the trade-off is almost always worth it for anything with a real-world side effect (money, inventory, sending a notification), and often skippable for pure reads or naturally-idempotent writes. The most common mistake is assuming an operation is idempotent because it 'usually' produces the same result, without actually verifying it under concurrent or partial-failure conditions specifically.
You must choose between Redis and Memcached to implement a session store for a web app. List trade-offs and recommend one choice. Consider persistence, data types, replication/HA, memory efficiency, eviction semantics, and operational features such as monitoring and backup.
Sample Answer
Direct answer
Choose Redis when you need richer data structures, persistence, or replication/high-availability (HA) built in; choose Memcached when you need the simplest possible pure key-value cache with the lowest per-operation overhead and multi-threaded read scaling out of the box.
Structured elaboration
- Data types: Redis supports strings, hashes, lists, sets, sorted sets, and more, useful when the cache itself needs to do more than store opaque blobs (e.g., a sorted set for a leaderboard). Memcached only stores simple key-value byte strings.
- Persistence: Redis can persist to disk (RDB snapshots, append-only file, AOF) so data can survive a restart; Memcached is purely in-memory with no persistence, so a restart is always a full cache flush.
- Replication / high availability: Redis has built-in replication and clustering (Sentinel for failover, Cluster for sharding); Memcached has no native replication, relying on the client or an external layer for HA.
- Memory efficiency: Memcached's simpler data model generally has lower per-key memory overhead for pure key-value use cases; Redis's richer data structures and features carry some additional overhead.
- Eviction semantics: both support least-recently-used (LRU) style eviction, but Redis offers more configurable policies (
allkeys-lru,volatile-ttl,allkeys-lfu, and others) versus Memcached's simpler slab-based LRU. - Operational features: Redis has a larger ecosystem for observability, Lua scripting for atomic multi-step operations, and pub/sub; Memcached's multi-threaded architecture can give it an edge on raw throughput for simple get/set at very high concurrency on a single node.
Worked example
For a session store: if sessions are pure key-value blobs, Memcached is a perfectly reasonable, simpler choice. If sessions need persistence across a restart (avoiding logging every user out simultaneously) or replication for HA, Redis with AOF persistence and Sentinel-managed failover is the safer choice, at the cost of a slightly more complex operational footprint.
Trade-offs and pitfalls
Choosing Redis "because it can do more" for a workload that is genuinely simple key-value adds operational surface area (persistence tuning, replication topology) without benefit; match the tool to the actual requirement. Memcached's lack of native replication means a node loss is a hard cache-miss event for everything that node held, with no automatic failover; that must be an explicit, accepted trade-off, not an oversight.
Compare using an application database's built-in text search (for example PostgreSQL tsvector) versus integrating a dedicated search engine (Elasticsearch/OpenSearch). Include trade-offs in indexing complexity, freshness, scaling, advanced query capabilities (relevance, facets), and operational overhead.
Sample Answer
Answer (Full‑Stack Developer perspective)
Summary
I’d choose PostgreSQL tsvector for simple apps with modest traffic and search needs; pick Elasticsearch/OpenSearch when you need advanced relevance, facets, and large-scale queries.
Indexing complexity
- PostgreSQL: easy — maintain tsvector columns or triggers; single transaction with app DB. Example: CREATE INDEX ON documents USING GIN(to_tsvector('english', content)).
- ES/OpenSearch: more setup — mapping, analyzers, ingest pipelines; ETL to sync DB → search index.
Freshness
- PostgreSQL: near‑real‑time since data and index live together.
- ES: eventual consistency unless synchronous writes are implemented; requires changefeed/CDC for low lag.
Scaling
- PostgreSQL: vertical scaling; GIN indexes can grow large and slow; sharding is complex.
- ES: designed to scale horizontally across nodes and shards for high query throughput.
Advanced queries
- PostgreSQL: supports ranking (ts_rank), phrase search, basic facets via aggregates.
- ES: richer relevance tuning, multi-field boosting, fuzzy, synonyms, aggregations/facets, suggestions.
Operational overhead
- PostgreSQL: minimal — one system to manage, backups and monitoring already in place.
- ES: additional cluster ops, tuning, memory management, and cost.
Recommendation
If requirements are simple and you want lower ops, use tsvector. If you need sophisticated UX (autocomplete, faceted navigation, heavy query load), invest in Elasticsearch/OpenSearch.
Design a minimal REST API (endpoints, HTTP verbs, example payloads) to create an order and notify eligible nearby couriers for acceptance. Assume a microservice model; include the request/response fields critical to routing and acceptance tracking.
Sample Answer
Design overview
Minimal REST surfaced by Orders service; Courier service (discovery/availability) and Notification service handle nearby courier lookup and delivery of push/WS messages. Use event-driven updates (webhooks or pub/sub) for scale.
Endpoints
- Create order
POST /orders
Request:
{
"user_id":"u_123",
"pickup": {"lat":37.77, "lng":-122.41, "address":"1 Market St"},
"dropoff": {"lat":37.79, "lng":-122.40, "address":"100 Pine St"},
"items":[{"id":"i1","qty":2}],
"priority":"normal",
"requested_eta_mins":30
}
Response:
{
"order_id":"o_456",
"status":"searching_courier",
"created_at":"2026-03-03T12:00:00Z"
}
Action: Orders service calls Routing/Courier service with pickup location + constraints to get eligible couriers (radius, capacity, status). Then calls Notification service to push an offer.
- Notify courier (internal; from Orders -> Notification)
POST /internal/notifications/courier-offer
{
"courier_id":"c_789",
"order_id":"o_456",
"pickup":{"lat":37.77,"lng":-122.41},
"dropoff":{"lat":37.79,"lng":-122.40},
"expires_at":"2026-03-03T12:02:00Z"
}
- Courier accepts/rejects
POST /orders/{order_id}/offers/{courier_id}/response
{
"courier_id":"c_789",
"response":"accept" // or "reject"
}
Response:
{
"order_id":"o_456",
"courier_id":"c_789",
"result":"accepted",
"assigned_at":"2026-03-03T12:01:10Z"
}
- Order status lookup
GET /orders/{order_id}
Response includes routing fields to help UI:
{
"order_id":"o_456",
"status":"assigned | searching_courier | cancelled",
"assigned_courier":{"id":"c_789","eta_mins":5},
"offers":[{"courier_id":"c_101","state":"pending","expires_at":"..."}]
}
Key fields for routing & tracking
- pickup/dropoff lat,lng (routing)
- user_id, order_id (correlation)
- priority/constraints (capacity, vehicle_type)
- offer_id or courier_id + expires_at (race/timeout handling)
- assigned_at, status, offered_at (audit)
Notes / reasoning
- Keep synchronous create lightweight; asynchronously fan-out offers.
- Use short TTL on offers to avoid races; first accept wins (Orders service enforces compare-and-set/DB transaction).
- Internal endpoints marked /internal to separate microservices and auth.
- Use pub/sub for large scale (Notifications subscribe to courier-offer events).
Evaluate a string arithmetic expression containing non-negative integers and the four basic operators (with correct precedence), without using a language built-in eval. Explain the role a stack plays in deferring lower-precedence operations until you know the full operand.
Sample Answer
Direct answer
Scan the expression once left to right, accumulating the current number and, on hitting an operator (or the string's end), resolving the previous operator against a value stack rather than a running total directly. Addition and subtraction push a signed value onto the stack to be settled later; multiplication and division pop the stack's top, combine it with the current number immediately, and push the result back, because those two operators must bind tighter than whatever addition or subtraction comes before or after them. The stack is what lets the scan defer every addition and subtraction until the very end, once every higher-precedence operation touching a given operand has already been folded in, summing the stack at that point gives the correct, precedence-respecting result.
Structured elaboration
Why a single accumulator is not enough
Evaluating left to right with one running total works for pure addition and subtraction, but multiplication and division must apply to their immediate neighbors before anything else touches those values. A single accumulator has no way to "undo" a value it already folded into the total in order to multiply it by something appearing later.
What the stack defers, specifically
Each time a complete number is read, look at the operator that preceded it:
+: push the number as-is; it will be added in at the end.-: push the number negated; subtraction is addition of a negative.*or/: pop the stack's current top, combine with the new number right now, and push the combined result back, this is what "deferring lower-precedence operations" really means in reverse: it is addition and subtraction that get deferred, while multiplication and division are resolved immediately because their operands are already fully known.
At the very end, summing the whole stack applies every deferred addition and subtraction in one shot, correctly, because every*//touching any of those values has already been folded in before it ever reached the stack.
Handling division sign and formatting
Division must truncate toward zero (not Python's default floor division, which rounds toward negative infinity for negative operands), so int(a / b) rather than a // b is used to match the conventional integer-arithmetic contract.
Worked example
def calculate(s: str) -> int:
s = s.strip()
stack = []
num = 0
op = '+'
n = len(s)
for i, ch in enumerate(s):
if ch.isdigit():
num = num * 10 + int(ch)
if (not ch.isdigit() and ch != ' ') or i == n - 1:
if op == '+':
stack.append(num)
elif op == '-':
stack.append(-num)
elif op == '*':
stack.append(stack.pop() * num)
elif op == '/':
prev = stack.pop()
stack.append(int(prev / num))
op = ch
num = 0
return sum(stack)
print(calculate("3+2*2"))
print(calculate(" 3/2 "))
print(calculate(" 3+5 / 2 "))
print(calculate("14-3/2"))
print(calculate("1*2-3/4+5*6-7*8+9/10"))
This prints:
7
1
5
13
-24
Tracing "3+2*2": read 3, hit +, push 3 (stack [3]), op becomes +. Read 2, hit *, push 2 (stack [3, 2]), op becomes *. Read the final 2 (end of string triggers resolution with op = '*'): pop 2, multiply by the new 2, push 4 (stack [3, 4]). Sum is 7, matching the printed output. "14-3/2" similarly resolves 3/2 to 1 via truncating division before the pending subtraction is ever applied, giving 14 - 1 = 13.
Key points
- The stack holds fully-resolved, precedence-correct terms; the final
sum()is the only place addition and subtraction actually happen across terms. *and/never get their own stack entries, they immediately combine with whatever the stack's top already holds.- Multi-digit numbers accumulate via
num = num * 10 + int(ch)before any operator triggers resolution.
Complexity
Time: O(n), a single pass over the string. Space: O(n) in the worst case for the stack (an expression that is entirely additions and subtractions of single terms pushes one entry per term), though it can be reduced to O(1) extra space by tracking only the running total and the most recent term instead of a full stack, at the cost of a less direct mapping to "what the stack is doing" pedagogically.
Edge cases
- Leading, trailing, or embedded spaces: skipped by the
ch != ' 'check, which does not trigger a resolution and does not get added into the accumulating number. - Multi-digit numbers: accumulated digit by digit before any operator resolves them.
- Expression ending exactly on a number (no trailing operator): the
i == n - 1condition forces one final resolution using whatever operator preceded that last number. - Division truncating toward zero for negative results: using
int(prev / num)rather thanprev // numavoids Python's floor-toward-negative-infinity behavior on mixed-sign division.
Trade-offs & pitfalls
The most common bug is using // for division and getting a different (floored, not truncated) result on negative operands; int(a / b) sidesteps this by truncating through the int() conversion itself. A frequent design question is whether to extend this to full recursive-descent parsing to support parentheses and unary operators (Basic Calculator III-style): the single-pass stack approach generalizes naturally to nested parentheses by recursing into a sub-expression whenever ( is seen and returning the sub-result to the outer scan, whereas true operator-precedence parsing with a formal grammar is a more general (and more code-heavy) solution better suited to expressions with many operator types or user-defined precedence rules.
Describe the two-phase commit protocol: the coordinator and participant roles, and the prepare and commit phases. Explain the classic failure case where 2PC blocks indefinitely (a coordinator crash after participants have voted to commit) and why that blocking is a real operational problem. Give one mitigation, and explain when you'd reach for a saga instead of a distributed transaction.
Sample Answer
Direct Answer
Two-phase commit (2PC) is a protocol that lets one coordinator get a group of participants, each owning a different resource such as a database or another service acting as a resource manager, to commit or abort a single transaction atomically. It works by first asking everyone to prepare, and only telling everyone to actually commit once every participant has confirmed it's ready.
The Two Phases
- Prepare (vote) phase: the coordinator sends Prepare to every participant. Each participant does whatever local work is needed to guarantee it can commit if told to, such as writing an undo or redo log entry, acquiring the necessary locks, or checking constraints, then replies Yes or No. Once a participant votes Yes, it must hold its prepared state and locks until it hears the final decision; it can no longer unilaterally change its mind.
- Commit/abort phase: if every participant voted Yes, the coordinator sends Commit to all of them; if any participant voted No, or didn't respond, it sends Abort to all of them. Each participant applies the decision and releases its locks.
The Classic Blocking Failure
If the coordinator crashes after collecting Yes votes from every participant but before sending out the final Commit or Abort, every participant is stuck holding its prepared state and its locks indefinitely. A participant can't safely decide on its own: if it guesses Commit but the coordinator, once recovered, had actually decided Abort because some other participant it hadn't heard from yet said No, that guess would violate atomicity. So each participant has no safe choice but to wait.
This is a real operational problem, not just an inconvenience, because those held locks are on real resources. Any other transaction that touches the same rows, files, or records is blocked too, for as long as the coordinator stays down. A single stuck 2PC transaction can produce an effective outage across everything those locks reach.
A Mitigation: Durable Coordinator Logging and Recovery
The coordinator writes its decision, and the votes it collected, to a durable write-ahead log, a log written to disk before the coordinator acts on it so it survives a crash, before sending Commit or Abort. On restart, or when a replacement coordinator takes over, elected through its own consensus mechanism, it replays that log to learn what it had already decided for any in-flight transaction and resends the correct outcome to whichever participants are still blocked. This doesn't remove the blocking window entirely, but it bounds it to however long recovery takes, instead of leaving participants blocked forever.
Worked Trace
Three participants: a relational database (DB), a document store (Doc), and, for illustration, a payment gateway wrapped with a prepare step (PG). Coordinator C.
- C sends Prepare to DB. DB validates and locks, replies Yes.
- C sends Prepare to Doc. Doc validates and locks, replies Yes.
- C sends Prepare to PG. PG validates, replies Yes.
- C now has 3 of 3 Yes votes and is about to send Commit, but it crashes before sending anything.
- DB, Doc, and PG are all blocked, each holding its prepared locks; none of them can safely commit or abort on its own, since each only knows its own vote was Yes, not the others'.
- A recovered, or replacement, coordinator reads its durable log, sees that all three votes were Yes and that Commit was the decision about to be sent, and resends Commit to DB, Doc, and PG. All three commit and release their locks.
Heterogeneous Resources and a Real-World Wall
2PC's coordinator and participant model works across different kinds of resources in principle: a relational database and a document store can both act as participants as long as each exposes a real prepare step, which is exactly what the XA standard, the X/Open standard defining a two-phase-commit interface for resource managers, formalizes for relational databases. The practical wall most teams hit is that an external payment gateway typically doesn't expose anything like a prepare/commit interface at all; it's a single, irrevocable HTTP call. That's one concrete reason a workflow like reserve inventory, charge card, and ship is usually built as a saga rather than a literal distributed transaction: at least one of the participants can't be plugged into 2PC as a real participant.
When to Reach for a Saga Instead
Reach for a saga instead of 2PC when at least one step can't participate in a real prepare/commit handshake, such as a third-party API with only a single irreversible call, when holding locks for the full duration of the workflow is unacceptable for availability or latency, or when some steps are long-running, such as waiting on a person, a batch job, or a slow downstream service, and you can't justify holding resources locked that long.
Trade-offs and Pitfalls
- A common wrong turn is assuming a participant can unilaterally abort on its own after a timeout once it has already voted Yes. It can't, safely, because it doesn't know whether the coordinator already told everyone else to commit; that's exactly why 2PC is called blocking.
- Presumed-commit and presumed-abort optimizations reduce how much needs to be logged in the common case, but they don't remove the fundamental blocking window; they just make the typical path cheaper.
- Three-phase commit adds an extra round specifically to shrink this blocking window, but it doesn't fully eliminate it, and it's rarely deployed in practice because of the added message and latency cost for a problem that a saga usually sidesteps entirely.
Rather than assuming blameless postmortems and structured learning practices reduce incident recurrence, design an experiment or quasi-experiment that would actually demonstrate it. Define your primary metrics, how you would form treatment and comparison groups given that incidents are relatively low-frequency, and what confounders you would need to control for.
Sample Answer
Direct answer
Proving blameless postmortems causally reduce recurrence, rather than assuming it, requires comparing incident outcomes between groups that did and did not receive the full blameless-postmortem treatment, while controlling for the fact that incidents are relatively rare, which makes a small, underpowered comparison unreliable.
Structured elaboration
- Define the primary metric precisely. Incident recurrence rate for the same or closely related failure category within a defined window (say, six months) after a postmortem, and mean-time-to-recovery for any recurrence that does happen, are both reasonable primary outcomes.
- Form comparison groups given low incident frequency. A staggered rollout across teams (some teams adopt full blameless postmortems now, others adopt a few months later) gives you a natural comparison without denying anyone the practice indefinitely, and it's more feasible than a strict randomized controlled trial in most organizations. Alternatively, compare incident classes that received a full postmortem against similar-severity incident classes from before the practice was adopted, using the organization's own history as the comparison.
- Account for low frequency directly. Because a single team's incident count is small, aggregate across many teams or many incident categories to get enough statistical power, and be honest that with genuinely rare, high-severity incidents, you may only be able to speak confidently about a proxy (like recurrence of the underlying vulnerability class in code review or testing) rather than recurrence of an actual outage.
- Control for confounders explicitly. Teams that adopt blameless postmortems early are often also the teams already investing more broadly in reliability practices, so any observed improvement could be due to that general investment rather than the postmortem practice specifically; a staggered rollout across otherwise-similar teams helps isolate this, and tracking a secondary metric less directly tied to postmortems (like general code quality trends) as a check helps rule out a confound affecting everything at once.
- Report the honest limitation. Even a well-designed study in this space will likely have wide confidence intervals given how rare severe incidents genuinely are; report that uncertainty rather than overstating confidence in a clean causal result.
Worked example
An organization with 40 teams rolls out mandatory blameless postmortems to half the teams (chosen to be broadly similar in size and incident history) starting this quarter, with the other half adopting the practice three months later. Primary metric: recurrence rate of a related incident category within six months of any postmortem-eligible incident. After the study window, teams in the early-adoption group show a lower recurrence rate than the later-adoption group during the period before the second group adopted the practice, and the gap narrows once the second group also adopts it, which is more convincing evidence of a causal effect than a simple before-and-after comparison on a single group would have been, since it rules out a general org-wide trend as the sole explanation.
Trade-offs and pitfalls
The most common mistake is treating a simple before-and-after comparison on one group as proof of causation, when it's equally consistent with unrelated organizational improvements happening over the same period. A second is understating how much statistical power genuinely rare, severe incidents cost you, and presenting a result with far more confidence than the small sample size actually supports.
You're the only engineer available and need to deliver a scoped, launch-critical piece of work within a hard one-week timebox with minimal spec. Produce a day-by-day plan: concrete deliverables for each day, your acceptance criteria, what you'll test and monitor, your checkpoint/communication schedule with stakeholders, and what you'll cut first if you get blocked.
Sample Answer
Direct answer
Solo, one week, minimal spec, launch-critical: the plan has to front-load clarifying scope and de-risking the biggest unknown on day one, ship the smallest correct version early, and hold a visible cut-list so a slip becomes a scope decision instead of a missed deadline. The plan below assumes a five-day work week.
Structured elaboration
The shape that makes a solo one-week delivery survivable is: clarify and de-risk early, build the narrowest correct path next, harden and observe before the deadline, and always know what gets cut first if something goes wrong. Acceptance criteria and monitoring have to be decided before day one ends, not discovered on day five, because there is no one else to catch a wrong assumption for you.
Worked example
Day 1: A short conversation with the requester to pin down acceptance criteria and write a one-page mini-spec covering the primary case and the assumptions I'm making, with explicit sign-off. Spend the rest of the day spiking the single riskiest unknown (for example, confirming the actual shape of an upstream dependency's response) before committing to a design around it.
Day 2: Build only the happy path end-to-end, wired behind a feature flag on an isolated branch. No edge cases yet; the goal is one correct path proven working top to bottom.
Day 3: Add handling for the two or three failure modes that actually matter in production, and write automated tests for the happy path plus those failure modes. End of day: a short async or 15-minute check-in with the stakeholder on progress against the day-1 plan.
Day 4: Test against production-like data, wire up monitoring (an error-rate and latency view, with an alert threshold) so day one in production is observable, and do a dry run with a teammate reviewing the diff and the plan.
Day 5: Ship behind the flag to a small slice of traffic first, verify against the acceptance criteria from day 1, then widen. Final checkpoint communication to the stakeholder covering the go/no-go decision and the rollback plan, with buffer time held back in case the initial ramp surfaces something.
Acceptance criteria: correct behavior on the primary path, handling for the top failure modes, monitoring live before go-live, and a documented rollback plan.
Checkpoint schedule: end of day 1 (scope confirmed), end of day 3 (progress check), end of day 5 (go/no-go).
Cut list if blocked, in order: first, secondary or nice-to-have edge cases; second, defer broader test coverage down to just the top failure modes; third, negotiate scope itself (for example, ship only the read path and defer the write path); last resort, tell the stakeholder directly that scope is being cut rather than silently letting the date slip.
Trade-offs and pitfalls
Skipping the day-1 scope conversation to "save time" is the single most common way a solo, tight-deadline effort fails, because any wrong assumption compounds for the rest of the week with no one to catch it. Building broad edge-case coverage before the happy path even works end to end risks having nothing shippable if day 5 arrives early. Waiting until day 5 to think about monitoring means the first production issue is invisible until a user reports it. And having no pre-agreed cut list forces an improvised, worse decision under pressure exactly when there is the least time to make a good one.
A cross-functional project you're on has a standing weekly meeting, but people are saying the meetings are unproductive and decisions keep stalling. What would you change?
Sample Answer
Direct answer
First diagnose why the meeting is stalling: usually it's because status-sharing and decision-making are mixed together, and no one is clearly accountable for closing a decision when people disagree. The fix separates the two (status moves async, meeting time is reserved for decisions), names a decision owner per topic, and tracks decisions in writing so they don't get relitigated the next week.
How to redesign it
Step 1: diagnose before redesigning. Ask whether people are status-updating instead of deciding, whether it's unclear whose call something is, or whether decisions do get made but aren't tracked so they resurface. Each cause has a different fix.
Step 2: separate status from decisions.
| Before | After |
|---|---|
| Round-robin status updates eat most of the meeting | Status posted async in a short template before the meeting |
| Decisions surface late, with little time left | Meeting time is reserved for items flagged as needing a live decision |
| Unclear who has the final call | Each agenda item has a named decision owner |
Step 3: track decisions so they don't restall. Keep a lightweight decision log: what was decided, who owns it, and the date. If an item can't close live, name a follow-up owner and a deadline instead of letting it silently carry over.
Step 4: reconsider the cadence. If most items now resolve async, a lower-frequency decision meeting paired with a written weekly status may serve the group better than a fixed weekly sync for everything.
Worked example
Situation: a cross-functional project with design, engineering, and data has a standing 60-minute weekly sync. Status updates take up 45 minutes, decisions surface in the last 15, and things 'decided' in the room get revisited the following week.
Action: introduced a pre-read posted 24 hours ahead covering status and any open decisions that need a live call; restructured the meeting to skip status entirely and spend the full time on flagged decisions, each with a named owner; started a shared decision log so a closed decision has a record to point back to.
Result: the meeting shortened from 60 to 30 minutes because status moved out of the room, and decisions stopped resurfacing because there was now a written record of what was actually agreed and by whom.
Trade-offs and pitfalls
- Cutting the meeting without giving people another outlet just moves the stalling into chat threads. Live time is still needed for genuine disagreement, don't eliminate it entirely.
- Naming a decision owner can feel like taking authority away from the group. Frame it as who is accountable if the call turns out wrong, not as a power grab.
- Async pre-reads fail without a light enforcement habit. If nobody protects the norm, it quietly reverts to status-in-the-room within a few weeks.
- Adding a decision log and a template is itself process. If it isn't paired with removing something (like the status round-robin), it just adds overhead on top of the original problem.
Want to create your own tailored preparation guide using our deep research?
Get Started for FreeInterview-Ready Courses
Visual-first, interactive, structured learning paths
Browse Full-Stack Developer jobs
AI-enriched listings across hundreds of company career pages
Explore Jobs