High-Level Design and the API
In one line: the area search service is the component that makes the whole design work, and it is easy to overlook. It is the thing that decides how much of the world to look at.
The components
| Component | Role |
|---|---|
| Location finder | Identifies the user's current location (latitude and longitude) to display on the map |
| Route finder | Calculates the path between a source and a destination |
| Navigator | Tracks the user's journey in real time. If the user deviates from the optimal path, sends updated directions and notifications |
| GPS / Wi-Fi / cellular | Technologies used to determine the user's physical position |
| Distributed search | Maintains an index mapping place names to coordinates |
| Area search service | Coordinates between distributed search and graph processing. Requests coordinates to define a map area spanning source and destination, then limits the search scope to this subgraph to optimize performance |
| Graph processing service | Runs shortest-path algorithms on the subgraph defined by the area search service |
| Database | Stores road network data as a graph — a graph database like DataStax Graph |
| Pub-sub system | Listens for events to trigger services — a path deviation triggers recalculation. Also collects location data streams for traffic analysis. Uses Kafka |
| Third-party road data | External road network data, preprocessed into a unified format |
| Graph building | Constructs the graph from third-party sources or user inputs |
| Load balancer | Distributes user requests across servers |
The area search service is the component doing the essential work
Its description is the most important sentence in the lesson: it "limits the search scope to this subgraph to optimize performance."
Lesson 2 established that running shortest-path over the global graph is infeasible. The area search service is what makes the problem tractable at all — it decides which slice of the world the graph processing service is allowed to look at.
Everything else is plumbing by comparison. Location finding is GPS. Route finding is orchestration. Graph processing runs a textbook algorithm. Choosing the subgraph is where the design's intelligence lives, and Lessons 5 through 8 are entirely about how it does that: partition into segments, connect through exit points, bound the search by aerial distance.
Notice also that it sits between distributed search and graph processing — it consumes coordinates and produces a scope. That positioning is why it is the natural place for the decision.
Two distinct services for 'find a route' and 'follow a route'
Route finder answers a one-shot question: given A and B, what is the path? Navigator does something continuous: track position, give turn-by-turn directions, detect deviation.
Splitting them is right because they have completely different profiles:
- Route finder is request-response, compute-heavy, and invoked occasionally.
- Navigator is long-lived and stateful, holding a connection for the duration of a journey — potentially hours — with low compute per update.
That is the same reason Lesson 11 needs WebSockets for the navigator: a persistent connection per active journey, which is a very different server profile from handling short bursts of routing computation.
If they were one service, the routing tier would be holding millions of long-lived connections while also doing graph work, and neither could be scaled on its own signal.
Two services rather than one is deliberate: finding a route and following a route are different jobs. Finding is a request-response query. Following is a persistent connection that streams position and pushes updates back, which is why currLocation sizes in connections rather than requests.
The workflow
- The user initiates a request. The location finder determines the starting point using GPS, Wi-Fi, or cellular.
- The user enters a destination address. A typeahead service provides suggestions to ensure accuracy.
- The user requests the optimal path, forwarded to the route finder.
- The route finder queries the area search service, which resolves latitude/longitude via distributed search and calculates the area of the map spanning these points.
- The area search service requests the graph processing service to process the subgraph within the identified area.
- The graph processing service calculates the shortest path and returns it. The route finder displays the path, including distance, time, and navigation steps.
- The navigator tracks the user's movement, updating the map location and providing turn-by-turn directions.
- If the user deviates, the navigator publishes an event to Kafka, triggering recalculation. Simultaneously it streams live location data to the pub-sub system for traffic analysis.
Step 8 does two things at once, and they serve different purposes
The deviation event and the location stream both go to Kafka, but they are not the same thing:
The deviation event is a control signal — it triggers immediate route recalculation for this user. It is urgent and specific.
The location stream is telemetry — it feeds traffic analysis benefiting every user later. It is continuous and aggregate.
That is a textbook pub-sub justification and exactly why pub-sub's model fits: one stream, multiple independent consumers. The area search service subscribes for recalculation; the analytics pipeline subscribes for traffic. Neither blocks the other, and Lesson 11 adds more consumers without touching the producer.
With a queue instead, these would compete — a deviation event might go to the analytics consumer and never trigger recalculation.
The typeahead service in step 2 is doing quiet correctness work
It looks like a UX nicety. It is a data quality mechanism.
Free-text addresses are ambiguous and misspelled. If a user types "Springfeild", geocoding either fails or resolves to something wrong — and a route to the wrong destination is worse than no route, because the user follows it.
Typeahead constrains input to known places, so the destination is a real coordinate before routing begins. It moves disambiguation to where the user can resolve it — at typing time, with context — rather than leaving the system to guess.
Same instinct as object storage's tiered resource categories: constrain user input to a set the system can handle correctly, rather than accepting anything and coping.
The API
currLocation(location) findRoute(source, destination, transport_type) directions(curr_location)
| Call | Parameter | Description |
|---|---|---|
currLocation | location | Whether the user location is on or off. Establishes a persistent connection where the client periodically updates the server about its current location. If false, the service requests the user to turn on their location |
findRoute | source, destination | The places (in text format) where the user wants to start and end |
findRoute | transport_type (optional) | Bicycle, car, airplane, and so on. Defaults to car |
directions | curr_location | The latitude/longitude of the user's current location on the map |
currLocation is not a request — it opens a persistent connection
This is the API's most unusual element and the easiest to misread. currLocation looks like a simple getter and is actually a subscription: it "establishes a persistent connection between the client and the server, where the client will periodically update the server about its current location."
So the data flows client to server, continuously, for as long as navigation is active. That inverts the normal request-response direction.
Three consequences:
Server capacity is measured in connections, not requests. Lesson 11 adds a load balancer specifically for WebSockets "to manage capacity limits" — millions of concurrent long-lived connections is the C10K profile the YouTube and Quora chapters also hit.
It is the design of the telemetry that Lesson 9's ETA computation depends on. The connection exists to serve this user's navigation, and as a side effect it produces the traffic data that improves everyone's ETAs.
Location is opt-in and can be off, which the parameter models explicitly. A user with location disabled cannot be navigated — and also contributes no traffic data, which is worth noting as a privacy-versus-accuracy tension the design does not otherwise discuss.
transport_type changes which graph you traverse, not just the speed
It is tempting to treat transport mode as a multiplier on travel time. It is not — it changes which edges are legal.
A bicycle can use paths a car cannot; a car cannot use pedestrian streets; a truck is barred from low bridges and some roads entirely. So the mode determines a different effective graph, and the same source and destination can produce genuinely different routes rather than the same route at a different speed.
It also changes edge weights, since Lesson 2 noted weights represent distance, time, or traffic — and the time to traverse an edge depends entirely on the mode.
That means precomputation (Lesson 5) is per mode: shortest paths cached for cars are not valid for bicycles. Which multiplies the precomputation and storage cost by the number of supported modes — a real cost the design does not mention, and worth raising.
Key takeaway
Twelve components, but the area search service does the essential work — deciding how much of the world to look at, which is what makes an infeasible problem tractable. Route finder and navigator are split because one is request-response and compute-heavy while the other holds a connection for hours. And currLocation opens a persistent connection rather than making a request, which is both the navigation channel and the design of all traffic telemetry.
Interview signal by level
| Level | What a strong answer sounds like |
|---|---|
| L4 | "A service finds the route from a graph database and another one gives turn-by-turn directions." |
| L5 | Identifies the scoping step: "an area search service resolves the coordinates and works out which part of the map to search, so graph processing only runs on a subgraph rather than the whole world." |
| Staff+ | Names the connection model and the mode implication: "currLocation isn't a request, it opens a persistent connection with the client pushing position updates — so that tier is sized in concurrent connections, not RPS, and it's also where all our traffic telemetry comes from. And transport_type changes which edges are traversable, not just the speed, so precomputed paths are per-mode — which multiplies the precomputation cost by the number of modes we support." |
Next: partitioning the world.