Free preview

A Two-Sided Real-Time Marketplace

In one line: this chapter builds directly on Yelp's quadtree, and the temptation is to treat it as Yelp with drivers. Three differences make it a genuinely harder system, and each one shows up in the architecture.

The product

Uber is a ride-hailing application that connects riders with drivers. Riders register to book vehicles for travel, while drivers register to fulfill these requests. The app facilitates real-time communication and coordination between parties via their smartphones.

The lifecycle is short and every stage is stateful:

1. Rider opens the app        -> sees nearby available drivers
2. Rider requests a ride      -> system searches for a driver
3. A driver accepts           -> both parties get each other's details
4. Driver drives to pickup    -> rider watches an ETA that must be right
5. Driver confirms pickup     -> the trip begins
6. Trip in progress           -> both sides get live updates
7. Driver ends the trip       -> payment settles, driver becomes available

Every stage is a state transition, and that is the first big difference

Compare that building block's interaction: a rider types "cafe," gets a list, and the system forgets them. Stateless, idempotent, retryable.

Here, a ride is a state machine that lives for tens of minutes and must be consistent across two phones, several services, and a payment system:

REQUESTED -> MATCHED -> ACCEPTED -> ARRIVED -> IN_PROGRESS -> COMPLETED -> PAID

Two properties follow, and both are unusual for this course.

The two parties must agree. If the rider's phone says "driver arriving" and the driver's says "trip cancelled," the product has failed in a way no amount of eventual convergence repairs — someone is standing on a street corner. That is why strong consistency appears in the non-functional requirements, and it is the first time in this course a problem chapter has asked for it.

A transition can fail after being externally observed. A driver who has accepted has already begun driving. You cannot roll that back. Compare a stale cafe rating, which costs nothing.

The state machine is the design. Nearly every component in this chapter exists to advance it, keep both sides synchronized with it, or recover it after a failure.

Three differences from Yelp

YelpUber
The objects being foundStatic — a cafe does not moveMoving — a driver's position is stale in seconds
The dominant operationReads — 5 writes/day vs 60M searchesWrites — 750,000 location updates/second
The resultA list the user browsesA match that commits two people
Consistency needEventual — staleness is invisibleStrong — both parties must agree
Failure costA slightly wrong ratingA person stranded

The read/write ratio inverts completely, and it is the single most important fact here

The Yelp chapter established a read-to-write ratio of roughly ten million to one, and nearly every decision followed from it: expensive quadtree splits were fine, ratings could rebuild daily, and locality could be traded away freely.

Here the ratio inverts. Lesson 3 will compute it precisely, but the shape is this:

Yelp:  5 writes/day        vs  60,000,000 searches/day
Uber:  750,000 writes/sec  vs  232 trips/sec

Uber's index is under continuous, massive write pressure from objects that will not hold still. The same quadtree that was nearly free to maintain at Yelp becomes the chapter's central engineering problem.

That single inversion drives:

  • A hash table in front of the quadtree, so the tree is not rebuilt at driver speed.
  • Redis absorbing writes, flushed in batches rather than applied individually.
  • Deliberately stale index data, updated every 10 to 15 seconds rather than every 4.

The same data structure under a different read/write ratio is a different engineering problem. Recognizing that is worth more than remembering that both chapters use quadtrees.

A moving target means the index is always wrong, and the design accepts it

A cafe indexed today is at the same coordinates next year. A driver indexed four seconds ago has moved — perhaps 100 metres at city speed, more on a highway.

So the spatial index is never exactly right, and the interesting question is not how to make it correct but how wrong you can afford it to be.

That reframing licenses the design's most important optimization. Lesson 7 updates the quadtree every 15 seconds rather than every 4 — meaning a driver's indexed position can be up to a few hundred metres off.

Is that acceptable? Yes, and for a reason specific to the domain: the index is used to produce candidates, not decisions. "Which drivers are roughly nearby" tolerates hundreds of metres of error, because the exact position comes from the hash table when a real match is made, and because a driver 300 metres from where you thought is still a perfectly good match.

When an index feeds a candidate set rather than an answer, its accuracy requirement is far weaker than it appears. That is the reasoning behind the entire two-tier location design.

What this chapter adds that no previous chapter had

Two subsystems appear here for the first time in the course.

Money. The ChatGPT chapter had billing, but it was a metering afterthought. Here payment is a first-class subsystem with double-entry bookkeeping, authorization holds, and external payment providers — because the system is moving real funds between two parties, and the list of things to prevent is explicit: missing payments, duplicates, wrong amounts, wrong currency, dangling authorizations.

An adversary. The Yelp chapter's biggest gap was that nothing defended against review fraud. Here, fraud detection is a stated non-functional requirement with a dedicated system. That is a meaningful step up, because adversarial problems do not improve on their own and most designs ignore them.

Both exist for the same reason: when a system moves money between strangers, someone will attack it. Lessons 12 and 13 take those on.

Most spatial indexes are built once and queried often. Here the index is being rewritten continuously by every driver on the road while simultaneously being queried, which is what makes the data structure choice load-bearing rather than incidental.

Key takeaway

A ride is a state machine spanning tens of minutes and two phones, which is why this is the first problem chapter to require strong consistency — and why a failed transition strands a person rather than showing a stale rating. Three differences from Yelp: the objects move, the read/write ratio inverts (750,000 location updates per second against 232 trips), and the result is a commitment rather than a list. The moving target means the index is always wrong, and the design's key insight is that it only feeds a candidate set, so hundreds of metres of error is affordable. And two subsystems appear for the first time: money and an adversary.

Next: the requirements, and the one that is unusual for this course.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue