cswork / libraryOpen practice workspace

Interview guides · Blinkit

Blinkit Software Engineer Interview Guide

Blinkit Software Engineer interview guide: reported rounds, DSA and resume questions, concurrency and graph prep, and a 7-day study plan.

The 60-second brief

Blinkit is a quick-commerce platform: customers order through the app and the items reach them within minutes through a local delivery network. The role description candidates see places software engineers on the problems behind that promise: logistics, inventory, real-time bidding, high concurrency and low-latency microservices. The work is described as backend infrastructure or mobile applications, along with code reviews, incident response, post-mortems, performance bottleneck hunting and feature iteration based on feedback from operations and customer data. For interview preparation, that means treating orders, riders, warehouses and stock levels as the data you model.

This guide is for candidates applying to Blinkit as a Software Engineer, on the backend or mobile side. It covers the two reported stages (Recruiter Screen and Technical Rounds), the five algorithm questions and five resume-discussion questions candidates report, the languages and tools the role lists (Java, C++ or Go, distributed systems, with cloud, container and streaming experience as extras) and the design scenarios candidates mention. Reported requirements point to roughly 1 to 3 or more years of professional experience.

Candidates report two stages over about 2-4 weeks: a Recruiter Screen about your background and fit, then Technical Rounds that combine algorithmic challenges with questions based on your resume. The number of technical rounds is not specified.

Focus areas

  • Data Structures & Algorithms (DSA)
  • Problem Solving
  • Algorithmic Thinking

Overview

The reported loop is short in stages but wide in content. After the Recruiter Screen, the Technical Rounds combine algorithmic challenges with a discussion of your resume, so two separate kinds of preparation are needed: code you can write correctly in Java, C++ or Go, and an account of your past work that you can defend decision by decision. Candidates also mention design scenarios, such as a notification service for very large push volumes and a real-time order tracking system, and report that design carries more weight at SDE-2 level and above.

The reported algorithm questions are all shaped by delivery and inventory work. One asks for an algorithm to optimize delivery routes for multiple riders, one for the top-performing products in a stream of order data, one for a thread-safe cache of product inventory, one for a graph traversal problem about warehouse distribution, and one for optimizing a recursive function on large input. Practise them as a set: heaps and hash maps for streams, locks and atomic updates for shared state, BFS, Dijkstra and topological ordering for graphs, memoization for recursion. Candidates also report example scenarios such as searching a billion-record database and handling concurrent updates to a single inventory item, so be ready to talk about indexes and race conditions, not only loops.

The resume half is five questions: the most challenging technical project, a critical production issue, why you chose a specific database or framework, refactoring a legacy system for performance, and balancing technical debt against fast feature delivery. Each needs a real story with a baseline, a decision, an alternative you rejected and a measured result. Pick two or three projects now and build every answer from them, so the stories stay consistent across rounds.

The role description lists distributed systems experience as a requirement and cloud infrastructure (AWS or GCP), Docker or Kubernetes and real-time streaming platforms as extras. You do not need to claim all of them, but whatever appears on your resume is fair material for the resume discussion, so know what each tool did in your project and what you would change.

The Blinkit interview process

Candidates describe two stages. The first is a conversation with a recruiter; the second is a set of technical rounds whose exact number is not reported.

Recruiter Screen

Candidates describe this stage as first contact with a recruiter, who discusses your background and your fit for the role. No coding is reported for it. Treat it as the point where your CV, your language choice and your project list are set up for the technical stage, since the same background feeds the resume questions later.

What to demonstrate

  • How clearly you summarise your background and the work you have done
  • Whether your experience matches the role as listed: an object-oriented language such as Java, C++ or Go, data structures and algorithms, distributed systems
  • Your reasons for applying to this role

How to prepare

  • Rehearse a short walk through your CV that ends on the two or three projects you would like to discuss in depth later.
  • Decide which language you will code in (Java, C++ or Go are the ones the role lists) and be ready to say how much production experience you have in it.
  • Ask the recruiter what the technical rounds cover and which language or environment is used, and note the answer.
  • Prepare an honest account of any distributed systems, cloud, container or streaming work on your resume, since the role lists these.

Technical Rounds

Candidates describe multiple technical rounds that focus on algorithmic challenges and on discussions based on your resume. The reported algorithm questions are about delivery routes for multiple riders, top products from a stream of orders, a thread-safe inventory cache, a graph traversal problem about warehouse distribution and optimizing a recursive function. The reported resume questions are about your hardest project, a production issue, database or framework choices, a legacy refactor and technical debt. Candidates also mention design scenarios, with more weight at SDE-2 level and above. Prepare both halves: write working code while explaining complexity, and tell project stories with numbers.

What to demonstrate

  • Working, readable code for algorithmic problems, with correct complexity analysis
  • Handling of edge cases, constraints and failure points, which candidates list among the evaluation areas
  • Reasons and impact behind the technical decisions in your past projects
  • For design scenarios, scalability, database choice (SQL or NoSQL), consistency and service communication

How to prepare

  • Implement the thread-safe inventory cache with an atomic reserve operation and test it with many concurrent threads, then do the top-k stream and warehouse graph questions in your chosen language.
  • Sketch an approach for the multi-rider route question: an assignment step, an ordering step, a baseline heuristic and one improvement.
  • Write one story per resume question, each with a baseline, the decision, the alternative you rejected and a result you can measure.
  • Outline one notification service and one real-time order tracking design, covering the data model, the queue or stream, and what happens when a dependency is down.

Where candidates lose points

Treating the delivery-route question as one shortest-path problem

Several riders and orders make this an assignment plus ordering problem, close to vehicle routing, where exact solutions do not scale. State the objective (total time, lateness or both) and the constraints, give a greedy insertion baseline, then improve it with a local-search step such as 2-opt, and say what the heuristic gives up.

Checking stock and then decrementing it in two separate steps in the inventory cache

Make check-and-reserve one atomic operation: a per-key lock, a compare-and-set loop on a version or an atomic counter. Explain the lost-update interleaving in two lines, and mention sharding the locks or using a concurrent map so one hot product does not block the rest.

Sorting every order to find the top products in a stream

Keep counts in a hash map and a size-k min-heap for the leaders, which costs O(n log k) and constant memory in k. Then handle the follow-ups: a recent time window (bucketed counts that expire), ties, and an approximate count sketch when the product set is too large for memory.

Giving project stories with no numbers, no rejected alternative and no result

For each of the five resume questions, write down the baseline metric, the decision, the option you passed on and the measured effect. For the database or framework question, name the access pattern and consistency need that drove the choice, not the tool's reputation.

Writing a recursive solution without checking depth or repeated work

Before coding, ask whether subproblems overlap (memoize or go bottom-up) and how deep recursion can get. Java and C++ stacks are fixed size by default, so on very large input convert to an explicit stack or a loop, and state the new time and space cost.

Questions & practice

Given a stream of order data, how would you find the top-performing products in real-time?

Medium · Data Structures and Algorithms

Approach

  1. Pin down the metric and the window first: units sold, revenue or order count, and all-time versus the last N minutes. Treat each order event as idempotent (dedupe by order id) and decide whether a cancellation subtracts from the count.
  2. Exact baseline: a hash map from product to count, updated in O(1) per event. For top k on demand, scan the map with a size-k min-heap in O(n log k). If top k is read constantly, keep an ordered set keyed by (count, productId): each increment is a remove and re-insert in O(log n), and reading the top k is O(k).
  3. For a sliding window, keep a ring of per-minute (or per-second) count buckets; add events to the current bucket and, when a bucket expires, subtract its counts from the totals. Memory is one map per bucket rather than one entry per event.
  4. When distinct products are too many to count exactly, use Space-Saving or Misra-Gries (a fixed number of counters that are guaranteed to keep every item above a frequency threshold of about N/k), or a Count-Min Sketch with width ceil(e/epsilon) and depth ceil(ln(1/delta)) plus a small heap of candidates. Both overestimate or undercount within a stated bound, so say which error you accept.
  5. At scale, partition the stream by product id so each product is counted on exactly one node; then each node's local top k can be merged into a correct global top k. If you partition by order instead, merged local top-k lists can miss a product that is moderately popular everywhere.

Follow-up

  • How do you handle cancellations and refunds if you used an approximate structure that only supports increments?
  • How would you produce the top products per city or per store instead of globally?
  • Events arrive late or out of order: which bucket do they count in?

Implement a thread-safe cache for product inventory.

Medium · Data Structures and Algorithms

Approach

  1. Clarify the operations and the consistency need: get(sku), put, and an atomic reserve or decrement; whether the cache is the source of truth or a read-through layer over a database; and whether it must evict (LRU, TTL). Overselling is the failure to design against, so a check-then-act sequence (read stock, then decrement) is the race to name.
  2. Java version: a ConcurrentHashMap gives thread-safe get and put, and compute() or computeIfAbsent() run atomically per key, so a decrement written as compute(sku, (k, v) -> v > 0 ? v - 1 : v) cannot interleave with another update to that key. Keep the mapping function short: it holds a lock on that bin, and it must not update other keys of the same map. In Go, a sync.Mutex or sync.RWMutex around a map; in C++, std::shared_mutex with unique and shared locks.
  3. If you add LRU eviction with LinkedHashMap in access order, a get() reorders the list, so even reads need the exclusive lock and a read-write lock gains nothing. Lock striping (N segments, each with its own lock and map) cuts contention; get and put stay O(1).
  4. Prevent a stampede on a miss: load each key once (computeIfAbsent, or a map of in-flight futures) so a hundred threads missing the same SKU cause one database read, not a hundred.
  5. Keep the database authoritative for stock: reserve with a conditional update such as UPDATE ... SET qty = qty - 1 WHERE sku = ? AND qty >= 1 and check the affected row count, then update or invalidate the cached entry. Mention the delete-then-stale-read race and use a TTL or version number to bound it.

Follow-up

  • Several application instances each hold a local copy of this cache: how do you keep them from overselling the same item?
  • One SKU gets most of the traffic during a sale: where does your design contend, and how would you relieve it?
  • Would you write through to the cache or invalidate it on a stock change, and what stale read can each one produce?

Solve a complex graph traversal problem related to warehouse distribution.

Medium · Data Structures and Algorithms

Approach

  1. The title is open-ended, so restate a concrete version before coding: nodes are warehouses and stores, edges are routes with travel time or cost, and the question is reachability, nearest supplier, an ordering, or how much stock can flow. Ask for sizes, whether edges are directed, and whether any weight can be negative.
  2. Match the question to the algorithm: connected components or reachability with BFS or DFS in O(V + E); shortest path with BFS if unweighted, Dijkstra with a binary heap in O((V + E) log V) for non-negative weights, Bellman-Ford in O(VE) if weights can be negative.
  3. For 'assign every store to its nearest warehouse', run one multi-source BFS or Dijkstra seeded with all warehouses at distance 0 (equivalently, a super-source joined to each warehouse) instead of one search per warehouse.
  4. If the question has dependencies (stock must move A before B), use a topological sort with Kahn's algorithm and report a cycle when fewer than V nodes are emitted. If edges carry capacities and the ask is maximum supply, it is a max-flow problem (Edmonds-Karp in O(V * E^2)), or min-cost flow when cost also matters.
  5. Write traversals iteratively with an explicit queue or stack so a long chain cannot overflow the call stack, mark nodes visited when they are enqueued, and test disconnected nodes, cycles, self-loops, duplicate edges and a source equal to the target.

Follow-up

  • A route closes while the system is running: do you recompute from scratch or update incrementally, and what does each cost?
  • Each warehouse now has limited stock: how does nearest-warehouse assignment change?
  • The graph no longer fits in one machine's memory: how would you partition the traversal?

Optimize a recursive function to handle large-scale input data.

Medium · Data Structures and Algorithms

Approach

  1. Separate the two problems a large input causes: repeated work (overlapping subproblems that make the time exponential) and call depth (one stack frame per level, which overflows on deep input). Identify which one you have before changing anything.
  2. For repeated work, memoise on the full state that determines the result, then consider converting to bottom-up tabulation. Fibonacci is the standard illustration: naive recursion is O(phi^n), memoised or iterative is O(n), and keeping only the last two values brings space to O(1).
  3. For depth, convert to iteration: a bottom-up loop for DP, or an explicit stack (stored on the heap) for tree and graph recursion. Java and C++ do not guarantee tail-call elimination, so rewriting as a tail call is not a reliable fix there; Python's default recursion limit is 1000.
  4. Reduce the state itself: rolling arrays when a DP row depends only on the previous row (O(n*m) memory down to O(m)), and in divide-and-conquer, recurse on the smaller part and loop on the larger so the stack stays O(log n), as in quicksort.
  5. Check the edge cases large inputs expose: integer overflow in the result (use 64-bit or modular arithmetic), a memo table that itself exhausts memory, and base cases for empty or single-element input. Re-run the original small tests to confirm the rewrite returns identical results.

Follow-up

  • The recursion has no overlapping subproblems, such as a plain tree walk: what does memoisation buy you then?
  • The memo table is too large for memory: how would you shrink the state or process the input in chunks?
  • Could the subproblems run in parallel, and which ones are independent?

Write the update path that detects a concurrent edit

Medium · optimistic concurrency · transactional outbox · audit history

resource carries version INT NOT NULL DEFAULT 1. resource_revision holds revision_id, resource_id, version, actor_user_id, change_kind, patch JSONB, request_id, created_at with UNIQUE (resource_id, version). outbox_event holds aggregate_type, aggregate_id, aggregate_version, event_type, payload, status. A PUT carries the version the client read. Write the exact statements for the single transaction that applies the edit, records the revision and enqueues 'resource.updated', and give the handler's branch on zero affected rows. Then say what PostgreSQL 16 does under READ COMMITTED when two of these updates hit one row at once.

Approach

  1. One transaction, three writes, no network call inside it: UPDATE resource SET title = $3, version = version + 1, updated_at = now() WHERE resource_id = $1 AND tenant_id = $4 AND version = $2; then INSERT the resource_revision row at version $2 + 1; then INSERT the outbox_event row at the same aggregate_version. The event goes to a table rather than a broker because no transaction spans both.
  2. Branch on the affected-row count before doing anything else. Zero has three causes — stale version, wrong tenant, row gone — so re-read once and map to 409 carrying the current version, or 404 for an id outside the caller's tenant, which also stops the endpoint confirming that another tenant's id exists.
  3. State the engine behaviour instead of assuming it. Under READ COMMITTED the second UPDATE blocks on the row lock, and when the first commits PostgreSQL re-evaluates the WHERE clause against the newly committed row, so the version predicate now fails and the statement reports zero rows. Under REPEATABLE READ the identical collision raises SQLSTATE 40001 instead, so the handler must fold both shapes into one conflict response.
  4. Keep UNIQUE (resource_id, version) even though the predicate already serialises writers. It is what makes a lost update unwritable if any other path ever reaches the revision table, and it converts a logic bug into 23505 rather than into a silently missing history row.

Follow-up

  • A client sends the version it read ten minutes ago and the resource has moved three versions. What is in your 409 so it can resolve the conflict without a full re-fetch?
  • Two editors, two disjoint fields, no overlap. Does your answer still refuse the second write, and should it?

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.

Approach

  1. Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
  2. Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
  3. Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
  4. State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.

Follow-up

  • A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
  • The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?

How would you design an algorithm to optimize delivery routes for multiple riders?

Medium · Data Structures and Algorithms

Approach

  1. Clarify what is being optimised before choosing an algorithm: total travel time, late deliveries against a promised window, or rider utilisation, plus the constraints (rider capacity, pickup point, orders that cannot be batched together). Name it as a vehicle routing problem, which is NP-hard, so the answer is a heuristic with a quality check, not an exact solver for the whole fleet.
  2. Build the cost model first: a travel-time matrix between pickup and drop points, from shortest paths on a road graph (Dijkstra per source) or a routing service, with haversine distance only as a cheap lower bound. Travel times are asymmetric, so the matrix is not symmetric.
  3. Split it into assignment and sequencing. Assign orders to riders with greedy cheapest insertion (put each order where it adds the least cost without breaking a deadline or capacity) or, for one order per rider, the Hungarian algorithm in O(n^3). Then order each rider's stops with nearest-neighbour plus 2-opt, or Held-Karp DP in O(n^2 * 2^n) when a rider has only a handful of stops.
  4. Make it work online: collect new orders over a short batching window and re-run assignment over the batch plus unstarted orders, trading a little waiting for better batching. Never reassign an order a rider has already picked up.
  5. Edge cases: an order with no feasible rider (queue it or relax the window), a rider going offline mid-route, a cancelled order removed from a route, ties between equal-cost riders, and an empty batch.

Follow-up

  • How would you measure whether your heuristic is good enough, for example against an exact solution on small instances or a lower bound?
  • Orders arrive continuously: what does a longer batching window gain and what does it cost the customer?
  • A rider goes offline with three undelivered orders: what does your system do?

Walk me through the most challenging technical project from your previous experience.

Medium · Resume Deep Dive and Experience

Approach

  1. Pick one project where you personally made the hard technical decisions, and open with the scale in your own numbers (requests per second, data size, latency target) so the difficulty is concrete rather than asserted.
  2. Name the hard part as a technical mechanism, not as 'it was complex': a race between two writers, a query that degraded as a table grew, a migration that had to run with no downtime. Then give two or three options you weighed and the specific reason each rejected option lost.
  3. Say 'I' for what you did and name what others did; a story told entirely in 'we' leaves no way to judge your share. Keep a diagram in your head that you can sketch: components, data flow, where the bottleneck sat.
  4. Close with a measured result (latency, error rate, cost, incidents before and after) and one thing you would now do differently. The answer falls apart when it lists technologies with no decision behind them, or when you cannot defend a choice one level deeper than you described it.

Follow-up

  • What would break first if the load on that system grew ten times?
  • Which decision in that project turned out to be wrong, and how did you find out?
  • Why did you not use the alternative you rejected; what would have had to be true for it to win?

Why did you choose a specific database or framework for your previous project?

Medium · Resume Deep Dive and Experience

Approach

  1. Start from the requirements, not the product: the access patterns (key lookups, range scans, joins, aggregations), the consistency you needed (multi-row transactions or not), the write and read volume, and how often the schema changed.
  2. Name the alternatives you considered and why they lost on those requirements: for example a relational database for transactional writes and ad hoc queries versus a key-value or wide-column store for very high write throughput with simple access by key. Be specific about the property that decided it.
  3. Include the practical factors honestly: what the team could operate, existing tooling, hosting cost, and migration effort. 'The team already knew it' is a legitimate factor, but only alongside the technical fit.
  4. Say how the choice held up: what worked, what hurt later (a missing index, a hot partition, painful migrations), and whether you would choose the same today. An answer that only lists strengths, or cannot explain an internal like indexing or isolation level of the chosen database, sinks it.

Follow-up

  • What change in requirements would make you switch to a different database?
  • How did you handle schema changes or data migrations on it in production?
  • Where did it struggle under your peak load, and how did you deal with that?

Describe a situation where you had to refactor a legacy system for better performance.

Medium · Resume Deep Dive and Experience

Approach

  1. Open with the measurement that justified the work: a baseline (p50 and p99 latency, throughput, cost or error rate) and a profile or trace that located the bottleneck, such as N+1 queries, a missing index, synchronous calls in a loop, lock contention or an unbounded in-memory structure.
  2. Explain the safety net you built before changing behaviour: characterisation tests that pin current outputs, and a way to compare old and new paths (shadow traffic, dual reads, or replaying recorded requests) so you could prove results were unchanged.
  3. Describe the incremental strategy rather than a big-bang rewrite: strangler-style replacement of one path at a time, behind a feature flag, with a staged rollout and a rollback plan.
  4. Close with before-and-after numbers and what you deliberately left alone. Claiming a speedup with no baseline, or a rewrite that shipped with no way to verify correctness, is the mistake that sinks this story.

Follow-up

  • How did you prove the refactored system returned the same results as the old one?
  • What did you decide not to refactor, and why?
  • How did you justify the time spent to the people waiting on features?

How do you balance technical debt with the need for rapid feature delivery?

Medium · Resume Deep Dive and Experience

Approach

  1. Answer with a real case, not a philosophy: one piece of debt, what it was costing (slower changes in that area, repeat incidents, hours of manual work), and how you measured that cost.
  2. Give a decision rule: debt that is cheap to reverse and isolated can be taken on deliberately, written down with an owner and a trigger for paying it back; debt that touches data correctness, security or hard-to-reverse schema and API contracts is not worth the shortcut.
  3. Show how you paid it down without stopping delivery: fixing debt in code you were already changing for a feature, keeping a standing share of capacity for it, or making the case with the measured cost so a product owner could weigh it against a feature.
  4. Say what happened: what you shipped faster by accepting the debt and whether you paid it back. 'Always refactor first' or 'ship and never look back' both sink the answer, as does a story with no cost in numbers.

Follow-up

  • Tell me about debt you took on deliberately: did you pay it back, and when?
  • How did you convince a product owner to schedule cleanup work?
  • Is there debt you decided never to pay, and why was that the right call?

How did you handle a critical production issue in your last role?

Medium · Resume Deep Dive and Experience

Approach

  1. Tell it as a timeline: how the issue was detected (alert, customer report, dashboard), what the user impact was and for how long, and your role in the response.
  2. Show that you mitigated before you diagnosed: rollback, feature flag off, failover, rate limit or scaling out to stop the impact, then root cause once users were safe. Say why you chose that mitigation and what it risked.
  3. Walk the diagnosis as a sequence: what changed and when (deploys, config, traffic, a dependency), which metrics, logs or traces narrowed it, and the hypothesis you ruled out. Distinguish the trigger (the deploy) from the cause (the bug or capacity limit it exposed).
  4. Finish with the fix and the follow-up that stops a repeat: a test, an alert that would have fired earlier, a safer rollout step, a runbook entry. Blaming a colleague, hiding your own part in causing it, or ending at 'we restarted it and it went away' sinks the answer.

Follow-up

  • How did you confirm the fix worked rather than the problem just going quiet?
  • What alert or check would have caught this before customers did?
  • If rollback had not been possible, for example after a schema migration, what would you have done?

Suggested practice checklist

The seven days follow the two reported halves of the technical stage: algorithm questions about streams, shared state, graphs and recursion first, then the resume questions, then a mixed run-through.

Day 1 — Map the loop and pick your language and projects

  • Write the two reported stages in order and list the five algorithm and five resume questions beside the Technical Rounds.
  • Choose your coding language from Java, C++ or Go and write a template for reading input, a class and a test harness in it.
  • List three projects from your resume that you can discuss in depth and note one metric for each.

Deliverable: A one-page loop map, a runnable language template and a list of three projects with one metric each.

Day 2 — Streams, heaps and route heuristics

  • Implement top-k products from an order stream with a hash map and a size-k min-heap, then extend it to a sliding time window with expiring buckets.
  • Outline the multi-rider route question: how orders are assigned to riders, how stops are ordered, a greedy insertion baseline and a 2-opt improvement.

Deliverable: Working top-k code with tests, plus a written route outline covering objective, constraints, baseline and improvement.

Day 3 — Concurrency and inventory

  • Implement the thread-safe inventory cache with atomic reserve and release, then write a multi-threaded test that tries to oversell one item.
  • Replace a single lock with per-key locks or a concurrent map and explain what each design costs.
  • Do the SQL practice drills on detecting a concurrent edit and holding a cap under concurrent creates, to practise the same race in a database.

Deliverable: A cache that passes the oversell test, a note comparing the locking choices, and two completed SQL drills.

Day 4 — Graphs and recursion

  • Model a warehouse network as a graph and solve it with BFS for fewest hops, Dijkstra for weighted travel time and a topological order for dependencies.
  • Take a naive recursive function, find the overlapping subproblems, add memoization, then rewrite it with an explicit stack and compare time, space and depth.

Deliverable: Three graph solutions with stated complexity and one recursive function in memoized and iterative forms.

Day 5 — Project deep-dive stories

  • Write the answer for the most challenging project: context, your part, the hardest decision, the alternative you rejected and the measured result.
  • Write the answer for why you chose a specific database or framework, naming the access pattern, consistency need and what you would change now.
  • Write the legacy refactor answer with a before and after number and the way you kept the system running during the change.

Deliverable: Three written project stories, each with a baseline, a decision, a rejected option and a result.

Day 6 — Incidents, technical debt and design scenarios

  • Write the production issue story in order: detection, impact, diagnosis, fix and prevention, with the post-mortem change.
  • Write your rule for balancing technical debt against fast delivery, backed by one case where you paid debt down and one where you deferred it.
  • Outline a notification service for very large push volumes and a real-time order tracking system, then do the three behavioral practice drills on estimating, reversing a decision and arguing then committing.

Deliverable: A production-issue story, a technical-debt answer with two cases, two design outlines and three completed behavioral drills.

Day 7 — Mixed dry run

  • Solve one algorithm question each from the stream, shared-state and graph groups aloud, writing the code and the complexity.
  • Tell two project stories from memory, then list two questions to ask the recruiter and the technical interviewers.

Deliverable: One recorded mixed run-through, a list of the answers that still need work and two questions to ask.

Resume and experience stories

Candidates report that the resume discussion centres on the reasons behind your technical decisions and the impact of your work. Prepare each answer around a project you can defend: what you chose, what you rejected, what it cost and what changed. Reported questions come first below; the last prompt rehearses a related story.

  1. Walk me through the most challenging technical project from your previous experience.
  2. How did you handle a critical production issue in your last role?
  3. Why did you choose a specific database or framework for your previous project?
  4. Describe a situation where you had to refactor a legacy system for better performance.
  5. How do you balance technical debt with the need for rapid feature delivery?
  6. Describe a technical decision you made and later reversed: what you believed then, what changed your mind, and what the reversal cost.

Estimate work you have never done and defend the range

Hard · estimation · backfills · expand-contract

You are asked to estimate a change you have never attempted: add a column to a 100-million-row table, populate it, move reads across, and drop the old shape. Give a range with the assumptions that generate it, including batch size, the signal your backfill throttles on, and wall-clock hours, and name the three unknowns that would move the number most. Then describe a real estimate you gave under comparable ignorance: how you expressed its uncertainty, what you committed to, and how wrong you turned out to be.

Approach

  1. Decompose into independently deployable steps before estimating anything: add the column nullable, write both shapes, backfill in batches, verify, move reads, stop writing the old shape, drop it. That is four deploys spread over days, and the calendar estimate is dominated by them rather than by the loop's runtime.
  2. Do the arithmetic aloud for the part that has arithmetic in it: batch size times number of batches times per-batch duration, at a write rate the primary can absorb alongside roughly 1.2k writes per second of production traffic. The loop is throttled by replication lag and lock waits, not by how fast it can issue statements.
  3. Price the schema step by its lock rather than its statement duration. In PostgreSQL an ALTER TABLE taking ACCESS EXCLUSIVE waits for every open transaction on that table while later queries queue behind it, so a millisecond change issued during a thirty-second analytics query stalls that table for thirty seconds. Adding a nullable column with a non-volatile default avoids a rewrite from version 11; a new index wants CREATE INDEX CONCURRENTLY, which cannot run inside a transaction block and leaves an invalid index behind if it fails.
  4. Express the answer as a range whose endpoints each trace to a stated assumption, then name the cheapest experiment that collapses it, which is almost always running one real batch against the real table and multiplying.

Follow-up

  • How do you verify the backfill genuinely finished, given rows written by production traffic while it ran?
  • Where does the backfill resume from after a worker is killed mid-batch, and what makes that resume point trustworthy?

Reverse your own decision and price the reversal

Medium · reversibility · measurement · migrations

Describe a technical decision you made and later reversed. Pick one that cost something: a service you split and merged back, a cache you added and removed, an index you created that pushed the planner onto a worse plan, a projection you rebuilt from scratch. State what you believed when you decided, the measurement that changed your mind, how long the wrong version ran in production, and what the reversal cost in migrations, dual writes, and a deprecation window for callers you did not own.

Approach

  1. State the original rationale without irony, in the version you would still defend given what was known then. If it is not defensible, the story is about carelessness rather than judgement, and a different example serves you better.
  2. Give the measurement that moved with a before and after: the p99 that did not improve, the cache hit rate that sat at 40%, the plan that flipped to a sequential scan once the table passed a size you can name.
  3. Cost the reversal in steps, not adjectives: expand-and-contract deploys, the dual-write window, the callers who had to be notified, the rows already written in the wrong shape that had to be backfilled or abandoned.
  4. Distinguish reversal from rewrite by naming what you kept. Most good reversals preserve the schema or the interface and undo one decision inside it, which is also why they were affordable.

Follow-up

  • What in that decision was irreversible, and did you know it was irreversible when you made it?
  • How did you tell the people who had already built on top of the original decision?

Argue against a design, lose, and commit anyway

Medium · disagreement · service boundaries · decision records

Describe a design you argued against and lost. State the failure you predicted as a named mechanism, not a feeling about complexity: two services that would need one transaction, a projection with no rebuild path, a write path with no idempotency key. Say what evidence you brought, what the decision maker weighed instead, and what you did after the decision was made: what you instrumented, what you wrote down, and whether the prediction came true. Five minutes.

Approach

  1. State the prediction in falsifiable form up front: the mechanism, the condition that triggers it, and the observable outcome. A prediction that cannot be checked also cannot be credited to you later.
  2. Show the evidence you had at the time and label each piece honestly as measured, analogous, or intuition. Keeping the intuition is fine; disguising it as data is the thing that erodes your standing in the next argument.
  3. Represent the opposing case at full strength, including the constraint you did not control: a fixed date, a team boundary, or the fact that the decision was cheap to reverse and yours was not.
  4. Make disagree-and-commit concrete. Name the artefact you left behind so the prediction could be settled without you: the alert and its threshold, the counter on the dashboard, the decision note that recorded the trade-off and the condition that would revisit it.

Follow-up

  • What threshold on that alert would have proved you right, and did anyone ever look at it?
  • If the same proposal arrived tomorrow with the same deadline, would you argue it the same way?