Mock Week 5 — System Design and Coding Combined Session
Advertisement
Overview
Senior-level FAANG interviews test both breadth and depth in the same session: design a system at high level, then implement one of its core components from scratch. This format appears at L5 at Google, E5 at Meta, and SDE II at Amazon. Week 5 builds the ability to transition fluidly between the two modes without losing context or communication quality.
Why This Matters
Most candidates prepare system design and coding as separate skills. Senior interviewers deliberately test the transition between them — they want to see that you can hold a high-level architectural decision in mind while simultaneously writing clean, correct code for a component that implements it.
FAANG mock interview preparation at week 5 requires practicing the handoff: "I described the URL shortener as using a base-62 counter — let me now implement that encoder." Candidates who can articulate the architecture and then implement a specific component without losing either context or code quality demonstrate the engineering judgment that earns senior-level ratings.
Session Format
| Phase | Time | Activity |
|---|---|---|
| System design | 0:00 – 0:15 | High-level architecture, 3 components |
| Component deep dive | 0:15 – 0:25 | Drill into one specific component |
| Code the core | 0:25 – 0:55 | Implement the critical data structure or algorithm |
| Review and complexity | 0:55 – 1:00 | Walk one example, state exact O() |
Core Framework — Three Combo Problems
Combo 1: URL Shortener — Base-62 Encoder
Design phase (15 minutes): encode URL, decode short code, handle 100 million URLs per day. Storage: key-value store such as DynamoDB. Encoding: base-62 counter or hash plus truncate. Collision handling: retry with increment. Read-to-write ratio is 100 to 1, so add a Redis read cache.
CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
def encode(n: int) -> str:
res = []
while n:
res.append(CHARS[n % 62])
n //= 62
return ''.join(reversed(res)) or CHARS[0]
def decode(s: str) -> int:
n = 0
for c in s:
n = n * 62 + CHARS.index(c)
return nconst CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
function encode(n) {
const res = [];
while (n) { res.push(CHARS[n % 62]); n = Math.floor(n / 62); }
return res.reverse().join('') || CHARS[0];
}
function decode(s) {
let n = 0;
for (const c of s) n = n * 62 + CHARS.indexOf(c);
return n;
}Time: O(log n base 62) for encode/decode | Space: O(log n) for result string
Combo 2: Distributed Cache — LRU Eviction
Design phase: consistent hashing distributes keys across nodes. LRU eviction runs within each node. Primary-replica replication for fault tolerance. Background TTL thread evicts expired keys.
The LRU implementation uses a doubly-linked list plus hash map for O(1) get and put:
class LRUNode:
def __init__(self, key=0, val=0):
self.key = key
self.val = val
self.prev = self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.cap = capacity
self.cache = {}
self.head = LRUNode() # dummy head
self.tail = LRUNode() # dummy tail
self.head.next = self.tail
self.tail.prev = self.head
def _remove(self, node):
node.prev.next = node.next
node.next.prev = node.prev
def _insert_front(self, node):
node.next = self.head.next
node.prev = self.head
self.head.next.prev = node
self.head.next = node
def get(self, key: int) -> int:
if key not in self.cache:
return -1
self._remove(self.cache[key])
self._insert_front(self.cache[key])
return self.cache[key].val
def put(self, key: int, value: int) -> None:
if key in self.cache:
self._remove(self.cache[key])
node = LRUNode(key, value)
self.cache[key] = node
self._insert_front(node)
if len(self.cache) > self.cap:
lru = self.tail.prev
self._remove(lru)
del self.cache[lru.key]Time: O(1) for get and put | Space: O(capacity)
Combo 3: Real-Time Leaderboard — Top-K Players
Design phase: 10 million players, updates via Redis sorted set with ZADD at O(log n). Top-K query via ZREVRANGE at O(K log n). Write-behind pattern persists to a relational DB.
from sortedcontainers import SortedList
class Leaderboard:
def __init__(self):
self.scores = {}
self.sl = SortedList(key=lambda x: -x[0])
def update(self, player_id: str, score: int) -> None:
if player_id in self.scores:
self.sl.remove((self.scores[player_id], player_id))
self.scores[player_id] = score
self.sl.add((score, player_id))
def top(self, k: int):
return [(pid, sc) for sc, pid in self.sl[:k]]Time: O(log n) per update, O(K) for top-K | Space: O(n) for all players
System Design Checklist
Before diving into any design, cover these five areas in order:
- Clarify requirements — functional (what does it do?) and non-functional (scale, latency, availability)
- Estimate scale — DAU, QPS, storage per day, bandwidth
- High-level design — Client, Load Balancer, App Servers, Cache, DB, replicas
- Deep dive one component — data model, indexing strategy, sharding key
- Trade-offs — SQL vs NoSQL, consistency vs availability, cache invalidation strategy
Common Mistakes
- Jumping into code before completing the design phase — lose the architectural context
- Not mentioning the read-to-write ratio — it determines caching strategy
- Forgetting to handle the encode edge case when n equals 0
- Skipping the LRU dummy head and tail — leads to null pointer bugs in remove
- Not discussing the trade-off between fan-out on write vs fan-out on read
Interview Tips
- Open the design phase with "Let me start with requirements — functional and non-functional" before drawing anything
- Transition to code explicitly: "I described the encoder — let me implement it now"
- During coding, reference the design: "This CHARS string matches what I said about base-62 encoding"
- State the complexity of the implemented component in the context of the full system: "This is O(1) per get, which is what makes the cache worth building"
- End with one trade-off you would revisit given more time
Key Takeaways
- Week 5 mirrors the senior-level interview format: design breadth plus implementation depth in the same session
- The handoff from design to code must be explicit — name the component you are implementing before typing
- Base-62 encoding runs in O(log n base 62) time; URL shorteners typically use 6-7 character codes
- LRU cache achieves O(1) get and put using a doubly-linked list plus hash map
- A real-time leaderboard uses a sorted set for O(log n) updates and O(K) top-K queries
- Always cover requirements, scale estimation, high-level design, deep dive, and trade-offs in every system design
- The read-to-write ratio drives caching strategy — a 100-to-1 ratio requires aggressive read caching
- Candidates who can design and implement without losing context demonstrate the judgment that earns senior ratings
Advertisement