Skip to content
SeeItFlow
Interactive guide · 7 chapters · ~35 min read

Interview Perspective

How to communicate a ride-hailing system design in an interview. This is not about what to build — it is about how to think out loud, structure your reasoning, handle pushback, and demonstrate the engineering judgment that gets you hired.

Mangesh MandlikLast updated:
Interview 01

How to Start

The first five minutes of a system design interview set the trajectory for the entire session. Candidates who jump straight into architecture waste those minutes and spend the rest of the hour digging out of a hole.

The instinct is to start drawing boxes. Fight it. The interviewer has not told you what they care about yet, and you have not told them what you understand. Those first five minutes are a negotiation — you are aligning on what this conversation is actually about.

The Four-Step Opening

Step 1: Clarify scope. Ask directly: "Are we designing the real-time matching system? The payment flow? The full ride lifecycle from request to drop-off?" A ride-hailing platform has dozens of subsystems. You cannot design all of them in 45 minutes, and the interviewer knows that. What they want to see is that you recognize the scope problem and address it.

Step 2: Confirm functional requirements. State them out loud: "So we need riders to request rides, the system to match them with nearby drivers, real-time location tracking during the trip, and fare calculation at the end. Does that cover it, or should I include surge pricing?" This forces agreement and prevents mid-interview scope creep.

Step 3: Identify non-functional priorities. "For a system like this, availability is more important than strict consistency for location data, but trip state and payments need strong consistency. Does that align with your expectations?" This shows you understand that not all data is equal.

Step 4: State assumptions and constraints. "I will assume we have roughly 1 million active drivers at peak, 500,000 concurrent trips, and drivers sending location updates every 6 seconds (about 10 per minute). I will refine these if needed." Putting numbers on the table early gives you something concrete to reason about.

Example Opening Dialogue

textA 90-second opening that establishes scope, requirements, and alignment
Candidate: "Before I start designing, I want to make sure we're aligned
           on scope. When you say 'design Uber,' are we focusing on
           the core ride flow — request, match, trip tracking, completion?
           Or do you want me to include payments, surge pricing, driver
           onboarding?"

Interviewer: "Focus on the core ride flow. Matching and tracking."

Candidate: "Got it. So the functional requirements are: a rider requests
           a ride, the system finds a nearby available driver, both
           parties see real-time location during the trip, and the
           trip has a clear completion state. For non-functional
           requirements, I'd say low-latency matching — under 10
           seconds — high availability for location tracking, and
           strong consistency for trip state transitions. Does that
           sound right?"

Interviewer: "Yes, that works. Go ahead."
Key takeaways
  1. 01Spend the first 5 minutes on scope, requirements, and assumptions — never on architecture.
  2. 02State your requirements out loud and get explicit agreement before moving forward.
  3. 03Distinguish which data needs strong consistency and which tolerates staleness.
  4. 04Put rough numbers on the table early — they ground every decision that follows.
Interview 02

Structuring the Design

After requirements, you need a framework for building the design incrementally. The goal is not to present a finished architecture — it is to think out loud, evolving the design as complexity demands it.

Follow this sequence and you will never lose your place:

1. Requirements (~5 minutes) — Already covered. Scope, functional, non-functional, constraints.

2. Core entities and relationships (~2 minutes) — "We have Riders, Drivers, Trips, and Locations. A Trip connects one Rider to one Driver. Locations are transient; Trips are persistent."

3. API surface (~3 minutes) — Define the key endpoints: POST /rides/request, POST /rides/{id}/accept, PUT /drivers/{id}/location, GET /rides/{id}/status. This grounds the system in concrete interactions.

4. High-level design (~5 minutes) — Start with the simplest possible diagram. One client, one server, one database. Then say: "This works at small scale. Let me talk about where it breaks."

5. Deep dive (~15 minutes) — This is where you spend the bulk of your time. Pick the hardest problems: real-time matching, location ingestion at scale, trip state management.

6. Scaling and failure modes (~5 minutes) — What breaks at 100x? What happens when a service goes down?

Start Simple, Then Evolve

Draw three boxes: Client, Server, Database. This is not naive — it is intentional. You are showing the interviewer that you start from a working system and add complexity only when the requirements demand it. Say explicitly: "This handles 100 rides per minute. At our target scale of 500K concurrent trips, the database becomes the bottleneck for location writes. That is where I want to split things apart."

Swipe to pan
Initial ArchitectureClient, app server, database — the simplest possible start.Rider Appmobile clientApp ServermonolithPostgreSQLtrips · usersRESTSQL
Start here — one server, one database. Then evolve it as bottlenecks appear.

Now evolve the diagram. Separate the location service from the trip service. Add a message queue between trip events and downstream consumers. Introduce a spatial index for driver matching. Each addition should be motivated by a specific problem you just identified. The diagram is a thinking tool, not a finished product.

Swipe to pan
Complete ArchitectureGlobal DNSLBApp 1App 2App 3Redisgeo indexPostgreSQL+ read replicaMatchinggeospatialKafkaevent busNotificationsAnalyticsRT GatewayWebSocketRider Appdecoupled services · async event flow · independent scaling
The final architecture emerges from decisions, not from drawing it first

Time Management

The most underrated interview skill is clock management. In a 45-minute system design round, you have roughly: 5 minutes for requirements, 5 minutes for high-level design, 15 minutes for deep dives, 5 minutes for scaling and failures, and 5 minutes of buffer for questions and pivots. If you are still discussing requirements at minute 15, you will not have time to demonstrate depth. If you skip requirements entirely, every design decision floats without justification.

Key takeaways
  1. 01Follow the flow: Requirements, Entities, APIs, High-level, Deep dive, Scaling.
  2. 02Start with Client-Server-Database and evolve — never start with the final architecture.
  3. 03Every new box on the diagram should be motivated by a specific problem.
  4. 04Manage your time: 5-5-15-5-5 is a reliable split for a 45-minute round.
Interview 03

Scale Estimation in Interviews

Scale estimation is not about memorizing numbers. It is about demonstrating that you know which numbers matter and how they shape architecture decisions.

The estimation method is always the same: start from users, narrow to active users, convert to requests per second, then derive storage and bandwidth. The trick is knowing which number in the chain is the one that actually forces an architectural change.

The Estimation Chain for Ride-Hailing

Start with the big number: "Assume 1 million active drivers at peak." Now drill down:

Location updates: 1M drivers sending 10 updates per minute = 10M updates/min ÷ 60 ≈ 166K writes per second. Each update is small — maybe 100 bytes (driver ID, lat, lng, timestamp). That is ~16 MB/s of location data. This is the number that shapes the architecture. A single PostgreSQL instance handles maybe 10–20K writes/sec under ideal conditions. We need something purpose-built for high-frequency transient writes.

Ride requests: Maybe 10,000 new ride requests per minute at peak = ~170 requests/sec. This is roughly three orders of magnitude smaller than location updates (166K vs 170 per second). A well-tuned web server handles this comfortably. This does not need special architecture.

Trip state transitions: Each trip goes through 5–6 state changes (requested, matched, driver en route, picked up, in progress, completed). At 170 rides/sec, that is about 1,000 state transitions per second. Modest. Needs strong consistency but not exotic infrastructure.

Why This Matters

The estimation reveals that location updates dominate the write load by 100x or more. This single insight justifies the entire architectural split: location data goes to a high-throughput, eventually-consistent store (Redis, an in-memory spatial index); trip data goes to a strongly-consistent relational database. Without the estimation, this split looks arbitrary. With it, the split is inevitable.

Compare the workloads side by side: location updates are high volume, low value per record, tolerant of staleness, and transient. Trip records are low volume, high value, require strong consistency, and are permanent. Payment records are even lower volume but need the strongest guarantees of all. Each category points to a different storage strategy, and the estimation is what makes that visible.

Key takeaways
  1. 01Follow the chain: users → active users → requests/sec → storage → bandwidth.
  2. 02Identify the dominant workload — for ride-hailing, it is location updates at ~166K writes/sec.
  3. 03Compare workloads by orders of magnitude to justify architectural splits.
  4. 04The estimation method matters more than memorized numbers.
Interview 04

Key Decisions to Discuss

Every system design has 4–6 decisions that interviewers expect you to reason about explicitly. For a ride-hailing platform, these are the ones. For each, state the problem, name alternatives, pick one, and acknowledge the trade-off.

Why separate location storage from trip storage?

The problem: Location data arrives at ~166K writes/sec; trip data at 1K writes/sec. Mixing them in one database means the location workload dominates I/O and makes trip queries slow.

Options: (1) Single database with partitioned tables. (2) Separate databases for each workload. (3) In-memory store for locations, relational DB for trips.

Decision: Option 3. Location data is transient — you only care about the latest position. Trip data is permanent and relational. Different access patterns, different consistency needs, different stores.

Trade-off: Operational complexity increases. You now have two data stores to monitor, backup, and understand. Worth it because a single store cannot serve both workloads well at scale.

Swipe to pan
Storage Separation · hot vs. transactionalApp Serversride serviceRedisdriver location · geo indexPostgreSQLtrips · users · payments166K writes/stransactional writesClientsrider + driver
Location data is transient and high-volume — it needs different storage than durable trip records

Why Redis for locations instead of PostgreSQL?

The problem: ~166K location writes/sec with reads that ask "find all drivers within 2km of this point."

Options: (1) PostgreSQL with PostGIS. (2) Redis with geospatial commands (GEOADD/GEOSEARCH). (3) Custom in-memory spatial index.

Decision: Redis. It handles the write throughput easily, supports geospatial queries natively, and the data is inherently transient — a driver's location from 30 seconds ago is worthless. If Redis restarts, drivers re-send their positions within seconds.

Trade-off: No durability guarantee for location data. Acceptable because stale location data has zero business value. PostgreSQL with PostGIS could work at lower scale but becomes the bottleneck at ~166K writes/sec without significant tuning and sharding.

How do you prevent double-assigning a driver?

The problem: Two ride requests arrive simultaneously for two riders near the same driver. Without coordination, both could be assigned to the same driver.

Options: (1) Optimistic locking in the database. (2) Distributed lock per driver. (3) Single-threaded matching per geographic zone.

Decision: Use an atomic conditional update in PostgreSQL: UPDATE driver SET status = 'assigned' WHERE id = X AND status = 'available'. If the row was already claimed by another transaction, zero rows are updated and the matching service simply moves to the next candidate. No distributed lock is needed — the database's own row-level locking during the UPDATE provides the mutual exclusion.

Trade-off: If two matching attempts target the same driver simultaneously, the loser must retry with the next-best candidate, adding a round-trip of latency. Acceptable because double-assignment is a terrible user experience — both riders see a driver accepted, then one gets cancelled — and the retry cost is small compared to that risk.

Swipe to pan
Race Condition · Driver Double AssignmentWITHOUT FIXRider ARider BMatchingDriver X: availableDriver X: availabledouble-booked!WITH ATOMIC CASRider ARider BMatchingUPDATE...WHEREstatus=available1 winsother re-matchesAtomic compare-and-swap prevents concurrent assignment of the same driver.UPDATE drivers SET status = 'assigned'WHERE id = $1 AND status = 'available'-- rows_affected = 1 ? success : retry
Atomic conditional UPDATE ensures only one assignment succeeds

What is synchronous vs asynchronous in this system?

Synchronous (user-blocking): Ride request → matching → driver notification. The rider is waiting. This path must be fast and reliable. Every millisecond of latency is felt.

Asynchronous (background): Fare calculation, trip history writes, analytics events, driver earnings updates, notification delivery. These happen after the critical user interaction and can tolerate queuing.

Decision: Use a message queue (Kafka or similar) to decouple the synchronous request path from asynchronous downstream processing. Trip state changes publish events; consumers handle analytics, billing, and notifications independently.

Trade-off: Eventually consistent for downstream data. A rider might see their trip history update a few seconds after completion. Acceptable for a dramatically simpler and more resilient critical path.

How does the rider get real-time updates?

The problem: During a trip, the rider needs to see the driver's location updating every few seconds on a map.

Options: (1) Polling — rider app requests driver location every N seconds. (2) Long polling. (3) WebSockets — persistent connection with server-pushed updates. (4) Server-Sent Events (SSE).

Decision: WebSockets for active trips. The connection is persistent, bidirectional, and efficient for the continuous stream of location updates during a trip. For pre-trip status updates ("driver is 3 minutes away"), SSE or polling is sufficient.

Trade-off: WebSocket connections are stateful, which complicates load balancing and horizontal scaling. You need sticky sessions or a connection-aware routing layer. Worth it because the alternative — 500K riders polling every 2 seconds — creates 250K requests/sec of unnecessary load.

Key takeaways
  1. 01For every key decision: state the problem, name 2–3 options, pick one, acknowledge the trade-off.
  2. 02The five decisions interviewers expect: storage split, location store choice, concurrency control, sync vs async, real-time delivery.
  3. 03Never present a decision as obvious — always show your reasoning.
Interview 05

Handling Pushback

When an interviewer challenges your design decision, they are not attacking you. They are giving you the opportunity to demonstrate the most valuable engineering skill: reasoning about trade-offs under pressure.

Pushback is the best part of the interview. It is where you differentiate yourself from candidates who memorized architectures. Your goal is not to defend your choice — it is to reason about it. Sometimes reasoning leads you to change your mind, and that is a strong signal, not a weak one.

"What if PostgreSQL can handle the location writes?"

Good response: "It can, at lower scale. PostgreSQL with connection pooling and write-optimized configuration can handle tens of thousands of writes per second. But our estimation showed ~166K writes/sec for location updates. To handle that in PostgreSQL, we would need sharding across multiple instances, and each query would need to hit the right shard. At that point, we have the operational complexity of a distributed system but without the benefits of a purpose-built geospatial store. Redis gives us the throughput with built-in geospatial indexing. That said, if our scale estimate is wrong and we are actually at 20K writes/sec, PostgreSQL with PostGIS is a perfectly reasonable choice and simpler to operate."

"Do you really need Kafka here?"

Good response: "Let me think about what happens without it. If the trip service directly calls the analytics service, the billing service, and the notification service on every state change, we have tight coupling. If the billing service is slow or down, it either blocks the trip flow or we lose the event. Kafka decouples these: the trip service publishes an event and moves on. Downstream services consume independently, at their own pace, with replay capability if they fall behind. The alternative is a simpler direct-call architecture with retry logic and a dead-letter table in our database. That works at smaller scale but becomes fragile as we add more consumers."

"What about consistency?"

Good response: "Not all data in this system needs the same consistency guarantees. Driver location is inherently approximate and transient — a location that is 3 seconds stale is perfectly usable for matching. Trip state transitions, on the other hand, need strong consistency. If a trip moves from 'in progress' to 'completed,' that must be exactly once and durable, because it triggers billing. Payment records need the strongest guarantees of all — we would use database transactions with serializable isolation for anything involving money. The key insight is that choosing eventual consistency where it is safe lets us use strong consistency where it matters, without making the entire system slow."

"What happens if Redis goes down?"

Good response: "Matching degrades significantly. We cannot find nearby drivers without the location index. But the impact is bounded: drivers continue sending location updates, and those are lost until Redis recovers. On recovery, the location index rebuilds itself within seconds as drivers re-send their positions. Active trips are not affected because trip state lives in PostgreSQL. New ride requests would fail or fall back to a broader, less efficient matching strategy. We could mitigate this with Redis Cluster for high availability, or a standby replica with automatic failover. The recovery time is fast because we are not restoring historical data — we just need the latest position from each active driver."

“The strongest signal in a system design interview is how you reason about trade-offs, not which technologies you name.”

— A common theme in system design interviews

The pattern in every good answer is the same: acknowledge the validity of the challenge, reason about the alternatives, explain your trade-off, and show where your decision might change under different assumptions. The key skill is not defending — it is reasoning.

Key takeaways
  1. 01Pushback is an opportunity, not an attack. Welcome it.
  2. 02Acknowledge the alternative, reason about trade-offs, explain your decision.
  3. 03Be willing to change your mind if the reasoning leads there — that is a strong signal.
  4. 04The pattern: "You are right that X could work. Here is why I chose Y, and here is when I would choose X instead."
Interview 06

Common Mistakes

These are the mistakes that experienced interviewers see repeatedly. Each one is avoidable with awareness and practice.

Mistake 1: Starting with the final architecture

You walk up to the whiteboard and draw 12 boxes with arrows between them. The interviewer cannot tell if you understand the system or memorized a diagram. Instead: start with three boxes (client, server, database), identify the first bottleneck, and add one component at a time. The evolution of the design IS the demonstration of understanding.

Mistake 2: Naming technologies without justification

"We will use Kafka." Why? "Because it is good for event streaming." That is a tautology. Instead: "We need to decouple the trip service from downstream consumers. The trip service publishes state changes, and billing, analytics, and notifications each consume independently. A durable message queue with consumer groups fits this pattern. Kafka is a strong choice here, though RabbitMQ or even a database-backed outbox pattern could work at lower scale."

Mistake 3: Ignoring scale estimation

Without estimation, every architectural decision is an opinion. With estimation, decisions become conclusions. "We need a separate location store" is an opinion. "We need a separate location store because ~166K writes/sec exceeds what a single relational database handles efficiently" is a conclusion. Even rough numbers — order-of-magnitude estimates — transform the quality of your reasoning.

Mistake 4: Treating all data the same

Location data and trip data have fundamentally different characteristics. Location data: high volume, low value per record, tolerant of staleness, transient. Trip data: low volume, high value, requires strong consistency, permanent. Payment data: very low volume, highest value, requires transactions, auditable. When you store them the same way, you optimize for nothing. When you recognize the differences, the architecture designs itself.

Mistake 5: Not discussing failures

If you present a design where nothing fails, the interviewer will make something fail for you. Get ahead of it. "What happens if the matching service goes down? New rides cannot be matched, but active trips continue because the driver app communicates location directly. We need a queue to buffer incoming ride requests so they can be processed when the service recovers." Discussing failures proactively shows operational maturity.

Mistake 6: Over-engineering for small scale

If the interviewer says "design this for a city of 50,000 people," you do not need sharding, multi-region replication, or a custom spatial index. A single PostgreSQL instance with PostGIS handles this comfortably. Over-engineering for scale you do not have is as much a red flag as under-engineering for scale you do have. Match your architecture to the requirements, not to the most impressive technology you know.

Mistake 7: Not managing time

Spending 20 minutes exploring requirements is thorough but fatal — you have no time left for the actual design. Spending zero minutes on requirements means every design decision is unjustified. The 5-5-15-5-5 split (requirements, high-level, deep dive, scaling, buffer) is not magic, but it is a reliable guardrail. Practice it until the time management is automatic.

Interview 07

The Summary Pitch

At the end of the interview, you may be asked: "Can you summarize your design?" This is your closing argument. You have two minutes to walk through the system, highlight key decisions, and leave the interviewer with a clear picture of your thinking.

The Summary Template

Follow this structure and you will never fumble the summary:

1. Name the core services (10 seconds): "The system has four core components: the Ride Service for managing trip lifecycle, the Location Service for real-time driver tracking, the Matching Service for connecting riders with drivers, and an event bus for asynchronous processing."

2. Walk through the request flow (30 seconds): "A rider requests a ride. The Ride Service creates a trip record in PostgreSQL and asks the Matching Service to find a driver. The Matching Service queries Redis for nearby available drivers, ranks them, and sends a request to the best candidate. The driver accepts, the trip state updates, and both parties receive real-time updates via WebSocket."

3. Highlight key decisions (30 seconds): "The critical decisions were separating location storage from trip storage because location writes run at ~166K/sec while trip writes are 1K/sec, using Redis for the spatial index because the data is transient and the query pattern is geo-bounded, and using a message queue to decouple the critical ride path from downstream analytics and billing."

4. Acknowledge trade-offs (30 seconds): "The main trade-off is operational complexity — we have multiple data stores and an event bus to operate. The location service is eventually consistent, which means matching decisions are based on slightly stale data. And if Redis goes down, matching degrades, but active trips are unaffected."

5. What would change (20 seconds): "If this were a smaller-scale system — say 10,000 drivers — I would collapse the location service into PostgreSQL with PostGIS and skip the message queue in favor of direct service calls. The architecture would be simpler because the scale does not demand the separation."

Example Two-Minute Summary

"The ride-hailing platform I designed has four main components. The Ride Service manages the trip lifecycle in PostgreSQL — it handles state transitions from requested to completed with strong consistency guarantees. The Location Service ingests driver positions at roughly 166K updates per second into Redis, which also serves as our geospatial index for driver matching. The Matching Service queries Redis for nearby available drivers when a ride is requested, uses atomic state transitions to prevent double-assignment, and notifies the selected driver in real time.

Downstream processing — billing, analytics, notifications — is handled asynchronously through Kafka. The trip service publishes state-change events, and each downstream consumer processes them independently. This keeps the critical path fast and prevents a billing outage from blocking riders.

The key trade-off is complexity versus resilience. We have three data stores and an event bus, which is more to operate. But each component is optimized for its workload, and failures are isolated — Redis going down stops new matching but does not affect active trips. If I were designing this for a much smaller city, I would use a single PostgreSQL database with PostGIS and skip the event bus entirely. The architecture should match the scale."

Closing: What Would You Change?

Always end by showing you can think beyond the design you just built. This signals flexibility and judgment. Some options: "If latency requirements were tighter, I would look at edge computing for the matching service." "If we needed multi-region, the location service scales naturally but trip state would need conflict resolution." "If cost were the primary constraint, I would start with a monolith and extract services as bottlenecks emerge." Pick one that is relevant and shows you are thinking about real engineering trade-offs, not theoretical ones.

Key takeaways
  1. 01Structure the summary: services, request flow, key decisions, trade-offs, what would change.
  2. 02Keep it under two minutes — this is a summary, not a re-explanation.
  3. 03Every decision you mention should trace back to a requirement or a number from your estimation.
  4. 04End with what would change under different constraints — this demonstrates engineering flexibility.
  5. 05The interview tests judgment, not knowledge. Show how you think, not just what you know.
Interview 08

Question Bank: Likely Questions & Follow-Ups

The sections above teach you how to run the conversation — how to open, structure, and close a system design interview. This section covers the other half: what actually gets asked, and the realistic follow-up questions an interviewer uses to push past your first answer. Each entry links to the relevant Architecture Deep Dive or Trade-offs section for the mechanics rather than re-explaining them here — this page's job is interview framing, not re-teaching what's already covered elsewhere.

Scope & Requirements

Q

"Design Uber." (the deliberately vague opener)

Strong answer angle

Don't guess — this is a scope-negotiation moment, not a design moment. Follow the Four-Step Opening from How to Start: ask what's actually in focus (matching? payments? surge?) before drawing anything.

Likely follow-ups
  • "What if we also need to support shared rides (Pool)?" — Tests whether you can extend a design rather than restart it; a strong answer identifies that shared rides mainly affects the matching stage (multi-passenger scoring) without touching the storage architecture.
  • "What if a driver's phone loses connectivity mid-trip?" — Tests failure-mode thinking on the spot; ties to the Redis-recovery reasoning already covered in Failure & Scale Scenarios.
  • "How would this change if we had to support 10 different countries with different regulations?" — Tests whether you understand data residency and multi-region trade-offs, covered in Single Region vs Multi-Region.

Driver Matching

Q

"How does Uber decide which driver to send a ride to?"

Strong answer angle

Walk through the four-stage pipeline (discover → filter → score → select), emphasizing that ETA dominates the score, not raw distance.

Likely follow-ups
  • "What if two ride requests both want the same driver at the same time?" — Tests whether you know the atomic-CAS solution, or whether you'd reach for a distributed lock (a common but heavier-handed wrong answer).
  • "Your greedy matching keeps picking the same driver as the best option for every nearby rider — what happens?" — Tests awareness of fleet-wide optimization versus naive greedy matching.
  • "How would you make this fair to drivers who've been waiting the longest?" — Tests whether you can layer a fairness constraint into a scoring function, not just distance/ETA.

Geospatial / Location

Q

"How would you find all drivers within 2km of a rider?"

Strong answer angle

Explain why this is a spatial-indexing problem, not a WHERE-clause problem — naive lat/lng range queries scan two dimensions poorly. Point to the Geohash explainer in Architecture Deep Dive.

Likely follow-ups
  • "Why not just use a SQL query with a bounding box?" — Tests whether the candidate understands why relational indexes handle 1D ranges well but 2D poorly.
  • "What's the downside of geohash?" — Tests awareness of edge-cell inaccuracy (two nearby points can have very different prefixes near a cell boundary) — the Geohash vs Quadtree vs H3 comparison is built to equip a reader to answer this.
  • "How would this change if drivers were spread very unevenly — dense downtown, sparse suburbs?" — Tests whether the candidate knows a quadtree adapts to density and a fixed geohash grid doesn't.

ETA

Q

"How would you estimate how long it'll take a driver to reach the pickup point?"

Strong answer angle

Present it as a spectrum of approaches (naive → routing-engine → ML), not a single answer.

Likely follow-ups
  • "Straight-line distance says Driver A is closest — why might they actually arrive later than Driver B?" — Tests whether the candidate understands road topology (rivers, highways, one-way streets) breaks naive distance.
  • "How would your ETA model handle a sudden road closure or accident?" — Tests whether the candidate thinks about real-time signal freshness, not just historical averages.

Surge Pricing

Q

"Design the surge pricing algorithm for Uber."

Strong answer angle

Start with the supply/demand signal pipeline, then the multiplier calculation — but the strongest answers explicitly address the feedback loop (price affects both supply and demand at once), which is the actual differentiator.

Likely follow-ups
  • "How do you prevent drivers from gaming the system by going offline to wait for surge?" — Tests anti-gaming awareness (minimum surge duration, geographic smoothing).
  • "How do you ensure surge doesn't consistently penalize lower-income neighborhoods?" — A genuinely hard fairness question with no fully clean answer; a strong response acknowledges the tension rather than claiming a perfect fix.
  • "What happens to your pricing model during a genuine emergency (e.g. a natural disaster) when surge would be predatory?" — Tests whether the candidate thinks about caps/overrides on top of the algorithmic model, not just the algorithm itself.

Data & Consistency

Q

"Why is driver location in Redis instead of your main database?"

Strong answer angle

Point to the two-workload framing — throughput and durability requirements are fundamentally different for location vs. trip data.

Likely follow-ups
  • "What happens to in-flight matching if Redis goes down?" — Tests whether the candidate has internalized the degraded-mode behavior from Failure & Scale Scenarios.
  • "Could you use Redis as your only datastore for everything?" — Tests whether the candidate understands Redis's durability trade-offs, not just its speed.

Trip State Machine

Q

"How do you make sure a trip can't be double-completed or go 'backwards' in state?"

Strong answer angle

Frame the trip as an explicit state machine with a fixed set of legal transitions, enforced server-side — reject (rather than silently ignore) any transition that isn't legal from the current state. Point to the trip state machine deep dive for the exact states and transitions.

Likely follow-ups
  • "What if two state-change events for the same trip arrive out of order?" — Tests whether the candidate reaches for a version/sequence check on the trip record rather than assuming events always arrive in order.
  • "How is this different from the double-dispatch problem in matching?" — Tests whether the candidate distinguishes assignment-race protection (one driver, two riders) from state-transition protection (one trip, illegal transition) — related concepts, not the same mechanism.

Real-Time Updates

Q

"How would you push a driver's location to a rider's app in near real time?"

Strong answer angle

Explain why this is a push, not a poll, problem at this frequency and scale, and point to the Real-Time Service deep dive for how per-user delivery over WebSocket connections actually works.

Likely follow-ups
  • "How does this scale to millions of concurrent connections?" — Tests awareness of connection-server horizontal scaling and why a single process can't hold every connection — the core scaling concern the Real-Time Service deep dive covers.
  • "What happens when a rider's app reconnects after losing signal for 30 seconds?" — Tests whether the candidate thinks about resuming from the current state rather than replaying every missed update — a reconnection needs the latest snapshot, not a backlog.

Scaling

Q

"How would this design change if Uber suddenly operated in 500 cities instead of 50?"

Strong answer angle

Distinguish what scales linearly with geography (matching, location indexing — both are already geo-partitioned) from what doesn't (a single relational primary, a single regional deployment). Point to Read Replicas vs Sharding and Single Region vs Multi-Region as the two decisions this question is really probing.

Likely follow-ups
  • "Which of your components would break first at 10x the cities?" — Tests whether the candidate can reason about bottlenecks rather than reflexively saying "add more servers" — a single PostgreSQL primary, not the geo-partitioned services, is the likely first constraint.
  • "Would you shard by city, region, or something else?" — Tests whether the candidate connects the sharding key choice back to how queries are actually made (most queries are naturally scoped to a city or region already).

Failure

Q

"What's your plan if an entire AWS region goes down?"

Strong answer angle

This is the regional-failure scenario, not a single-component failure — point to the Regional Failure scenario for detection, failover, and blast-radius reasoning rather than re-deriving it live.

Likely follow-ups
  • "How do you avoid losing in-flight trips during a regional failover?" — Tests whether the candidate understands what state must be replicated cross-region ahead of time versus what can be safely rebuilt after failover.
  • "How long is an acceptable failover time, and why?" — Tests whether the candidate can reason about the business cost of downtime for an in-progress ride versus a not-yet-requested one — not every failure mode has the same acceptable recovery time.

Cross-Cutting Curveballs

Q

"How would this design change for Uber Eats instead of ride-hailing?"

Strong answer angle

Identify what's genuinely reusable — geospatial matching and real-time tracking both transfer directly — versus what changes: multi-item orders replace a single rider/driver pairing, and restaurant prep time becomes a new, harder-to-predict input into the ETA calculation alongside travel time.

Likely follow-ups
  • "What's the hardest new problem Eats introduces that ride-hailing doesn't have?" — Tests whether the candidate identifies restaurant prep-time variance (and coordinating a delivery driver's arrival with an uncertain prep finish time) as the genuinely new problem, rather than treating it as a cosmetic renaming of the same system.
  • "Would the matching algorithm need to change?" — Tests whether the candidate recognizes that matching now also needs to consider which restaurant an order originates from, not just rider/driver proximity — a real, not superficial, change to the scoring function.
Q

"What would you cut if you had to launch an MVP in 6 weeks?"

Strong answer angle

Tests prioritization, not just technical depth — a strong answer keeps the core rider-request-to-driver-assignment loop and explicitly defers surge pricing, sophisticated fleet-wide optimization, and multi-region failover, naming each cut and why it's safe to defer rather than silently omitting them.

Likely follow-ups
  • "What's the risk of cutting surge pricing for launch?" — Tests whether the candidate understands surge exists to manage supply/demand imbalance, not just revenue — without it, an MVP has no lever for handling demand spikes beyond simply failing requests.
  • "What would make you reconsider and build multi-region from day one instead of deferring it?" — Tests whether the candidate ties the decision to a real constraint (e.g. a regulatory requirement for data residency in a specific launch market) rather than treating every deferred item as equally deferrable.