System-design interview · Extended interviews
Design maps and route planning
Model road and turn transitions, calculate shortest paths, version traffic and shortcuts, and scale routing separately from map tiles.
You will learn to
- Calculate shortest paths on a directed weighted road graph.
- Separate tile delivery, endpoint snapping, route search, and ETA.
- Explain versioned topology/traffic and cross-region search failure behavior.
Practice in this chapter
8 interview questions with model answers and follow-ups.
Go to interview practiceUseful foundations: Design nearby place search and friend discovery · Database indexes: B-trees, composite keys and query access · Caching: cache hits, misses, write policies and invalidation · Data partitioning and sharding
Workload and timing examples are interview assumptions.
Dotted concept links open the relevant explanation in a new tab.
01Problem and scope
A routing service finds legal paths using the selected road graph, travel profile and traffic version. Displaying the map is a separate job: delivering map tiles. In the example, A-B-D costs 4+4=8 minutes and A-C-D costs 3+8=11. The route follows legal roads with the lowest travel-time cost, which may differ from the shortest geometric path. Its estimated duration is not a guaranteed arrival time.
Represent intersections as vertices and directed roads as edges with nonnegative travel-time costs. One-way restrictions remove reverse movements. Turns may need extra state recording the incoming road. On one server, store the graph and run a shortest-path algorithm; only then discuss regional distribution.
I clarify whether the interviewer means drawing a map, computing a route, or navigating a moving driver. We build map display and point-to-point driving routes for departure now, with an optional navigation session that refreshes after incidents. We do not claim the private design of a named map provider.
The product question is “fastest under the selected road and traffic model,” not “guaranteed arrival at exactly this time.” Traffic estimates can be wrong. Access restrictions and known closures, however, are hard constraints in that selected model. The route client should not be sent across a forbidden edge merely because its geometric path is shorter.
I ask about geographic scope and choose a large country with regional deployments and cross-region routes. That makes boundary routing and consistent map versions concrete requirements without pretending every street fits on one tiny server.
02Functional requirements
- View a map. Versioned tiles for a bounding box and zoom.
- Request directions. Legal road sequence, geometry, duration, distance, and data versions.
- Avoid tolls. Search the permitted profile or clearly report no route.
- Start away from a road. Snap to an accessible candidate within a bounded radius.
- Refresh after an incident. Recompute under a newer compatible traffic/closure bundle.
- Request a matrix. Bounded origin/destination set with explicit resource limits.
Scope and acceptance boundaries
Support background map tiles, driving directions, distance, estimated arrival time, avoid-toll preferences, and known closures. Geocoding addresses, transit schedules, offline routing, and lane guidance are separate extensions. State whether departure is now or a future time; future-time costs require stronger modeling than a single current-speed snapshot.
A tile is a visual map fragment, not the routing graph. Snapping connects a GPS point to plausible accessible roads. Map matching interprets a sequence of noisy GPS observations. Routing engines expose these operations separately; OSRM is one documented implementation. OSRM API.
A no-route result differs from a snapping failure. A point may have no plausible accessible road, or two valid snapped points may be disconnected under current restrictions. Those conditions receive separate codes and user guidance.
An alternative-route feature promises a small set of meaningfully different valid candidates, not every possible path. We keep it optional because finding diversity and ranking alternatives requires more work than one shortest-path result. Geometry simplification for display must not change the underlying legal road sequence used for directions.
03Non-functional requirements
- Workload. Assume ten million route requests/day and a 2,000/s peak.
- Latency. Target route p95 below 300 ms for ordinary regional trips and tile p95 below 100 ms from a nearby edge cache.
- Availability. Target 99.9% routing availability. The sample algorithms do not supply this objective automatically.
- Update freshness. Publish validated topology daily, normally refresh traffic weights within one minute, and target trusted urgent-closure ingestion within ten seconds.
- Version consistency. Use one compatible immutable bundle of topology, turn restrictions, weights and acceleration structures. Return its versions and traffic freshness.
- Closure validation. Before returning a route, check its roads and turns against the closure data available at final validation, then return that data's version and the validation time.
Safe degradation
| Missing or invalid input | Permitted response |
|---|---|
| Current traffic unavailable | Use labeled historical weights while preserving known access restrictions |
| Invalid topology or incompatible artifacts | Fail or fall back to a verified base search |
| New closure after response | Notify active navigation sessions to recompute |
An older estimate can still describe one consistent road model. Mixing versions can instead pair shortcuts with costs or roads that no longer match. Never invent a route to meet uptime. No service can guarantee knowledge of an unreported physical incident; an already returned route can be invalidated by a newly reported closure.
04Capacity estimates
| Quantity | Calculation | Consequence |
|---|---|---|
| Route requests | 10M/day / 86,400 ≈ 116/s average | Design for separate peaks |
| CPU at assumed peak | 2,000 queries/s × 0.05 CPU-s = 100 cores | Before redundancy/headroom |
| Tile reads | 1B/day / 86,400 ≈ 11,574/s | CDN delivery dominates reads |
| Raw edge metadata | 100M directed edges × 32 B = 3.2 GB | Geometry/turn data/indexes add much more |
The 50-millisecond CPU cost is a benchmark assumption, not an engine guarantee. Long rural/interregional routes may explore more graph than short city trips. Cache immutable tile versions separately from short-lived traffic-sensitive route results.
With a 60% planned CPU utilization ceiling, the assumed 100 cores of route work implies about 167 cores before redundancy. Surviving the loss of one of three equally sized zones while maintaining that utilization would require more reserved capacity. A worker may reach its memory-bandwidth limit first, especially if the search repeatedly fetches graph data that is not nearby in memory.
At an illustrative 20 KB route response, 2,000 routes/s yields 40 MB/s of response payload. Tile traffic is different: one billion 30 KB tiles/day is 30 TB/day, about 347 MB/s average, before peaks. A CDN is therefore justified by repeated immutable map content even if route computation stays regional.
A 100-by-100 travel-time matrix contains 10,000 pairs. A specialized many-to-many algorithm can reuse work, but the request is not equivalent to one route. Cap matrix dimensions and use estimated work, rather than HTTP request count, when deciding how many matrices to admit.
Version retention multiplies graph memory or disk. Three simultaneously loaded 3.2 GB raw edge sets require 9.6 GB before geometry, turns, shortcuts, indexes, and worker overhead. Retain only the bundles needed for active queries, rollback, and the declared replay window, with explicit query pins: records that prevent cleanup from deleting a graph bundle while a query is using it.
05APIs and contracts
Route request and response
POST /routes accepts {requestId:"q61",origin:[lon,lat],destination:[lon,lat],mode:"car",avoidTolls:true,departure:"now"}. The response includes snapped endpoints, durationSeconds=480, distanceMeters, turn steps, geometry, bundleId, closureVersion, and trafficObservedThrough. A retry is a fresh computation unless a client explicitly requests the same retained bundle; route calculation itself has no financial side effect requiring a persistent idempotency ledger.
Distinct error outcomes
Invalid coordinates, unsupported profiles, excessive matrix size, no accessible segment, and no connecting route are distinct errors. Returning straight-line distance as a driving route would misrepresent the product. If a matrix offers a fallback estimate, each such cell must be flagged as estimated rather than a valid road path.
Tile and route-cache identities
Tile URLs include style and immutable map version as well as zoom/x/y. Route-cache identity includes profile, snapped endpoints, avoidance preferences, departure assumptions, and compatible bundle version. Rounding endpoints too much can move them across a divided road or onto an overpass. Any cache-key simplification must preserve the chosen road connection.
Navigation session and privacy
A navigation session supplies a route ID, current location, and last accepted closure version. Position updates are authenticated and short-lived. They are not exposed through public cache keys or reused as another user's raw trace.
06Data model and access patterns
Store both the actual road connections and the built data structures that speed up search. A shortcut is a search edge summarizing an existing path; it must retain enough information to expand back into those roads. It does not create a new legal road connection. The bundle manifest identifies the road, turn, weight and shortcut versions built to work together; publication checks that they are compatible.
| Record | Material fields | Use |
|---|---|---|
| Directed edge | edgeId, from, to, geometry, access classes | Legal road movement |
| Turn rule | incomingEdge, outgoingEdge, profile, restriction/cost | Prohibit or penalize specific turns |
| Weight | edgeId, version, travel time, observation age | Travel-time cost used in this bundle |
| Snap index | spatial cell, accessible edge candidates | Attach coordinates to plausible roads |
| Shortcut | endpoints, expanded path, cost, compatibility version | Faster search that expands back to real roads |
| Bundle manifest | topology, turns, weights, shortcuts, checksums | Atomic compatible release |
| Closure overlay | affected edge/turn, version, effective interval | Hard access constraint |
| Tile object | map/style version, zoom, x, y | Cacheable visual display |
Raw map edits and consent-based observations are source inputs. Built routing graphs and tiles are derived artifacts. The bundle manifest is authoritative for which compatible artifacts are serving. A traffic update referencing removed edge IDs cannot be blindly applied to a new topology; builders map or reject incompatible observations before publication.
Location histories receive a separate short retention and access policy from public road geometry. Aggregated traffic should not allow a route query to retrieve an individual driver's trace.
A snapped point may lie partway along a road edge. Add temporary directed connectors or split that edge for the query. Use proportional or model-derived travel costs, while keeping its turn and access restrictions. On a one-way 1,000 m segment, an origin 200 m from its start and destination 900 m from its start imply a 700 m forward traversal, not a full 1,000 m edge or an illegal reverse shortcut. Candidate snapping also needs a bounded search policy: selecting one plausible candidate is not proof of the best route across all plausible candidates.
07Basic working design
The first server loads a directed, turn-aware graph and its spatial index into memory. For q61 it validates the car profile, chooses accessible snap candidates near A and D, and runs Dijkstra under fixed nonnegative travel-time weights. It relaxes tentative distances by checking whether each explored edge gives a cheaper known path, saving the predecessor edge whenever it does. When D is settled—its minimum cost is established—the server follows those saved edges backward to reconstruct the route.
In the example graph, A→C initially looks promising at three minutes, but its continuation to D costs eight, producing eleven total. A→B takes four and B→D four, so that path wins at eight. The server returns the real edge sequence, turn instructions, geometry, and the pinned data version. Map tiles can be served as simple static files separately.
This baseline supports a legitimate small routing product. It has no distributed graph transaction and no need to move a query between servers. A map refresh builds a second immutable graph and switches a local pointer only after validation, allowing in-flight queries to finish on their old version.
We deliberately begin with correct base search. Accelerating an incorrect access model only returns illegal answers faster. Turn restrictions, one-way roads, and unreachable endpoints are tested before adding hierarchy shortcuts or regional sharding.
The graph is turn-aware and pinned for the request; tiles are a separate display artifact.
Read each connection in order
- syncq61: A to D, carMap client → Route application
- syncSnap and search fixed weightsRoute application → Directed graph + snap index
- syncA–B–D / eight-minute estimateRoute application → Map client
- syncLoad visual map tilesMap client → Static tile objects
08Find the baseline flaws
At the assumed peak, fifty milliseconds of CPU per query consumes one hundred cores. A single worker cannot provide that compute, and long interregional paths may explore far more state than the average. Map tiles additionally create repeated bandwidth load unrelated to route CPU. Separate tile bandwidth from route computation when sizing servers.
A correctness failure appears when a worker uses a shortcut A→D with cost 8 built from A→B→D, while a live update closes B→D. If it treats the shortcut as an independent legal road, it still returns eight minutes through a forbidden segment. The acceleration structure must be compatible with changed constraints or the query must fall back to a method that checks them correctly.
Another failure comes from naive regional partitioning. The fastest valid route between two points inside region X may leave X and reenter. Searching only X or selecting the nearest border misses valid candidates. Regional boundaries are deployment choices, not road-access restrictions.
Finally, a nearest geometric snap can place the route client on a motorway above a local street without an accessible ramp. Directions then begin with an impossible movement. Snapping uses mode, direction, road access, and a bounded set of candidates, not only Euclidean distance.
09Improve the design, step by step
The baseline already finds a valid shortest path; the scaling question is how to examine less graph or spread independent queries across machines. For the shortest-path guarantee used here, A* guides exploration with an estimate no greater than the remaining cost. Preprocessed methods instead build reusable path summaries before requests arrive. Those are different ways to reduce search work, with different update costs.
| Approach | Strength | Cost |
|---|---|---|
| Base Dijkstra/A* | Clear flexible search | Expensive large explorations |
| Preprocessed shortcuts | Faster long paths | Preprocessing/version compatibility |
| Regional graph shards | Smaller worker state | Boundary routing and crossings |
| Historical time profiles | Stable estimates with sparse observations | Miss current incidents |
A routing hierarchy summarizes known subpaths as shortcuts with valid costs. If weights or restrictions change, update the affected shortcut data or use a search that does not rely on it. For regional shards, an overlay records connecting border routes; a valid path may leave and reenter a region. Do not assume one boundary crossing or blindly choose the nearest border. Bound matrix sizes because n origins×m destinations can multiply work far beyond one query.
First, split immutable tile delivery from route computation. The trigger is high repeated tile bandwidth. Put versioned tiles behind edge caches while route servers compute personalized paths. This reduces origin load and improves map rendering, at the cost of cache storage and style/version lifecycle. Direct static serving remains sufficient for a small geographic product. Tile freshness does not determine traffic-weight freshness.
Second, replicate in-memory routing workers. The trigger is the 100-core peak estimate. A region-aware router sends queries to warmed workers with a compatible graph bundle already loaded. This increases parallel route throughput without changing shortest-path semantics. Each replica needs graph memory and time to load it. A new worker must check checksums and bundle compatibility before accepting requests. One larger server is simpler while measured demand fits comfortably.
Third, preprocess a valid acceleration structure. The trigger is long-route search CPU. Shortcuts or hierarchical methods summarize subpaths while retaining expansion information and compatibility requirements. The search may examine far fewer edges, but building, storing and updating shortcuts takes extra work. A base Dijkstra/A* fallback remains useful for unusual profiles or changed restrictions that invalidate shortcuts. We do not assume every hierarchy supports arbitrary dynamic weights without rebuilding.
Fourth, partition very large graphs with a compatible overlay. The trigger is a bundle too large or expensive to replicate everywhere. Regional workers handle local detail while a border overlay represents valid interregional connections and costs under the same release. Each worker stores less graph data, but workers must coordinate how a route crosses their boundaries. The overlay must permit repeated region crossings, and its selected route must expand into valid local subpaths. Full-graph replicas remain preferable when affordable because they avoid these distributed boundary concerns.
Each optimization is accepted only after comparison with a trusted base search on representative and adversarial routes. Faster average latency is not evidence that the new routing method still respects restrictions.
10Detailed architecture
Validated build pipeline
The final system has a data pipeline and a serving path. Map editors and trusted feeds supply topology and restriction updates. A traffic pipeline validates and aggregates consent-based observations. Build workers produce compatible graph, turn, weight, shortcut, and snap artifacts, test them, and register immutable bundles. A manifest authority switches the active bundle only after the required serving regions can load it.
Tile and route serving
Clients fetch tiles from a CDN backed by immutable tile objects. Route requests instead pass through authentication and admission, then a regional query router. Warm routing workers pin one manifest bundle, use a graph cache or local memory, perform search, expand shortcuts, validate closure constraints, and return the versioned result. The route cache key includes all request choices that affect the path, plus the bundle version.
Urgent closures
Trusted urgent closures enter a versioned overlay and invalidate affected cached routes or trigger navigation recomputation under the stated freshness policy. Check that the overlay’s edge IDs and expanded shortcuts belong to the selected graph; closure data cannot be applied to an arbitrary graph version.
Artifact lifetime and implementation
Builds, traffic aggregation, tile generation, and deployment are asynchronous. Query routing, snapping, search, and final validation are synchronous. Old artifacts remain pinned for active queries and rollback. A cleanup transaction cannot mark an artifact deleting while a serving manifest or valid query pin references it; publication rejects deleting artifacts. This makes retention safe even during a release race.
OSRM offers a concrete build/serve option with extraction plus either contraction-hierarchy preprocessing or multi-level partition/customization. Select the pipeline for update frequency and supported profiles, then verify its update capabilities against the one-minute traffic objective. PostgreSQL with PostGIS/pgRouting is useful for smaller graphs, spatial preprocessing and a reference shortest-path implementation. Neither product name automatically supplies this chapter’s bundle publication, urgent-closure boundary or arbitrary per-request restriction support; those contracts must be verified in the selected deployment.
Query workers pin compatible artifacts; traffic builds and tile delivery follow separate paths.
Read each connection in order
- syncLoad versioned visual tilesMap / navigation clients → Tile CDN
- syncCache missTile CDN → Immutable tile objects
- sync1. q61 route / preferencesMap / navigation clients → Route auth / admission router
- sync2. Admit and route queryRoute auth / admission router → Warm regional routing workers
- sync3. Pin compatible bundleWarm regional routing workers → Bundle manifest + query pins
- sync4. Snap / search / expand pathWarm regional routing workers → Graph / turns / weights / shortcuts
- syncRead / write exact version keyWarm regional routing workers → Versioned route-result cache
- sync5. Final closure validationWarm regional routing workers → Trusted closure overlay
- asyncTopology and turn updatesTrusted map and restriction feeds → Validated graph build workers
- asyncObserved positions / timesConsent-based observations → Traffic matching / aggregation
- asyncVersion-compatible weightsTraffic matching / aggregation → Validated graph build workers
- syncUpload tested immutable artifactsValidated graph build workers → Graph / turns / weights / shortcuts
- syncPublish ready compatible bundleValidated graph build workers → Bundle manifest + query pins
- asyncBuild immutable visual tilesValidated graph build workers → Immutable tile objects
- asyncTrusted urgent closuresTrusted map and restriction feeds → Trusted closure overlay
11Write path and acknowledgement
Topology, restrictions and traffic changes produce tested compatible artifacts. Activate a version only when the required serving workers can use the complete bundle.
GPS observations collected with consent are noisy. Use movement and direction to match a sequence to roads, reject implausible samples, aggregate speeds over time, and supplement sparse observations with historical profiles. Do not expose raw traces through route caches. Known closures remain access constraints even when live-speed updates fail.
Publish topology builds after connectivity/restriction checks and sample-route tests; switch a version manifest atomically. Keep older compatible snapshots for in-flight queries and rollback. For future departures, evaluate time-dependent edge costs at arrival to each edge. Algorithms require explicit assumptions, such as whether leaving an edge later can ever produce earlier arrival; do not reuse a static proof without those conditions.
- Each accepted observation records where it came from, when it occurred and which location use was permitted. The pipeline rejects impossible jumps and stale or malformed samples before aggregation.
- Map matching associates a sequence with plausible directed edges under a known topology. One isolated noisy point does not establish a vehicle's road or speed.
- Aggregation estimates travel time and confidence for each edge, using historical profiles when there are too few reliable samples. Trusted closure events remain hard restrictions rather than inferred low speeds.
- A build or customization job creates a candidate bundle g12/w9 with compatible turns and shortcut data. It runs connectivity, access, expansion, and sample-route comparisons against a verified reference.
- Workers stage and checksum the immutable artifacts. The manifest authority atomically publishes the compatible bundle and its serving policy, while retaining references for active old-version queries.
- Cache entries keyed to w8 are no longer selected as w9 results. Active navigation may receive a refresh notice. A failed publication leaves the previous manifest intact; uploaded candidate artifacts alone never make a release live.
The relevant time-dependent condition is called FIFO, for first in, first out: entering the same edge later cannot produce an earlier arrival at its end. This matters because a shortest-path search must know whether arriving sooner can ever be worse than arriving later. The algorithm section returns to the precise condition and what changes when waiting can help.
For departure in the future, an edge's cost depends on when the path reaches it. The static eight-minute example does not prove correctness for arbitrary non-FIFO time-dependent travel, so that extension requires a matching algorithm and explicit waiting assumptions.
12Read and delivery path
Each route keeps one compatible graph, weight set and profile while it runs. It connects endpoints to accessible roads and expands shortcuts into the actual road sequence.
| API/record | Example |
|---|---|
| Route | POST /routes {requestId:q61,origin:...,destination:...,mode:car,avoidTolls:true,departure:now} |
| Edge | r2: B→D,costMinutes=4,allowedCar=true,graph=g12 |
| Snapshot | (topology=g12,weights=w8,profile=car) |
| Matrix extension | Bounded origins×destinations → travel times |
- q61 validates locations/profile and pins g12/w8.
- The snap index finds accessible candidates A and D; nearby overpass geometry alone cannot imply access.
- Search evaluates A-B-D=8 and A-C-D=11 under those versions.
- Expand any shortcut edges into actual roads, then construct turn steps and geometry.
- Return the eight-minute estimate with freshness/version context; tiles load independently.
Include profile, endpoints, preferences, departure assumptions, and graph/weight versions in route-cache identity.
- The worker checks the expanded edge and turn sequence against the closure version at its final validation boundary. If a newly known closure invalidates B→D, it recomputes or returns a retryable update condition according to the latency budget; it does not return a route whose actual expanded path fails the selected constraints.
- It returns the bundle, validation time, traffic freshness, estimate confidence and any fallback used. The route client can distinguish current observed traffic from historical estimation.
- The query releases its artifact pin after response construction. A navigation session retains route identity and listens for relevant incident changes; it does not keep the entire old graph version alive indefinitely merely because the user has not closed the app.
A cache hit still obeys closure freshness policy. The cache key protects against accidental version mixing, but an urgent incident may deliberately invalidate an otherwise valid older cache entry. The routing product must choose that policy explicitly rather than assuming a short TTL makes every cached route safe.
13Correctness deep dive
Dijkstra repeatedly settles the unsettled vertex with the smallest known accumulated cost. From A, tentative B=4 and C=3. Settle C first: D becomes 11. Settle B next: D improves to 8. Then settling D establishes the eight-minute route for this nonnegative-cost graph. pgRouting’s Dijkstra explanation.
All edge weights in this example are nonnegative and fixed for the query. Greedily following the first cheap edge would miss the best complete route.
Remember: Choose the smallest tentative distance; update routes through that node.
Read the diagram
- Directed edges cost A-B=4, A-C=3, B-D=4 and C-D=8 minutes.
- Settle C first at 3 and discover a tentative route to D of 11.
- Settle B at 4 and improve D to 8.
- Settle D at 8; the best route is A-B-D.
A* adds a lower bound for remaining cost to guide exploration. Straight-line distance divided by a genuine maximum possible speed can be admissible; an arbitrary ETA guess may not be. If optimality is promised, pruning must preserve it. Road closures represent forbidden edges, not merely a tiny speed penalty.
The key algorithm invariant is that, with nonnegative costs, the smallest unsettled tentative distance cannot be improved through a later unsettled vertex. In the example, settling C at 3 produces D11; settling B at 4 improves D8; D is then settled at 8. Choosing C greedily and committing its entire path at the first step would be wrong. A* may guide the queue with a lower bound, but its exact correctness conditions still matter.
Publication can also race a query. Query Q must select its graph bundle as one unit while publisher P switches the active bundle:
beginRoute():
transactionally read active bundle B
require B status == ready and artifacts not deleting
acquire query pin on B
return immutable B
publish(candidate C):
verify compatible topology/turns/weights/shortcuts
require all artifacts ready and not deleting
atomically change active bundle to C with references
| Ordering | Q's interpretation | Result |
|---|---|---|
| Q pins g12/w8 before publication | Entire search uses old compatible bundle | Eight minutes, unless final closure validation requires refresh |
| P publishes g12/w9 before Q pins | Entire search excludes B→D | A→C→D, eleven minutes |
| Q observes a newer closure at final validation | Existing path is rejected if affected | Recompute or explicitly retry |
For a time-dependent edge, FIFO means departing later cannot produce an earlier arrival on that edge: t + travelTime(t) is nondecreasing. Under the appropriate FIFO assumptions, a label-setting time-dependent search can remain valid. If FIFO does not hold, waiting may improve arrival and the algorithm/state model must represent that possibility; a static Dijkstra implementation cannot simply read changing costs mid-search.
The old query retains its coherent bundle; final closure validation can require recomputation.
Read each connection in order
- syncPin ready g12/w8Routing worker Q → Manifest authority
- returnReturn artifact referencesManifest authority → Routing worker Q
- syncPublish compatible g12/w9Bundle publisher P → Manifest authority
- syncSearch w8: A–B–D cost 8Routing worker Q → Routing worker Q
- syncValidate expanded path / closure versionRouting worker Q → Closure authority
- returnB–D now prohibitedClosure authority → Routing worker Q
- syncPin new compatible bundleRouting worker Q → Manifest authority
- syncRecompute A–C–D cost 11Routing worker Q → Routing worker Q
- syncRelease old query pinRouting worker Q → Manifest authority
14Failure and recovery
| Failure or race | Required response and boundary |
|---|---|
| Closure changes during a query | While q61 uses g12/w8, an incident creates closure version w9 removing B→D. If final closure validation observes that restriction, the running query must recompute or return an explicit retry/degraded outcome; it cannot return the now-forbidden path just because its bundle was pinned earlier. A closure published after the stated validation boundary can instead invalidate an already authorized response or active route. Never mix half of w8 with half of w9. The next query on w9 selects A-C-D=11 if permitted. Urgent closures may warrant invalidating cached routes and notifying active navigation sessions. |
| Traffic/topology unavailable | When traffic is unavailable, label historical ETA; when topology cannot connect endpoints, return no route rather than fabricate one. Monitor snapping distance, no-route rate, route p99, ETA error, traffic age, graph-build failures, and cross-region regressions. Restrict access to user locations and minimize raw trace retention. |
| Query or build crash; bad release | A worker crash loses only an in-flight computation; the client can retry and may receive a newer bundle. A build worker crash leaves staged artifacts that are not serving until manifest publication. An invalid release is rolled back by changing the active manifest to a retained compatible bundle, while a trusted closure overlay still enforces known restrictions under its defined compatibility rules. |
| Control-plane partition | During a control-plane partition, warmed workers may continue under a bounded cached-manifest policy for ordinary routes. If urgent closure freshness exceeds the permitted age, the service reports degraded freshness or refuses affected safety-sensitive requests rather than claiming current knowledge. A region without the required graph or overlay cannot fabricate a cross-region path. |
| Expensive-query overload | During overload, cap expensive alternatives and matrix dimensions, queue only within the latency budget, and reserve capacity for active-navigation reroutes. Serving a stale historical ETA may be acceptable if labeled; serving a path through a known prohibited edge is a different failure and not an equivalent fallback. |
15Operations, security, and cost
Location data is sensitive. Authenticate navigation sessions, minimize raw trace retention, aggregate traffic, and restrict access to individual coordinates. Public tiles can be broadly cached, but personalized origin/destination pairs should not leak through shared logs or cache inspection. Trusted closure feeds require provenance and auditability so an unverified report cannot block an entire city automatically.
Track route p95/p99 by distance and region, snap distance, no-route rate, expanded-path restriction violations, traffic age, ETA error, and candidate-bundle validation failures. Compare ETA to completed trips with awareness of selection bias and detours; an aggregate error metric alone can conceal severe underestimation on one region or road class.
Before publication, test one-way streets, turn prohibitions, overpasses, disconnected islands, toll avoidance, border exits/reentries, and shortcut expansion after a closure. Run copies of representative queries against the candidate, previous release and a trusted base search, then compare their results without returning the candidate's answers to users yet. A canary rollout pins a fraction of traffic to the candidate and permits immediate manifest rollback.
At 167 assumed compute cores before redundancy, reducing mean CPU from 50 ms to 20 ms would reduce the same 2,000/s work from 100 to 40 core-seconds/s. That benefit must be weighed against preprocessing time and memory. If a traffic update requires rebuilding for ten minutes, a faster query engine may fail the one-minute freshness objective. Measure both sides of the tradeoff.
16Decision ledger and limitations
| Decision | Benefit | Cost and change trigger |
|---|---|---|
| Immutable compatible bundles | Reproducible search and safe rollback | Retained artifacts; rebuild when compatibility changes |
| Base search fallback | Flexible correctness reference | More CPU on long paths |
| Preprocessed shortcuts | Fast long-distance queries | Build/customization complexity and version coupling |
| Regional graph plus overlay | Each worker stores less graph data | Must preserve valid border crossings; regional calls add latency |
| CDN tiles | Cheap repeated map display | Separate visual-version lifecycle |
| Historical traffic fallback | Routes remain available with sparse observations | Less current ETA; freshness must be visible |
Start by replicating full regional bundles. Fetching individual graph vertices from remote servers would add many network waits and make the route depend on more servers staying available. When graph size forces partitioning, an overlay summarizes cross-boundary work instead of making every edge relaxation a network request.
The remaining limit is the accuracy and timeliness of input data. More cores cannot infer an unreported closure, and a mathematically shortest path under inaccurate travel times may not be fastest in reality. The product therefore returns estimates and freshness while preserving legal constraints in its known model.
Future departures, transit, and offline navigation are substantial extensions. Each changes the time model, access model, or update availability and deserves a fresh requirement discussion.
17Interview closing
“I separated map tiles from route computation. A route is a shortest legal path under the chosen cost model in a directed, turn-aware graph. I begin with a correct nonnegative-cost search and accessible endpoint snapping, then scale tiles through a CDN and route work through warmed replicas. Add precomputed shortcuts only when their versions match and they can be expanded back into valid roads.
“The hard serving guarantee is one coherent graph bundle per query. Topology, turns, weights, and shortcuts are pinned together, with final closure validation under a stated version. A release cannot make one query mix old shortcut costs and new restrictions. A route affected by a newly enforced closure must be recomputed against a compatible bundle before release, rather than retaining an invalid shortcut. Already returned routes can be refreshed through navigation notices.
“The tradeoffs are preprocessing versus freshness, graph memory versus regional boundaries, and current traffic versus labeled historical estimates. I would benchmark long and cross-border routes and test closures, overpasses, and turn prohibitions before optimizing average latency. The next measurement is whether query CPU or update-to-serving delay limits the product.”
If the interviewer adds future departures, I would use time-dependent costs evaluated at arrival to each edge and verify the relevant FIFO or waiting assumptions. The static proof would not be reused unchanged.
Practise the interview questions
Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.
Edges A→B and B→D each cost four minutes; A→C costs three and C→D eight. Which legal route from A to D is faster?
Reveal a model answer
The legal directed edge costs sum to eight minutes for A-B-D and eleven for A-C-D. The optimization target is travel time, not the number of roads or visual distance. I would explicitly include one-way/access and turn rules in the graph representation.
Interviewer follow-up
What if B→D is closed?
Reveal the follow-up answer
That movement is removed or made forbidden under the active profile. The valid eleven-minute alternative can win; a small added penalty would incorrectly leave a forbidden road usable.
What the answer must demonstrate: Calculate a legal path under the chosen cost.
Why does A* need an admissible heuristic?
Reveal a model answer
When I promise the optimal path, the heuristic must be a lower bound. In graph search I also use a consistent heuristic if closed states are never reopened, or reopen states when an admissible but inconsistent heuristic discovers a better path. Straight-line distance divided by a genuine maximum speed can provide a lower bound; an arbitrary learned ETA can overestimate.
Interviewer follow-up
Can you still use a nonadmissible heuristic?
Reveal the follow-up answer
Yes if the product deliberately accepts approximate routes and the implementation’s behavior is evaluated accordingly. I would not claim the same optimality proof after changing that assumption.
What the answer must demonstrate: Connect algorithm assumptions to the promised result.
Why not snap the route client to the geometrically nearest road?
Reveal a model answer
GPS can be near an overpass, fenced road, or wrong carriageway without a legal connection. I consider road accessibility, direction, and plausible endpoint candidates. For a GPS sequence, movement context helps choose the correct road rather than processing every point independently.
Interviewer follow-up
Is snapping the same as geocoding?
Reveal the follow-up answer
No. Geocoding resolves a human address/place into a coordinate; snapping connects coordinates to routable graph positions. Each can be a separate service and failure mode.
What the answer must demonstrate: Define adjacent location operations distinctly.
Traffic changes while a route search is exploring its graph. Which versions should the request read?
Reveal a model answer
Keep one compatible graph-and-weight snapshot throughout the search, or deliberately restart on a newer one. Arbitrarily mixing changing values makes the route cost difficult to interpret and can invalidate preprocessed shortcuts. The response should state the freshness assumptions used for its estimate.
Interviewer follow-up
What if the change is an urgent closure?
What the answer must demonstrate: Version consistency and safety refresh policy are both needed.
Can a cross-country route be composed from the nearest region exits?
Reveal a model answer
Not reliably. The nearest exit locally can lead to a much longer global route, and a valid path may reenter a region. I need an overlay that represents interregion connectivity and correct shortcut costs, then search that structure under the selected profile.
Interviewer follow-up
Why keep a base-graph fallback?
Reveal the follow-up answer
Some weight/restriction changes may be incompatible with old acceleration data. A slower correct path is preferable to using shortcuts whose validity no longer holds.
What the answer must demonstrate: Local greediness does not prove global route quality.
How does tomorrow at 8 a.m. differ from leaving now?
Reveal a model answer
The cost of each edge depends on when the route client reaches it, so one frozen current-speed value per edge is insufficient. I need historical/time-dependent functions and an algorithm whose assumptions match those functions, then label the forecast uncertainty.
Interviewer follow-up
Can the same route still be cached?
Reveal the follow-up answer
Only under a key that includes departure-time/profile/model assumptions and a suitable validity interval. A route calculated for current traffic does not automatically answer a request to leave at another time.
What the answer must demonstrate: Future departure is a modeling change, not just another timestamp field.
A traffic release arrives halfway through a query. What prevents mixed weights and shortcuts?
Reveal a model answer
The query pins one immutable compatible bundle at admission. Publication switches a manifest, not individual arrays. The query either completes under that bundle or restarts under a newer one when the closure policy requires it. Artifact pins prevent cleanup while it runs.
Interviewer follow-up
Does pinning guarantee the road stays open after the response?
Reveal the follow-up answer
No. It guarantees coherent computation under known data. Final validation states its closure version and time, and active navigation can react to later incidents. Unreported or future physical events remain outside that guarantee.
What the answer must demonstrate: Distinguish internal consistency from perfect real-world knowledge.
Why can a 100-by-100 matrix overload a service with a low request count?
Reveal a model answer
It asks for ten thousand origin-destination relationships. Specialized algorithms may reuse work, but the workload is much larger than one route. I bound dimensions, estimate work, and use separate admission or asynchronous execution for large matrices.
Interviewer follow-up
Would charging every request one quota unit be fair?
Reveal the follow-up answer
No. I would charge by measured or estimated compute and output size, with limits protecting ordinary navigation traffic. Raw HTTP QPS is not a sufficient capacity measure.
What the answer must demonstrate: Count internal work, not only endpoint calls.
Blank-page exercise · 45 minutes
Build the answer yourself
Find a route from A to D across two alternatives. Scale map tiles separately, then close B→D mid-query and extend the request to a future departure time.
- Calculate both route costs by hand.
- Distinguish geocoding, snapping, matching, tiles, and routing.
- Estimate CPU and tile/graph payloads separately.
- Pin coherent versions and explain shortcut validity.
- Handle closures, regional boundaries, and future-time assumptions.
Check that each component and design decision follows from your requirements and workload.
Recall the key ideas
Answer from memory before opening each card. Explain why the choice works and what it costs. Revisit missed cards tomorrow.
Design maps and route planningWhat is a road graph?Recall first, then reveal
Vertices represent positions/states; directed edges represent legal movements with costs such as travel time.
Connections + direction + cost.
Return to lessonDesign maps and route planningWhat makes an A* heuristic safe?Recall first, then reveal
It must not overestimate the remaining cost when optimality is promised.
Lower bound, not a hopeful guess.
Return to lessonDesign maps and route planningWhy pin graph and traffic versions?Recall first, then reveal
A route’s edges, restrictions, and costs must describe one compatible view while the query runs.
One query, coherent road rules.
Return to lessonFinal revision
Summary and interview notes
Routing finds a legal shortest path under a specified directed graph, turn model and cost version. Tiles, endpoint snapping, route search and traffic estimation scale differently. Keeping each query on one compatible version of the graph, restrictions, weights and shortcuts prevents updates from mixing incompatible route calculations.
Remember these points
- Record legal directions and the road used to enter an intersection, so nearby roads are not mistaken for valid turns.
- Dijkstra requires nonnegative included costs; A* needs a valid heuristic and appropriate reopen/consistency rules.
- For endpoints partway along a road, preserve legal travel direction and charge only the cost of the part traveled.
- Pin topology, turns, weights and shortcuts together; expand and validate against the stated closure boundary.
- Traffic estimates can be stale or wrong even when the computed path is optimal for its model.
Interview tips
- Compute the two route costs by hand before discussing hierarchy or sharding.
- Test overpasses, one-way roads, prohibited turns and regional exit/reentry against base search.
- Separate query CPU, tile bandwidth and update-to-serving delay in the capacity discussion.
Important qualifications
- Future-departure routing requires time-dependent FIFO or explicit waiting assumptions.
- Engine preprocessing and supported dynamic updates vary; the custom publication contract is not implied by selecting OSRM or pgRouting.
Technical references
- OSRM API documentationPrimary descriptions of route, nearest, table, and match operations in a routing implementation.
- pgRouting Dijkstra documentationVersioned primary Dijkstra cost API reference. The worked graph uses nonnegative travel costs; this link is not a claim about the newest pgRouting release.
- OSRM backend documentationOfficial extraction, MLD partition/customization and CH contraction pipelines; benchmark update compatibility rather than assuming arbitrary dynamic restrictions.
Practice marks stay in this browser.