Mock 07 — Senior Engineer

Interview type: Senior SWE coding + design hybrid Target role: Senior Software Engineer (L5 Google / E5 Meta / SDE3 Amazon) Time limit: 60 minutes Format: ONE problem + system extension + explicit tradeoff discussion Hints policy: Hints on the algorithm lower your score significantly; hints on the extension are acceptable. Primary goal: Show senior-level reasoning — not just solving, but choosing among solutions with reasoning.


What This Mock Tests

At the senior bar, mere correctness is not enough. The interviewer wants to see:

  • You consider multiple approaches and articulate why you chose one
  • You understand the production implications of your choices
  • You can extend the algorithm into a service-like context
  • You can answer “what if the input is 1000× larger” with a concrete plan

Scoring weights: Tradeoff Reasoning (#13), Production Awareness (#14), Optimization (#4), Follow-ups (#11) are all critical. A senior who scores 3 on tradeoffs has signaled “mid-level”; needs 4+.


Pick One Problem

Problem A — Design a Rate Limiter

Build a rate limiter supporting allow(user_id, timestamp) → bool. Each user can make at most N requests per W seconds. Discuss the algorithm, then extend to a multi-server / distributed setting.

Initial constraints: in-process, single-thread. N ≤ 1000 reqs/window. W ≤ 60 sec. 1M users.

Problem B — Top K Frequent Elements (LC 347) + Streaming Extension

Phase 1: Given an array nums and integer k, return the k most frequent elements. O(N log K).

[1,1,1,2,2,3], k=2  → [1, 2]
[1], k=1            → [1]

Phase 2 (extension): the input is a never-ending stream; report top-k continuously with bounded memory. Discuss exact vs approximate tradeoffs.

Problem C — Snapshot Array (LC 1146)

Implement SnapshotArray:

  • SnapshotArray(length) — initialize with length zeros
  • set(index, val) — set value at index
  • snap() → snap_id — take a snapshot, return its id
  • get(index, snap_id) — value at index at the time of snap_id

Discuss the algorithm; extend to a versioned key-value store with garbage collection of old snapshots.


Expected Communication Style

  1. Restate, including the implied requirements (“rate limit must be enforced even if the same user hits multiple instances”).
  2. Ask senior-grade clarifying questions: read-heavy vs write-heavy? Latency targets? Consistency requirements? Failure modes acceptable?
  3. Propose 2+ approaches with explicit tradeoffs. (“Token bucket vs sliding window log vs sliding window counter — I’d pick X because…”)
  4. State the algorithm and complexity.
  5. Code the chosen approach with senior code quality (clear naming, error handling at boundaries, no premature abstraction).
  6. Discuss the production extension without prompting.
  7. Anticipate failure modes — what breaks at 10× scale? 100×?

Solution Sketches

A. Rate Limiter:

  • Sliding window log: per user, deque of timestamps. On request, drop entries older than W, check length < N, append. O(N) per request (amortized O(1) drop). Memory: O(users × N).
  • Token bucket: per user, (tokens, last_refill). On request, refill tokens += (now - last) × rate, cap at N, decrement if ≥ 1. O(1) per request. Slightly bursty.
  • Sliding window counter: approximate; uses 2 buckets (previous + current window), weighted by overlap. O(1), small memory.

Distributed extension: per-user state in Redis with atomic Lua script; or consistent-hash users to dedicated instances; or central counter with relaxed accuracy.

B. Top K Frequent:

  • Static: Counter + min-heap of size K. O(N log K).
  • Streaming exact: impossible with bounded memory in general (any element could become top-K later).
  • Streaming approximate: Count-Min Sketch + heap of candidates; or Misra-Gries / SpaceSaving algorithm for ε-approximate. O(1/ε) memory.

C. Snapshot Array:

  • Naïve: copy entire array per snapshot. O(length) per snap, O(snaps × length) memory.
  • Better: per-index, store list of (snap_id, value) pairs sorted by snap_id. Lookup with binary search. O(log S) per get, O(1) per set, O(total writes) memory.

Versioned KV store extension: persistent data structures (Clojure-style); or copy-on-write trees; or LSM-tree with snapshot isolation.


Common Failure Modes

  1. Implemented the first algorithm that came to mind without discussing alternatives. This is the #1 senior-bar failure.
  2. Said “I’d just use Redis” without explaining the algorithm Redis would implement. The interviewer wants the algorithm; the database is a deployment choice.
  3. Top-K streaming: claimed exact algorithm with bounded memory. Impossible in general; signals theoretical weakness.
  4. Snapshot Array: copied the array per snapshot. Acceptable as brute force; bad as final answer for a senior.
  5. No tests beyond the given examples.
  6. Skipped the production extension entirely.

Passing Bar

  • Total score: 53/70 (average 3.8)
  • Tradeoff Reasoning #13: ≥ 4
  • Production Awareness #14: ≥ 4
  • Optimal or near-optimal algorithm
  • Extension discussed substantively (not just “I’d shard it”)
  • Correct, readable code

Follow-up Questions

For A (Rate Limiter):

  • Latency budget: < 1ms p99. → In-memory store; Redis is borderline (network RTT). Local cache with eventual sync.
  • Multi-region with strict global limit. → Hard; usually relaxed to per-region limit + occasional reconciliation.
  • What if Redis goes down? → Fail-open (allow) vs fail-closed (deny); usually fail-open for rate limiters.
  • Hot user (one user makes 90% of requests). → Dedicated shard; or local fast path before checking shared state.

For B (Top K):

  • Approximate with ε = 0.01. → Count-Min Sketch sized accordingly.
  • Top K most-improved over the last hour. → Two-window comparison; bigger memory.
  • Trending detection (top K with sudden growth). → Slope/derivative-based; needs time-windowed counts.
  • What if K = 1M? → Heap-of-K doesn’t fit memory; external merge or sampling.

For C (Snapshot Array):

  • Snapshot every write (versioned KV). → Same structure; consider compaction.
  • Memory pressure: drop snapshots older than 1 hour. → Per-index list pruning; tombstones for fully-deleted snaps.
  • Snapshot isolation in a multi-writer setting. → Multi-version concurrency control; per-transaction snapshot id.
  • Persist snapshots to disk. → Log-structured store; periodically checkpoint.

Required Tests

  • Given examples
  • Empty / boundary input
  • Heavy churn (many writes to same index for C)
  • Single user / single key
  • Burst of requests at the window boundary (A)
  • K = N for B (no filtering)

Required Complexity + Production Discussion

Cover:

  • Time per operation, space per user/element
  • Latency under typical load vs worst case
  • Memory growth and GC implications
  • Failure semantics (what happens on partial failure)
  • Monitoring metrics you’d add (rate limit reject rate, top-K convergence time, snapshot lookup p99)

Self-Evaluation Template

Mock 07 — Senior Engineer
Date: _______
Problem: _______
Time: ___ / 60 min

Scores (1–5):
___ Total /70

Tradeoff Reasoning (#13): ___
Production Awareness (#14): ___
Did I propose 2+ approaches before coding? Y/N
Did I anticipate scale-up failure modes? Y/N

Action item:

What to Do If You Fail

  • Tradeoff or Production score below 4: Read Phase 8 (practical engineering) deeply; rebuild a small system (rate limiter, cache).
  • Algorithm score below 3: You haven’t earned the right to do senior interviews yet; back to Mock 04–06.
  • Code quality issues: Read CODE_QUALITY.md.
  • Pass twice consecutively before Mock 08.