System designby Learnastra

System-design interview · Core interviews

Design nearby place search and friend discovery

By Anup Rai

Find the nearest eligible places within a stated radius, then extend the design to private, expiring friend locations without confusing search freshness with permission.

You will learn to

  • Explain complete spatial coverage and exact distance with a boundary example.
  • Scale place searches while making indexing delay explicit.
  • Design private nearby-friend lookup with current sharing checks and expiring positions.

Practice in this chapter

8 interview questions with model answers and follow-ups.

Go to interview practice

Useful foundations: Database indexes: B-trees, composite keys and query access · Data partitioning and sharding · Caching: cache hits, misses, write policies and invalidation · CAP theorem: consistency, availability, and partition tolerance

Workload and timing examples are interview assumptions.

01Choose the nearby-search contract

Build a service that returns the nearest twenty open cafés within a requested radius. A place has coordinates, category, name and reviews; a separate nearby-friends feature returns consenting contacts' recent positions. Exclude driving routes, advertising and reservations. Straight-line distance is not driving time, so the API must name which it returns.

Use a concrete query throughout: Maya stands at local coordinate x=990 and asks for cafés within 50 meters. Café P12 is at x=1010 with the same y coordinate. It is twenty meters away even though a grid boundary at x=1000 separates them. This is the simplest test of whether the search actually works.

Target public-place edits becoming searchable within five seconds for 99% of accepted edits under normal operation. A successful edit means the source record is durable, not that every search replica already contains it. Return a searchable timestamp or generation when useful. For the first page, promise the closest eligible results in the selected searchable snapshot, up to the requested limit. Do not silently widen the radius when fewer than twenty exist. Current private authorization has a stronger requirement than slightly delayed public-place indexing.

Clarify the ranking and audience first: does nearby mean straight-line distance or travel time, and are we searching public places or currently consenting friends? Confirm the maximum radius and acceptable update delay. This answer uses nearest-by-distance place search and a separate permission-checked friend lookup.

02Functional requirements

  1. Search nearby places. Return up to twenty open places matching category and radius, ordered by geographic distance with a stable tie-breaker.

  2. View place details. Return names, coordinates, review summaries and photo references for selected places.

  3. Maintain places. Let authorized owners create and update place records, recover retried writes and reject conflicting edits.

  4. Find nearby friends. Accept authenticated position updates and return nearby contacts who currently permit sharing, including the age of each observation.

03Non-functional requirements

These are illustrative interview assumptions, not product facts or measured benchmarks. Confirm them before choosing components, then validate the completed design under the stated workload. Here p95 means the 95th-percentile latency: 95% of measured requests take no longer than that value. Report errors and rejected work alongside latency; a fast failure is not a successful outcome.

  1. Workload and response time. Plan for 500 million places and 100,000 peak searches/s. For admitted requests returning at most twenty results within a maximum 5 km radius, target 200 ms p95 API latency; count timeouts as misses and measure dense cities separately.

  2. Freshness. Target public-place changes becoming searchable within five seconds for 99% of accepted edits under normal load. Friends publish every five seconds; label points older than fifteen seconds stale and exclude them after thirty seconds.

  3. Result correctness. Return the closest eligible results in the selected searchable snapshot. Cover the whole radius; never silently skip a required region or substitute travel time for distance.

  4. Recovery and failure behavior. Preserve committed source edits across application restarts and rebuild lost indexes from the source plus changes. If a required search region is unavailable, fail an exact query or explicitly label incomplete coverage; the index is not the only copy of places.

  5. Location privacy. Check current sharing permission and presence validity before disclosure. Reject unauthorized edits and omit private positions when their permission cannot be established.

04Start with a spatial database and one complete request

The first implementation needs an API service, a relational database with a spatial index, and object storage for photos. A spatial index organizes records by geometry so the database can discard distant regions without scanning every place. It narrows the candidates; the exact distance predicate determines which candidates are truly within the radius.

For Maya’s search:

  1. Send the coordinate, radius and category.

  2. Validate units and limits, then ask the database for matching open cafés.

  3. Compute geographic distances, sort by distance and place ID, and select up to twenty results. The stable ID breaks equal-distance ties.

  4. Fetch review summaries and photo references in batches after selection rather than executing one query per café, then return the selected results.

Use a geography-aware implementation that accepts meters. Raw longitude differences do not have the same ground distance at every latitude. A bounding rectangle can efficiently find candidates, but its corners extend outside a circular search, so a final distance test remains necessary. The mature database implementation handles geometric edge cases; the interview should explain the contract rather than invent spherical mathematics.

An owner edit updates the authoritative place record transactionally. At modest scale the same indexed database can serve both writes and searches, avoiding asynchronous-index complexity entirely.

Design diagramA complete local nearby search

The spatial database supplies candidates and exact distance; photos travel separately.

A complete local nearby searchThe spatial database supplies candidates and exact distance; photos travel separately. client to api: Coordinate, radius, category; api to db: Cover region; filter and rank; db to api: Eligible places and distances; api to client: Results and photo references; client to media: Fetch selected imagesCoordinate, radius, categoryCover region; filter and rankEligible places and distancesResults and photo referencesFetch selected imagesACTORMaya’s searchSERVICEQuery and place APISTOREPlaces + spatialindexEXTERNALPhoto deliverysyncreturn
Read each connection in order
  1. syncCoordinate, radius, categoryMaya’s search → Query and place API
  2. syncCover region; filter and rankQuery and place API → Places + spatial index
  3. returnEligible places and distancesPlaces + spatial index → Query and place API
  4. returnResults and photo referencesQuery and place API → Maya’s search
  5. syncFetch selected imagesMaya’s search → Photo delivery

05Estimate the work per search

Assume 500 million places and 100,000 searches per second at peak. At 800 bytes per place, source records occupy about 400 GB before indexes, replicas, reviews and photos. An index payload consisting only of an 8-byte ID and 16-byte coordinates is 24 bytes, or 12 GB for 500 million places; real index structures require more space.

Twenty results of 1 KB each produce roughly 2 GB/s of response payload at the stated peak. Deliver photos separately through an edge cache. Three copies of source records require about 1.2 TB before overhead; replication is not a backup against an accidental deletion applied to all copies.

The decisive search cost is often candidate count. If a dense-city query examines 5,000 points at an illustrative two microseconds of CPU each, it spends ten milliseconds of CPU before fetching details. At 100,000 such queries per second, that stage alone requires approximately 1,000 CPU-seconds each second. Actual hardware sizing needs measurements, especially because rural and downtown workloads differ greatly.

Measure candidates examined, cells visited and returned records by radius and city. Use the agreed 5 km maximum radius and twenty-result bound; a country-wide best-rated search is a different workload from a local nearest-café request.

06Make units, ownership and freshness visible

Interfaces

Request or message Contract
GET /places with latitude, longitude, radius and limit Returns places, distances, searchable time and an opaque cursor.
PUT /places/P12 with expectedVersion and changed place fields Updates an authorized place only if version 4 is still current.

Example radius request

GET /places?lat=40.741&lon=-73.989&radiusMeters=50&limit=20

Fields of a version-checked place update

expectedVersion: 4 (the version being replaced)
place fields: the intended changes to the authorized place

Stored records

Record Fields or identity Purpose
Place id, point, category, open, version Durable source for place state.
Spatial entry region, id, point, version Searchable projection of a source version.
Review id, placeId, author, rating Separate durable user content.
Presence user, session, sequence, point, expiresAt Latest private position, not a permanent location history.

The cursor binds the original point, radius, filters, ordering and searchable generation. Reusing it after moving the query point would no longer mean “the next page of the same search.” If retaining a snapshot across pages is too expensive, explicitly offer best-effort pagination with possible movement-related changes.

Derive editor and presence-owner identity from authentication. Version checks prevent one editor overwriting another's change. Place creation uses a request identity so retrying a lost response does not create another place. Ratings can be updated less frequently than coordinates if their separate freshness promises are clear. Neither review averages nor spatial membership determine who may see a private location.

07Explain why the search finds the nearest results

A grid assigns each point to a cell. For Maya's 50-meter query, cover every cell intersecting the query region, including the cell beyond x=1000. Then check exact distance and eligibility. Searching only Maya's own cell misses P12 despite its twenty-meter distance.

The simplest correct bounded-radius algorithm collects all eligible candidates in the radius, sorts them and takes twenty. That is a defensible interview baseline. A large candidate set motivates pruning: each unvisited region has a lower bound on how close any point in it could be. Visit promising regions first and retain the best twenty eligible results.

For a two-result example, the first region yields cafés at 30 and 40 meters. A neighboring region can contain a point ten meters away, so inspect it. Finding P12 at twenty changes the best results to twenty and thirty. A remaining region whose closest possible point is 35 meters away cannot improve them. Continue equal-distance bounds when the ID tie-breaker could still matter.

The bounds must never overstate a region’s minimum distance, and must use the same geography and snapshot as its indexed points. Delegating it to a proven spatial implementation is preferable to improvising a custom distributed tree during a 45-minute answer.

08Add read capacity before distributing ownership

First cache place details and add spatial read replicas. Details are repeatedly requested, whereas exact query coordinates vary, so a cache of complete responses may have fewer useful hits. Measure cache hit rate before treating it as the main solution. Replicas add capacity but also introduce update lag and consume index memory.

When one index cannot meet storage or rebuild targets, partition it geographically. A routing manifest maps regions to owners. The query computes all intersecting regions, contacts those owners, merges candidates and deduplicates place IDs. Dense regions can split or receive more replicas. Smaller regions reduce local candidate counts but increase routing and boundary work.

Hashing by place ID offers another tradeoff: records distribute evenly, but a proximity query must ask every index partition. Geographic ownership is attractive when most queries are local; either layout still needs capacity for a popular city.

During a split, copy records and catch up changes before routing new queries exclusively to the replacement owners. Use one consistent version of the region map for each bounded query. If a required owner fails, fail an exact query or label its result incomplete; twenty results from other regions do not establish that no closer result was omitted.

09Move and delete places without claiming instant search

When place storage and the search index are separate, a saved edit can still fail to reach the index. Commit each place change together with an outbox record: a durable instruction describing the change. A worker relays that instruction to the index and retries after failure. The place version lets the index reject an older update delivered after a newer one.

Suppose P12 moves from region A to B as version 5. The worker adds the version-5 entry to B and removes or marks the old entry in A. These may be separate operations. Temporary duplicates can be merged by ID; a temporarily missing new entry means B's queries may omit the café until indexing catches up.

Reading current details can reject the old position but cannot discover a record absent from the candidate list. Therefore the ordinary API retains its stated indexing delay. A strict read-after-edit search must wait for a caught-up index or include a complete set of recent changes before selection. Checking returned records cannot find a café missing from the index.

Keep geometry and distance ranking consistent with the selected searchable snapshot. If current coordinates differ, restart against compatible data or disclose incompleteness rather than substitute them into an old pruning decision. Deletions likewise need versioned removal so delayed events cannot revive a closed place.

10Treat nearby friends as a private presence feature

For a user sharing with a few hundred contacts, begin with a simpler approach: load the authorized contact set, fetch their latest positions in a batch, discard expired observations and compute distances. This avoids maintaining a global private spatial index before the audience size warrants one. Public place search and private presence can share distance utilities without sharing permissions or caches.

Each publishing session receives a generation and sends increasing sequence numbers. The server rejects older generations or sequences, preventing delayed packets from moving a friend back to an old point. A new authenticated session can restart numbering without letting the previous session overwrite it. Keep receipt time separately from the phone's asserted observation time.

As an assumption, devices publish every five seconds, the interface labels observations older than fifteen seconds stale, and records expire after thirty seconds. Those values are product choices, not proof that GPS is accurate. Return location age and avoid displaying a stale point as a live position.

Before returning a private point, read current sharing permission and the corresponding presence version from a consistent authority, or revalidate their versions together. Revocation must affect subsequent authorization decisions even if a candidate remains in an old index. If permission cannot be established, omit the point or fail the private query.

Design diagramGeographic search and separate private presence

Public search projections may lag; private points require current consent.

Geographic search and separate private presencePublic search projections may lag; private points require current consent. client to api: Public places or private contacts; api to regions: All intersecting regions; places to worker: Committed place changes; worker to regions: Apply source version; api to contacts: Authorized fresh contact points; api to client: Distance, age, coverage statusPublic places or privatecontactsAll intersecting regionsCommitted place changesApply source versionAuthorized fresh contact pointsDistance, age, coverage statusSERVICEQuery serviceSTORERegional spatialreplicasSTOREDurable places +outboxWORKERVersioned indexworkerSTORESharing + currentpresenceACTORAuthenticated viewersyncasyncreturn
Read each connection in order
  1. syncPublic places or private contactsAuthenticated viewer → Query service
  2. syncAll intersecting regionsQuery service → Regional spatial replicas
  3. asyncCommitted place changesDurable places + outbox → Versioned index worker
  4. asyncApply source versionVersioned index worker → Regional spatial replicas
  5. syncAuthorized fresh contact pointsQuery service → Sharing + current presence
  6. returnDistance, age, coverage statusQuery service → Authenticated viewer

11Test missing results as well as slow requests

Monitor search latency by city and radius, index-update lag, candidates per result, region fanout and rebuild duration. Add synthetic places on cell edges and corners; compare sampled answers with a trusted spatial database. Include antimeridian crossings and coincident points, which can defeat careless custom subdivision.

Recover an index from a source snapshot plus versioned changes. A routing map alone does not contain the places it routes to. Record the snapshot’s change-log position so replay neither skips changes nor restores older values. Limit rebuild bandwidth to protect serving traffic, and verify the new generation before switching queries.

For private presence, test revocation during a request, delayed location packets, device restart and expiry-worker failure. Eligibility must check the deadline even when physical cleanup is delayed. Keep precise coordinates out of general analytics logs and restrict administrative access.

Overload should reduce optional detail fetching or reject excessively expensive queries. Silently skipping a region changes the correctness promise. Public browsing can continue when private presence is unavailable, because the two features have separate state and authorization paths.

12Check the design against its requirements

Use the numbered requirements to check the final design. FR refers to the functional list; NFR refers to the non-functional list. Performance rows specify tests still required, not achieved benchmark results.

Requirement Design mechanism Verification and remaining limit
FR1–2; NFR1,3: complete, fast search Spatial coverage, exact distance, stable sorting and batched details; cache details and distribute geographic regions as needed. Run boundary/corner cases and compare with a trusted spatial query. Load-test 200 ms p95 at the agreed radius, density and peak; aggregate QPS alone is insufficient.
FR3; NFR2,4: edits and search freshness Transactional source edits, scoped retry identity and versioned outbox indexing. Lose an edit response, restart an index worker and move a place between regions. Measure commit-to-searchable delay against the five-second target.
FR4; NFR2,5: private presence Fetch the authorized contact set, reject old session sequences and enforce observation expiry at read time. Revoke sharing during lookup, delay a packet and stop cleanup. No unauthorized or expired point may be returned.
NFR3–4: honest degradation Route over one coherent region map and rebuild from source history. Remove a required region and confirm the response cannot claim a complete nearest-twenty answer. Source-database disaster recovery remains a separately agreed promise.

13Rapid revision

Remember: A nearby place can cross a cell boundary. Cover the whole radius before choosing the nearest results.

Decision Mechanism and consequence
Find nearby places Search every region intersecting the requested radius, then measure exact distance in the stated units.
Return nearest twenty Sort all candidates within the radius, or stop only when no unvisited region can beat result twenty.
Start simply Keep place records and their spatial index in one database; fetch selected places’ details together.
Scale searches Add read replicas, then assign geographic regions to separate servers when measured load requires it.
Handle place changes Save each place change and its indexing task together; reject older versions at the index.
Disclose lag An edit may reach search later. Checking returned places cannot find one missing from the index.
Query private friends For small contact sets, fetch authorized contacts' current points directly.
Protect location For the returned location, check viewer permission, update order within its session and expiry.
Recover failures Rebuild from saved records and later updates; report incomplete results if a region’s server is unavailable.

In an interview, spend the opening minutes on radius, ranking, freshness and privacy, then trace Maya's boundary café. Introduce distribution only after showing the correct single-database query. Close with the two residual limits: search can lag accepted edits, and geographic proximity does not establish travel time or access permission.

Practise the interview questions

Say your answer aloud before opening the model answer. Then answer the follow-up and compare the reasoning.

Foundation · Question 1

Why can a café across a cell boundary be the closest result?

Reveal a model answer

Cells organize storage; they do not constrain physical distance. Maya at x=990 and P12 at x=1010 are twenty meters apart. Search must cover intersecting cells and apply exact distance.

What the answer must demonstrate: Explain cross-cell coverage and the exact circular distance predicate.

Applied · Question 2

When can a nearest-twenty query stop?

Reveal a model answer

After examining all eligible bounded candidates, or after every remaining region has a valid minimum distance worse than the current twentieth result. Equal distances need the stated tie-breaker.

What the answer must demonstrate: State the stopping bound and apply eligibility before counting best results.

Foundation · Question 3

Why name the field radiusMeters?

Reveal a model answer

It makes the distance unit explicit. Latitude and longitude are angles, and longitude distance varies with latitude, so raw degree subtraction is unsuitable.

What the answer must demonstrate: Distinguish angular coordinates from distance units and use appropriate geography.

Applied · Question 4

Why partition spatially instead of hashing place IDs?

Reveal a model answer

Geographic ownership keeps most local queries on a few owners. Hashing IDs balances records but requires querying every index partition.

What the answer must demonstrate: Compare geographic locality with ID-hash fanout and hot-city skew.

Applied · Question 5

Can current detail reads repair every stale-index error?

Reveal a model answer

They can remove incorrect returned candidates but cannot discover a moved place absent from the new region. Preserve the indexing-delay contract or use a caught-up index.

What the answer must demonstrate: Distinguish rejecting stale candidates from discovering missing moved records.

Foundation · Question 6

What is the simplest nearby-friends design?

Reveal a model answer

Fetch the viewer’s authorized contacts, read their latest positions in a batch, check expiry and compute distances. A bounded contact set may not need a global spatial index.

What the answer must demonstrate: Use current viewer consent and presence expiry, including the small-contact-set alternative.

Follow-up · Question 7

A neighboring region is unavailable; can twenty other results count as success?

Reveal a model answer

Not for an exact nearest-result promise. The missing region might contain closer places. Return an explicitly incomplete result or fail that query.

What the answer must demonstrate: Refuse to claim exact completeness when a required region is missing.

Follow-up · Question 8

Is best-rated within a radius the same as nearest twenty?

Reveal a model answer

No. A farther café inside the radius may outrank every nearby café on rating. Candidate selection must cover the ranking contract.

What the answer must demonstrate: Choose candidate coverage from the ranking objective, not only nearest distance.

Blank-page exercise · 45 minutes

Build the answer yourself

Design nearby café discovery, then explain a café just across a grid boundary and a friend who revokes sharing while their old point remains indexed.

  • Agree numbered functional and non-functional requirements, including distance ranking, freshness and private-location access. Then explain complete spatial coverage and exact distance with a boundary example.
  • Scale place searches while making indexing delay explicit.
  • Design private nearby-friend lookup with current sharing checks and expiring positions.
  • Trace a timeout and a concurrent request using the actual durable records.
  • Review the final architecture against every numbered requirement, including measured bottlenecks, targets still needing validation and remaining failure limits.

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 nearby place search and friend discoveryMaya is at x=990 and P12 at x=1010. Why must a 50-meter search cross the x=1000 cell boundary?Recall first, then reveal

P12 is twenty meters away. Search every intersecting cell, then test exact distance and rank eligible places.

Nearby can cross a cell boundary: cover, measure, rank.

Return to lesson
Design nearby place search and friend discoveryCan checking current place details find a place missing from the search index?Recall first, then reveal

No. It only checks places already found. Finding an omitted place requires an up-to-date index or all relevant recent changes.

Validation is not discovery.

Return to lesson
Design nearby place search and friend discoveryWhen may the service return a friend’s location?Recall first, then reveal

Only when the viewer currently has permission to see that exact position record.

Nearby is not permission.

Return to lesson

Final revision

Summary and interview notes

Find eligible places within a radius and return the nearest. For friends, check current viewing permission and location expiry; a fresh search result alone does not authorize disclosure.

Remember these points

  • Search the whole radius before choosing the nearest results.
  • Keep distance units and search freshness explicit.
  • Separate durable places, derived search and private presence.
  • Never infer permission from a candidate index.

Interview tips

  • Agree on radius, ranking, freshness and privacy.
  • Trace Maya’s search across x=1000, then move P12 before the index catches up.

Important qualifications

  • Traffic and latency figures are interview assumptions, not claims about a named company's deployment.

Continue after the core interview

Explore the advanced version

The advanced lesson keeps the full detailed design. Use these sections when you want to examine the stronger requirements and failure cases.

Technical references

  • PostGIS ST_DWithinDefines geography distance units and index-assisted candidate filtering.
  • H3 documentationPrimary introduction to hierarchical geographic indexing; an alternative to hand-built adaptive rectangles.

Practice marks stay in this browser.