Backend engineer owning the request-handling API and the data-access layer.
Design question
40 min
Making entry listing scale past a few million rows
You own the Content entry API in a Python service backed by a relational database. List endpoints accept limit and offset, return a total count, and serialize each entry through the Request and response schemas, which compute per-viewer fields: whether the caller bookmarked the entry, the bookmark count, and whether the caller subscribes to the author. The content entry table now holds about 3 million rows and the list endpoint serves roughly 40 requests per second, mostly anonymous. The 95th percentile latency has climbed from 80 ms to 900 ms over six months, and the database shows many small queries per request alongside one slow count over the filtered set. Product also wants a personal feed of entries from authors the caller subscribes to, with the same filters on labels and authors. Propose how you would restructure the query path, the pagination contract and the computation of per-viewer fields so the endpoint scales to 30 million entries. State which of your changes alter the API contract, how you would roll them out without breaking existing clients, and what you would measure to prove each change helped.
Rubric
Diagnosis Identifies N+1 serialization and the unbounded count as the two distinct causes. | 25% |
Query design Proposes concrete batched or annotated queries and supporting indexes. | 30% |
Pagination and contract Handles cursor paging and the total-count trade-off with a rollout plan. | 25% |
Measurement Defines before/after metrics and a realistic test. | 20% |
Red flags
- Suggests only adding a cache without removing the query pattern
- Keeps offset paging at 30M rows without justification
- Ignores that anonymous callers have no per-viewer fields
Expected-solution outline
- Name the two costs: per-row computed fields causing N+1 queries and a full count on every page
- Replace per-row resolution with one annotated or batched query for bookmark state and subscription state
- Move from offset to keyset (cursor) pagination, and either drop the exact total or serve an approximate or cached count
- Define indexes for the label, author and feed filters, including the composite order used for feed paging
- Describe contract changes (cursor tokens, total semantics) and a compatible rollout with deprecation
- Give measurements: queries per request, p95, plan inspection, and a load test with anonymous and authenticated mixes
Debugging from a description
30 min
Authenticated requests slow down and the session table keeps growing
Read the problem and rubric
The Token authentication component decodes a signed bearer token, loads the backing session row and then the account row, and optionally lets anonymous callers through. A token is issued, along with a new session row, on registration, login and every account update. Over the last quarter you observe three symptoms: median latency of authenticated read endpoints rose from 25 ms to 60 ms while anonymous reads did not change; the session table grew from 2 million to 41 million rows and its index no longer fits in memory; and a mobile client that refreshes its account on every launch creates about 200 sessions per active account per month. There were no recent deploys to the Token authentication component. Write down your ranked hypotheses, the queries or metrics you would use to confirm or kill each one, and the fix you would ship first. Then describe how you would clean up the existing rows safely, and what you would change so the problem cannot recur while keeping the ability to revoke a token.
| Hypotheses and evidence | 30% |
| Immediate fix | 25% |
| Safe cleanup | 25% |
| Prevention and revocation | 20% |
Extend-this-system take-home
90 min
Add scheduled publication to content entries
Read the problem and rubric
Authors want to schedule an entry to appear at a future time. You are extending the Content entry API and the Relational data model and migrations in a Python service. Today an entry is created inside one transaction that also finds or creates its labels (flow: Entry creation), and every list, feed and read endpoint serializes entries through the Request and response schemas. Requirements: an author can set a publish time when creating or updating an entry; until that time only the author can see the entry; after it, everyone sees it without any manual action; the author can reschedule or cancel before publication; list endpoints keep their pagination contract and must not leak or count hidden entries; and existing entries must behave exactly as before. Deliverables: (1) the schema change and a migration plan that is safe on a table with 3 million rows; (2) the request and response schema changes, with validation rules; (3) pseudocode for the visibility predicate used by list, feed and read, and where you would apply it so no path can bypass it; (4) how entries become visible at the scheduled time and what happens if the process is down then; (5) a test plan listing the five most important cases, including time-zone and clock-skew edge cases.
| Data and migration | 20% |
| Visibility design | 30% |
| Scheduling semantics | 25% |
| API and validation | 10% |
| Test plan | 15% |
Design question
35 min
Replacing the library-owned label tables without downtime
Read the problem and rubric
A past migration replaced a third-party tagging library's tables with an owned label table and a link table between entries and labels, copying data with raw SQL and then dropping the legacy tables in a later migration. You are about to repeat this kind of change: the owned link table must be split so that each link also records the account that applied the label and the time it was applied, and the label table itself must be deduplicated case-insensitively. The service runs on a relational database with 5 million entries and about 20 million entry-label links, is deployed with rolling restarts, and cannot take more than a few seconds of write unavailability. Design the migration sequence, including how old and new application versions coexist during the rollout, how you backfill, how you verify correctness before cutting over, and how you roll back if verification fails after cutover. Call out which steps are reversible and which are not, and explain why you would or would not run the data copy inside a schema migration.
| Migration sequencing | 35% |
| Correctness and verification | 25% |
| Rollback and risk | 25% |
| Operational judgment | 15% |