Coding Fundamentals
Language choice, the DSA patterns that actually appear in infra rounds, async basics for the right kind of "I/O-bound" problem, and the code-style signals senior reviewers look for.
Picking a language for the live round
The JD names Python first and lists C++, Rust, Go, CUDA as nice-to-haves. For the coding round, the default is Python unless you're explicitly told otherwise. Reasons:
- Most infra tooling tasks at the company will be Python or Go.
- Interviewers grade on clarity and reasoning; Python lets you express the algorithm without language ceremony.
- If you're strongest in another language, say so explicitly and use it — the worst outcome is fumbling syntax in Python because you're a Go native.
For deep-system questions (kernel bypass, lock-free queues), C++ or Rust may come out naturally. Don't force it; let it come.
Python — the lingua franca
For this role, "Python" in practice means:
- Standard library fluency —
collections,heapq,itertools,asyncio,concurrent.futures,contextlib,dataclasses. - HTTP clients —
httpxfor async,requestsfor sync. - Numerical —
numpyat a comfort level. Maybepandas. - Async —
asynciofor I/O concurrency. - Subprocess and OS —
subprocess,os,pathlib. - Type hints — use them by default for senior code reviews.
# The shape of senior Python you should produce by reflex
from __future__ import annotations
from dataclasses import dataclass
from collections import deque
from typing import Iterable
@dataclass(slots=True)
class Request:
id: str
prompt_tokens: int
deadline_ms: int
class TokenRateLimiter:
"""Token-bucket rate limiter; thread-safe outer use assumed monotonic."""
def __init__(self, capacity: int, refill_per_sec: float) -> None:
self.capacity = capacity
self.refill = refill_per_sec
self._tokens = float(capacity)
self._last_ts = 0.0
def allow(self, now: float, cost: int = 1) -> bool:
self._tokens = min(
self.capacity,
self._tokens + (now - self._last_ts) * self.refill,
)
self._last_ts = now
if self._tokens >= cost:
self._tokens -= cost
return True
return False
Notice: type hints, dataclass(slots=True) for performance + clarity, from __future__ import annotations, one clear public method.
Systems languages — C++, Rust, Go
You won't be asked to write 200 lines of C++ in a 45-minute round, but you should be able to discuss why these languages show up in GPU infrastructure.
| Language | Where it lives in this stack |
|---|---|
| C++ | CUDA kernels, custom inference servers, Triton backends, integration with cuDNN/NCCL/TRT, anything inside vLLM's hot path |
| CUDA | The kernel language for NVIDIA GPUs. Knowing how a kernel launches, what shared memory and registers are, is a senior signal even if you don't write CUDA daily. |
| Rust | New control-plane services, network proxies, observability collectors. Increasingly used in adjacent infra (Tokio for async, Axum for services). Some inference layers (text-generation-inference) are Rust. |
| Go | Kubernetes ecosystem — operators, CRD controllers, kubelet extensions, networking plugins. If you write a custom scheduler extender, you'll write Go. |
// A minimal Rust sketch — async queue worker for a request pool.
// You wouldn't be asked to write this from scratch in an interview,
// but you should be able to discuss the shape.
use tokio::sync::Semaphore;
use std::sync::Arc;
async fn run_worker(
queue: Arc>,
limit: Arc,
backend: Arc,
) {
while let Ok(req) = queue.recv().await {
let permit = limit.clone().acquire_owned().await.unwrap();
let backend = backend.clone();
tokio::spawn(async move {
let _p = permit;
backend.handle(req).await;
});
}
}
Async patterns — when they matter, when they don't
Async is the right tool when:
- You're orchestrating many concurrent I/O operations (HTTP fan-out, multiple downstream services, streaming).
- You're building a gateway, router, or sidecar that holds many open connections.
- You're consuming a high-rate event stream.
Async is not the right tool when:
- Your work is CPU-bound. Async doesn't help; use processes or threads with the GIL released by the underlying lib.
- You need parallelism on multi-core, not concurrency.
# The shape of async you might be asked to write —
# fan out N inference calls with a concurrency cap.
import asyncio
import httpx
async def fan_out(prompts: list[str], url: str, max_in_flight: int = 16):
sem = asyncio.Semaphore(max_in_flight)
results: list[str | None] = [None] * len(prompts)
async with httpx.AsyncClient(timeout=60.0) as client:
async def one(i: int, prompt: str) -> None:
async with sem:
try:
r = await client.post(url, json={"prompt": prompt})
results[i] = r.json()["text"]
except httpx.HTTPError:
results[i] = None
await asyncio.gather(*[one(i, p) for i, p in enumerate(prompts)])
return results
DSA patterns that show up in this role's coding rounds
You're unlikely to get a hard graph theory problem. You are likely to get something that looks like systems-with-numbers.
| Pattern | Why it matters here | Typical problem framing |
|---|---|---|
| Hash map / hash set | Idempotency keys, dedupe, prefix-cache index, request-by-ID | "De-dup these requests"; "implement a small LRU" |
| Sliding window | Latency percentiles over time, rate limiters, queue depth tracking | "Compute p99 over the last N seconds" |
| Heap / priority queue | Priority scheduling, soonest-deadline jobs, top-k | "Pull the next inference job from a multi-priority queue" |
| Deque | Bounded FIFO queues, monotonic queue for max-in-window | "Bounded batch buffer with timeout" |
| Prefix sum / counters | Token counting, rolling sums, budget tracking | "Total tokens served in the last minute" |
| Two pointers | Window over sorted streams, merge intervals | "Merge overlapping reservation windows" |
| Greedy / bin-packing | Pack jobs onto GPUs, fit requests in a batch | "Place these jobs onto N nodes" |
| Simple graph | Topological ordering for pipeline stages, dependency DAG | "Order these training steps" |
| Reservoir sampling | Sampling logs at fixed rate without buffering everything | "Pick a uniform sample from a stream" |
Big-O sanity
Senior interviewers don't ask you to recite complexities; they expect you to reach for the right structure without thinking. Refreshers worth being cold on:
| Structure | Lookup | Insert | Notes |
|---|---|---|---|
Python dict / set | O(1) avg | O(1) avg | Hash collisions in worst case; rare |
Python list | O(1) index | O(1) append, O(n) middle | pop(0) is O(n); use deque |
collections.deque | O(1) ends | O(1) ends | O(n) middle; great for queues |
heapq | O(1) min | O(log n) | Min-heap; negate for max |
Sorted list / SortedContainers | O(log n) | O(log n) | Convenient but third-party |
For a coding round, talk out loud about the complexity of your choice before you write the code. "I'll use a heap because I need fast min and insertion is logarithmic" closes 80% of the "why this structure?" follow-up.
Code-style signals senior interviewers watch for
- Start with the signature and the data model. A class with fields. Method signatures. Then bodies. Top-down beats bottom-up under pressure.
- Names that read like the problem. Not
i, j, x. Userequest,deadline_ms,queue. - Edge cases first. Empty input, single-element, capacity zero, time going backward.
- One function, one responsibility. When you start to feel the function ballooning, extract.
- Type hints in Python. Free documentation.
- Test as you go. A small assert at the bottom that exercises the happy path is worth more than racing to "done."
- Explain trade-offs out loud. "I could use a sorted list here, but lookups would be log; for 100k entries that's negligible, so I'd take the simpler code."
- Recover from mistakes calmly. If you spot a bug, say "wait, that's wrong; here's the fix." Don't try to silently rewrite.
When given a problem, take 60 seconds to: (1) restate it, (2) clarify one assumption, (3) name the data structure, (4) name the complexity target. Then code. The setup is what separates the senior take from the junior take.
What to rehearse this week
For this role, drill these eight kinds of problem until they're reflexive. Chapter 11 has worked examples of each:
- Token-bucket rate limiter.
- Sliding-window percentile (p95/p99) over a stream.
- Priority queue with multiple classes & preemption.
- Bounded batch buffer (merge requests up to N or time T).
- Bin-packing — place items of varying memory on bins of fixed capacity.
- Connection pool with timeout & fairness.
- LRU cache (and a brief discussion of how this maps to KV-cache eviction).
- Topological order over a small DAG (pipeline stages).
Each takes 25-35 minutes. Do them on a timer. Once you've solved each once, do them again from scratch a day later. The second pass is what builds the under-pressure version.