Vasu Patel logoVasu Patel
← Whiteboard to Blueprint: HLD & LLD
All chapters in this track
  1. 01Chapter 1: What HLD and LLD Are, and How They Differ
  2. 02Chapter 2: Gathering and Clarifying Requirements Before Designing Anything
  3. 03Chapter 3: HLD Deliverables: Architecture, Components, Technology Choices, Data Flow
  4. 04Chapter 4: LLD Deliverables: Class Diagrams and Sequence Diagrams
  5. 05Chapter 5: LLD Deliverables: Database Schema and API Contracts
  6. 06Chapter 6: Documenting Decisions: ADRs and Communicating Trade-offs to Stakeholders
  7. 07Chapter 7: Moving Cleanly from HLD to LLD Without Losing Intent
  8. 08Chapter 8: Common Mistakes: Over-Designing, Under-Specifying, and Skipping Non-Functional Requirements
  9. 09Chapter 9: When LLD Contradicts Its Own HLD
  10. 10Chapter 10: HLD and LLD in Design Reviews: What Reviewers Actually Look For
  11. 11Chapter 11: Worked Example: Ride-Sharing Dispatch — Requirements Through HLD to LLD
  12. 12Chapter 12: Worked Example: Hotel Booking — Requirements Through HLD to LLD
  13. 13Chapter 13: Worked Example: Food Delivery — Requirements Through HLD to LLD
  14. 14Chapter 14: How HLD and LLD Show Up in Interviews and Design Reviews
  15. 15Chapter 15: Common Interview Questions About HLD and LLD

Chapter 11 of 15

Chapter 11: Worked Example: Ride-Sharing Dispatch — Requirements Through HLD to LLD

Why this matters

This chapter walks one system completely through every stage covered in Parts 1-3 — requirements clarification, HLD with all four deliverables, and LLD with class/sequence diagrams and a schema — demonstrating the full, real process end to end rather than any single stage in isolation.

Requirements (Chapter 2)

Clarifying questions: "Is this matching riders to nearby available drivers in real time? What's the matching criteria — nearest driver, or something more sophisticated (rating, vehicle type)? What happens if no driver is available? What's the expected scale?"

Assumed answers: real-time matching to the nearest available driver within a reasonable radius; if none available within the radius, expand the search radius progressively; assume a large metro area with ~50,000 active drivers and ~200,000 ride requests/day.

HLD

Architecture diagram:

+----------+     +----------------+     +-------------------+
|  Rider   |---->| API Gateway    |---->| Dispatch Service   |
|  App     |     +----------------+     +-------------------+
+----------+              ^                       |
                           |                       v
+----------+               |              +-------------------+
|  Driver  |----(location updates)------->| Location Service   |
|  App     |                              | (tracks driver     |
+----------+                              |  positions)         |
                                          +-------------------+
                                                    |
                                                    v
                                          +-------------------+
                                          | Geospatial Index    |
                                          | (e.g., Redis with    |
                                          |  geospatial commands)|
                                          +-------------------+

Component responsibilities: Dispatch Service owns matching a ride request to a specific driver and managing the ride lifecycle; Location Service owns ingesting and storing real-time driver position updates; the Geospatial Index provides fast "nearest drivers to this point" queries.

Technology choice, with reasoning: "Redis with geospatial commands (GEOADD, GEORADIUS) for the driver location index, specifically because nearest-neighbor geospatial queries need to be extremely fast (sub-second) and driver positions update very frequently (every few seconds per active driver) — a general-purpose relational database's spatial query support would be comparatively much slower under this specific access pattern's write frequency."

Data flow — "request a ride":

1. Rider requests a ride with their current location.
2. API Gateway routes to Dispatch Service.
3. Dispatch Service queries the Geospatial Index for nearby available drivers.
4. Dispatch Service sends a ride offer to the nearest driver (via push
   notification, asynchronously).
5. Driver accepts (or the offer times out and goes to the next-nearest driver).
6. Dispatch Service confirms the match to the rider.

Capacity estimate: 200,000 rides/day ≈ 2.3 requests/second average, with a peak factor (companion System Design book, Chapter 4) likely higher than typical (rush-hour concentration) — assume peak of ~15-20 requests/second. Driver location updates: 50,000 drivers × 1 update/5 seconds ≈ 10,000 updates/second — this is actually the dominant write load on the system, far exceeding ride-request volume, and should drive the Location Service and Geospatial Index's capacity planning specifically.

LLD — deep-dive on the Dispatch Service (Chapter 13's "identify the hardest part" principle, applied here)

Class diagram:

+---------------------------+
|        RideRequest         |
+---------------------------+
| - id: string               |
| - riderId: string          |
| - pickupLocation: GeoPoint |
| - status: RideStatus       |
+---------------------------+
| + assignDriver(driverId)   |
| + expandSearchRadius()     |
+---------------------------+
         | ─── (association: a request is matched to a driver)
         v
+---------------------------+
|          Driver            |
+---------------------------+
| - id: string               |
| - currentLocation: GeoPoint|
| - status: DriverStatus     |
+---------------------------+

Sequence diagram — the progressive radius expansion (the genuinely tricky part):

RiderApp      DispatchService      GeospatialIndex      DriverApp
   |                |                     |                  |
   |--requestRide-->|                     |                  |
   |                |--nearbyDrivers(1km)>|                  |
   |                |<--[] (none found)---|                  |
   |                |--nearbyDrivers(3km)>|                  |
   |                |<--[driver_42]-------|                  |
   |                |--sendOffer--------------------------->|
   |                |                     |    (driver has 15s to accept)
   |                |<---------------accept()----------------|
   |<--matched------|                     |                  |

Database schema (partial):

CREATE TABLE ride_requests (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    rider_id UUID NOT NULL REFERENCES riders(id),
    pickup_lat DOUBLE PRECISION NOT NULL,
    pickup_lng DOUBLE PRECISION NOT NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'searching',
    assigned_driver_id UUID REFERENCES drivers(id),
    created_at TIMESTAMP NOT NULL DEFAULT now()
);
CREATE INDEX idx_ride_requests_status ON ride_requests(status)
    WHERE status = 'searching';  -- partial index: only searching rides
                                    -- need frequent lookup by this status

Tying it together: HLD-LLD consistency check (Chapter 9)

"The LLD's progressive radius expansion directly implements the HLD's stated matching behavior ('if none available, expand the search radius progressively') — I traced this explicitly to confirm no contradiction. The LLD's driver offer/accept flow uses an asynchronous push notification, consistent with the HLD's data flow step 4, rather than a synchronous call that would risk blocking Dispatch Service on a slow or unresponsive driver app."

Common mistakes

  1. Not identifying driver location updates as the dominant write load, focusing capacity planning entirely on ride-request volume when location updates are actually ~4,000x more frequent in this estimate.
  2. Choosing a general-purpose relational database for the geospatial index without recognizing the specific, extreme write-frequency and low-latency-query requirements that favor a specialized geospatial data structure/store.
  3. Not producing a sequence diagram for the progressive radius expansion, missing the chance to make this genuinely tricky, multi-step, timeout-involving flow explicit and reviewable before implementation.
  4. Skipping the explicit HLD-LLD consistency check, missing a chance to catch a potential contradiction (like an accidentally-synchronous driver offer flow) before implementation.

Chapter summary / cheat sheet

  • Ride-sharing dispatch's dominant load is driver location updates, not ride requests — this should drive capacity planning and technology choice (a geospatial-optimized store) specifically.
  • The genuinely hard LLD problem: progressive radius expansion with driver offer timeouts — worth a dedicated sequence diagram given its multi-step, timing-dependent nature.
  • This worked example demonstrates the complete requirements → HLD (all four deliverables) → LLD (class diagram, sequence diagram, schema) → consistency-check pipeline from Parts 1-3, applied concretely to one real system.