no card has every word. Showing the closest matches
JUNIOR What they test
Can you code, reason and learn? Fundamentals over breadth.
Coding round is king: arrays, hash maps, strings, two pointers, BFS/DFS, simple DP. Say the Big-O.
One language, deep: collections, errors, how references/values behave.
OOP pillars + SOLID basics , SQL joins, HTTP + REST, git, writing a unit test.
AI literacy: what an LLM/token/prompt is, and how you use AI tools responsibly.
Think out loud, ask clarifying questions, show curiosity. Unfinished but well reasoned beats silent and perfect.
MID What they test
Can you own a feature end to end without hand-holding?
Clean code: SOLID applied, patterns used for a reason, testable design.
Data: indexes, transactions, N+1, picking SQL vs NoSQL.
APIs: REST design, idempotency, pagination, auth (OAuth/JWT).
Intro system design: cache, queue, load balancer, and why each one is there.
Prod: debugging, logs/metrics, CI/CD, safe deploys. AI: RAG, tool calling basics.
Stories: a bug you chased, a feature you shipped, feedback you acted on.
SENIOR What they test
Can you make good tradeoffs, own ambiguity and lift the team?
System design depth: scaling, caching, sharding, consistency, failure modes, back-of-envelope.
Distributed systems: event-driven, delivery guarantees, sagas/outbox, observability, SLOs.
Architecture judgment: monolith vs services, when not to use a pattern.
AI in production: evals, cost/latency, guardrails, agents & RAG quality.
Leadership: mentoring, design reviews, incidents, pushing back with data.
Coding still matters, but clarity and tests beat cleverness.
ARCHITECT What they test
Can you shape systems and organizations over years, not sprints?
Boundaries: DDD, bounded contexts, integration styles, data ownership.
NFRs as design drivers: availability, RTO/RPO, security, compliance, cost.
Evolution: strangler fig, migrations, BC and versioning, tech-debt strategy.
Platform & cloud: multi-region, IaC, platform engineering, FinOps.
AI strategy: build vs buy, model/vendor risk, governance, LLM gateway, eval culture.
Communicate up and down: ADRs, diagrams, and the "why" for executives.
ARCH Architect's toolkit
ADR short record: context → decision → consequences
C4 model diagrams at Context → Container → Component → Code
NFRs / "-ilities" scalability, availability, security, maintainability, cost
Conway's law systems mirror org structure; inverse Conway maneuver
Buy vs build build only what differentiates you
Fitness functions automated checks that architecture rules hold
Tech radar adopt / trial / assess / hold
One-way doors irreversible decisions deserve slow, deep review
LANG Python
from collections import Counter, defaultdict, deque
import heapq
freq = Counter(words).most_common(3)
g = defaultdict(list); g[u].append(v)
q = deque([start]); q.popleft() # O(1) queue
heapq.heappush(h, (prio, item)) # min-heap
pairs.sort(key=lambda p: (-p[1], p[0]))
squares = [x*x for x in xs if x % 2]
@dataclass(frozen=True)
class Point: x: int; y: int
Idioms: comprehensions, generators (yield) for lazy streams, with for context managers, enumerate/zip, f-strings.
Typing: type hints + mypy/pyright; Protocol = structural interface.
Async: asyncio event loop; await asyncio.gather(*tasks).
Gotchas: mutable default args (def f(x=[])), late-binding closures in loops, is vs ==.
GIL: threads for I/O, multiprocessing for CPU. Free-threaded builds (3.13+) are removing it.
LANG JavaScript / TypeScript
const counts = new Map();
for (const w of words) counts.set(w, (counts.get(w) ?? 0) + 1);
const { id, ...rest } = user; // destructure
const name = user?.profile?.name ?? "anon";
const [a, b] = await Promise.all([fa(), fb()]);
nums.sort((x, y) => x - y); // default sort is lexicographic!
type Result<T> = { ok: true; value: T } | { ok: false; error: string };
Event loop: call stack → microtasks (promises) drain first → then macrotasks (timers, I/O).
this depends on call site; arrow functions capture lexical this.
TS: structural typing, generics, union + narrowing, unknown over any, utility types (Partial, Pick, Record).
Gotchas: == coercion (use ===), 0.1+0.2 !== 0.3, var hoisting, closures in loops (use let).
LANG Java
Map<String, Integer> freq = new HashMap<>();
for (var w : words) freq.merge(w, 1, Integer::sum);
var top = freq.entrySet().stream()
.sorted(Map.Entry.<String,Integer>comparingByValue().reversed())
.limit(3).map(Map.Entry::getKey).toList();
record Point(int x, int y) {} // immutable data carrier
var pq = new PriorityQueue<int[]>((a, b) -> a[0] - b[0]);
try (var ex = Executors.newVirtualThreadPerTaskExecutor()) { ex.submit(task); }
Modern: records, sealed interfaces, pattern matching in switch, virtual threads (21).
equals/hashCode contract — override both or HashMap breaks.
Gotchas: Integer == only works in cache range (−128..127), type erasure on generics, checked vs unchecked exceptions.
JVM: heap/stack, generational GC (G1, ZGC), JIT warm-up.
LANG Go
freq := map[string]int{}
for _, w := range words { freq[w]++ }
results := make(chan int)
var wg sync.WaitGroup
for _, j := range jobs {
wg.Add(1)
go func() { defer wg.Done(); results <- work(j) }()
}
go func() { wg.Wait(); close(results) }()
if err != nil { return fmt.Errorf("load: %w", err) }
Errors are values , wrap with %w, check with errors.Is/As.
Interfaces are implicit (duck typing at compile time). Keep them small, define at consumer.
CSP: "share memory by communicating". select, context.Context for cancel/timeout.
Gotchas: nil-pointer-in-interface ≠ nil, slices share backing arrays, maps not goroutine-safe.
LANG C# / .NET
var top = words.GroupBy(w => w)
.OrderByDescending(g => g.Count())
.Take(3).Select(g => g.Key).ToList(); // LINQ
public record Point(int X, int Y);
var msg = shape switch {
Circle { R: > 10 } => "big circle",
Circle c => $"circle {c.R}",
_ => "other" };
await using var conn = await db.OpenAsync(ct);
async/await on Task; pass CancellationToken.
Nullable reference types , pattern matching, records, Span<T> for zero-copy.
Gotchas: async void (only for event handlers), .Result deadlocks, IEnumerable deferred execution (enumerates twice).
struct vs class = value vs reference semantics.
LANG Rust
let mut freq: HashMap<&str, usize> = HashMap::new();
for w in &words { *freq.entry(w).or_insert(0) += 1; }
fn parse(s: &str) -> Result<u32, ParseIntError> {
let n = s.trim().parse::<u32>()?; // ? propagates Err
Ok(n * 2)
}
match shape { Shape::Circle(r) => area(r), Shape::Square(s) => s * s }
let shared = Arc::new(Mutex::new(vec![]));
Ownership: one owner; move by default; borrow &T (many) XOR &mut T (one).
No null, no exceptions: Option / Result + exhaustive match.
Traits = interfaces + generics (static dispatch) or dyn Trait (dynamic).
Fearless concurrency: Send/Sync checked at compile time. tokio for async.
String (owned) vs &str (borrowed slice).
LANG C++
std::unordered_map<std::string, int> freq;
for (auto& w : words) ++freq[w];
std::priority_queue<int, std::vector<int>, std::greater<>> minHeap;
auto p = std::make_unique<Widget>(); // sole owner
auto s = std::make_shared<Cache>(); // ref-counted
std::ranges::sort(v, {}, &User::age);
RAII: resource lifetime = object lifetime; destructors release.
Move semantics (std::move, rvalue refs) avoid copies. Rule of 0 / 3 / 5.
priority_queue is a max-heap by default.
Gotchas: undefined behavior, iterator invalidation on vector resize, dangling refs, shared_ptr cycles (use weak_ptr).
LANG PHP 8.x
enum Status: string { case Paid = 'paid'; case Due = 'due'; }
final class Money {
public function __construct(public readonly int $cents) {}
}
$label = match (true) { $n < 0 => 'neg', $n === 0 => 'zero', default => 'pos' };
$slug = $title |> trim(...) |> strtolower(...); // 8.5 pipe
8.4: property hooks, asymmetric visibility public private(set), lazy objects, array_find/any/all.
8.5: pipe operator |>, clone-with, #[\NoDiscard], array_first/last.
Gotchas: foreach(&$v) then reuse $v; self vs static (late static binding); never unserialize() untrusted input.
ROSETTA Same idea, many languages
Hash map Min-heap Dynamic array
Python dictheapqlist
JS/TS Mapnone (hand-roll) Array
Java HashMapPriorityQueueArrayList
Go mapcontainer/heapslice
C# DictionaryPriorityQueueList<T>
Rust HashMapBinaryHeap+ReverseVec
C++ unordered_mappriority_queue+greatervector
ROSETTA Concurrency models
Python asyncio (single-thread loop), threads (I/O), processes (CPU)
JS/Node single-threaded event loop + promises; worker threads for CPU
Java OS threads, executors, CompletableFuture, virtual threads
Go goroutines (M:N scheduled) + channels (CSP)
C# Task-based async/await on the thread pool
Rust threads + ownership; async futures run by a runtime (tokio)
Erlang/Elixir actors: isolated processes + message passing, "let it crash"
LANG Language concepts
Paradigms imperative · OOP · functional · declarative (SQL, HTML) · logic
Static vs dynamic types checked at compile time vs runtime
Strong vs weak no vs implicit coercion ("1"+1)
Nominal vs structural Java/C# name-based vs TS/Go shape-based
Compiled / JIT AOT to native (Go, Rust) vs bytecode + JIT (JVM, .NET, V8)
Memory GC (tracing / ref-count) vs ownership (Rust) vs manual (C)
Value vs reference copy on assign vs share pointer; pass-by-sharing
Stack vs heap fast, scoped, fixed-size vs dynamic, longer-lived
Closure function + captured lexical environment
Generics reified (C#) vs erased (Java) vs monomorphized (Rust, C++)
OOP Four pillars
Encapsulation : hide state behind behavior; invariants enforced in one place.
Abstraction : expose what , hide how (interfaces, public API).
Inheritance : "is-a" reuse. Deep trees = fragile base class .
Polymorphism : one interface, many forms. Subtype (override), parametric (generics), ad-hoc (overload).
Senior signal: say where each one bites you, not just the definition.
OOP Composition over inheritance
// inheritance: behavior locked in at compile time
class LoggingRepo extends SqlRepo { ... }
// composition: behavior injected, swappable, testable
class OrderService {
constructor(private repo: Repo, private log: Logger) {}
place(o: Order) { this.repo.save(o); this.log.info("placed", o.id); }
}
Prefer has-a + interfaces; inherit only for true is-a that honors Liskov.
Composition enables Strategy, Decorator and DI naturally.
OOP Interface vs abstract class & friends
Interface contract only (may have default methods); multiple allowed
Abstract class partial implementation + state; single inheritance
Trait / mixin reusable behavior bundle, horizontal reuse
Overload same name, different params: compile-time
Override subclass replaces method: runtime (dynamic dispatch)
Static dispatch resolved at compile time (generics, templates) — faster, inlinable
Diamond problem multiple inheritance ambiguity; solved by interfaces/MRO
KEY DIP vs DI vs IoC container
DIP = the principle (depend on abstractions).
DI = the technique (pass deps in, usually via constructor).
Container = the tool (Spring, .NET DI, Guice, NestJS resolve them).
Anti-pattern: Service Locator (Container.get(X) inside business code) hides deps and breaks tests.
Separating these three cleanly is a senior signal.
OOP Coupling, cohesion, Demeter
Low coupling between modules, high cohesion within them.
Law of Demeter: talk to friends only. No a.getB().getC().do() train wrecks.
Tell, don't ask: account.withdraw(x), not if (acc.balance > x) acc.balance -= x.
Anemic domain model: data bags + logic in services. OK for CRUD, smell for rich domains.
SOLID The five
S ingle Responsibility: one reason to change (one actor). Invoice ≠ InvoicePrinter ≠ InvoiceRepo.
O pen/Closed: add behavior by adding code (new Strategy/plugin), not editing tested code.
L iskov: subtypes must honor the contract. Classic break: Square extends Rectangle (setWidth changes height).
I nterface Segregation: many small interfaces > one fat one. No Printer.fax() throwing NotSupported.
D ependency Inversion: high-level policy and low-level details both depend on abstractions .
SOLID OCP in 8 lines
# closed: every new type edits this function
def price(kind, base):
if kind == "vip": return base * 0.8
if kind == "sale": return base * 0.5
# open: new behavior = new class, zero edits
class Discount(Protocol):
def apply(self, base: float) -> float: ...
def price(d: Discount, base): return d.apply(base)
PRINCIPLES Beyond SOLID
DRY one source of truth for knowledge , not for similar-looking code
AHA / WET avoid hasty abstractions; duplicate twice, abstract on the third
KISS simplest thing that works
YAGNI don't build for imagined requirements
SoC separation of concerns (UI / domain / infra)
POLA principle of least astonishment
Fail fast validate at boundaries, crash loudly on broken invariants
Boy Scout leave code cleaner than you found it
CoC convention over configuration (Rails, Spring Boot)
SMELLS Code smells → refactor
Long method Extract Method
God class Extract Class by responsibility
Feature envy Move Method to the data it uses
Shotgun surgery one change → many files; consolidate
Primitive obsession Value Object (Email, Money)
Switch on type Replace Conditional with Polymorphism
Long param list Parameter Object / Builder
Magic numbers named constants / enums
GoF Creational
Factory Method : subclass/function decides which concrete to create.
Abstract Factory : families of related objects (UI kit per OS, driver per cloud).
Builder : step-by-step construction of complex/immutable objects; fluent API.
Prototype : clone an existing instance.
Singleton : one instance. Often an anti-pattern (global state, hidden deps). Prefer a DI-scoped singleton.
GoF Structural
Adapter : convert one interface to another (wrap a 3rd-party SDK).
Decorator : wrap to add behavior, same interface (caching, logging, retry).
Facade : simple front for a complex subsystem.
Proxy : same interface, controls access (lazy load, remote, auth).
Composite : tree where leaf and group share an interface (UI, file system).
Bridge : split abstraction from implementation so both vary.
Flyweight : share immutable intrinsic state (glyphs, tiles).
GoF Behavioral
Strategy : swap algorithms behind an interface (payment, pricing, routing).
Observer : subscribers notified on change (events, reactive UIs).
Command : request as an object → queue, undo, audit log.
State : behavior changes with internal state (order lifecycle FSM).
Template Method : base defines skeleton, subclasses fill steps.
Chain of Responsibility : pass along handlers (HTTP middleware).
Iterator · Visitor · Mediator · Memento : traverse · add ops to a tree · centralize comms · snapshot state.
PATTERN Decorator + Strategy, live
class CachedRepo(Repo): # Decorator
def __init__(self, inner: Repo, cache):
self.inner, self.cache = inner, cache
def get(self, id):
if (hit := self.cache.get(id)) is not None: return hit
v = self.inner.get(id); self.cache[id] = v; return v
strategies = {"card": pay_card, "paypal": pay_pp} # Strategy
strategies[method](amount)
In functional languages, Strategy is just "pass a function".
PICK "I need to…" → pattern
swap algorithm at runtime Strategy
add behavior w/o subclassing Decorator
tame an ugly API Adapter / Facade
react to something happening Observer / Pub-Sub
undo / queue actions Command
complex object creation Builder / Factory
lifecycle with rules State machine
pipeline of handlers Chain of Responsibility / middleware
treat one & many alike Composite
FP Functional patterns
Pure functions + immutability → easy tests, safe concurrency.
Higher-order : functions in/out; map/filter/reduce.
Currying / partial application , function composition, pipelines.
Option / Result (a.k.a. Maybe / Either) replace null & exceptions; "monad" = chainable wrapper with flatMap.
Algebraic data types + exhaustive pattern matching.
Functional core, imperative shell : pure logic inside, I/O at the edges.
ANTI Anti-patterns
God object , big ball of mud , spaghetti code.
Golden hammer : one tool for everything ("just add Kafka").
Premature optimization / premature abstraction.
Distributed monolith : microservices that must deploy together.
Shared database across services = hidden coupling.
Magic / action at a distance : global state, hidden side effects.
ARCH Monolith ↔ Microservices
Win Cost
Monolith simple deploy, local calls, ACID scales as one, team contention
Modular mono enforced module boundaries, one deploy discipline required
Microservices independent deploy/scale, team autonomy network, distributed txns, ops overhead
Serverless zero ops, pay per call cold starts, limits, lock-in
Start modular monolith; split along bounded contexts when team or scale forces it (Conway's law).
ARCH Clean / Hexagonal / Onion
Dependency rule: source deps point inward . Domain knows nothing of DB, HTTP or frameworks.
Ports = interfaces the core owns (OrderRepo, PaymentGateway).
Adapters = implementations at the edge (Postgres repo, Stripe client, REST controller).
Layers: Entities → Use cases → Interface adapters → Frameworks .
Payoff: swap infra, unit-test core without mocks of the world.
DDD Domain-Driven Design
Ubiquitous lang. code uses the business's words
Bounded context boundary where a model is consistent (≈ service boundary)
Entity identity over time (Order#42)
Value object defined by values, immutable (Money, Address)
Aggregate consistency boundary; one root; one txn per aggregate
Domain event "something happened" (OrderPlaced)
ACL anti-corruption layer translating a foreign model
Context map how contexts relate (upstream/downstream, shared kernel)
ARCH CQRS & Event Sourcing
CQRS : separate write model (commands, validation) from read models (denormalized, fast queries).
Event Sourcing : store events , not current state. State = fold(events).
Gains: full audit log, time travel, rebuild new projections by replay .
Costs: eventual consistency of reads, event schema versioning, snapshots needed for long streams.
Use them independently; neither requires the other.
ARCH Microservice patterns
API Gateway single entry: routing, auth, rate limit, TLS
BFF backend-for-frontend, one per client type
Service mesh sidecar proxies (Envoy/Istio/Linkerd): mTLS, retries, telemetry
Strangler fig incrementally replace legacy behind a facade
DB per service own your data; share via APIs/events
Service discovery registry / DNS (Consul, K8s Services)
Bulkhead isolate resource pools so one failure doesn't sink all
Circuit breaker closed → open → half-open; fail fast
EDA Event-driven basics
Event = fact, past tense, many listeners (PaymentCaptured). Command = intent, one handler (CapturePayment).
Queue (point-to-point): each message to one consumer; work distribution.
Pub/Sub / topic : each subscriber gets a copy; fan-out.
Choreography : services react to each other's events (loose, harder to trace).
Orchestration : a coordinator tells services what to do (explicit, central).
Event types: notification (thin, "go fetch") vs event-carried state transfer (fat payload).
EDA Delivery guarantees
At-most-once (may lose) · At-least-once (may duplicate) · Exactly-once ≈ at-least-once + idempotent consumer .
Idempotency key : store processed IDs; dedupe on retry. No double charges.
Ordering only within a partition/key: route by orderId.
Retries : exponential backoff + jitter , capped; then DLQ .
Poison message : always fails → blocks partition unless moved to DLQ.
def handle(msg):
if store.seen(msg.id): return # idempotent
with tx: apply(msg); store.mark(msg.id)
EDA Outbox, CDC, Saga
Dual-write problem: save to DB and publish to broker. One can fail.
Transactional Outbox : write event to an outbox table in the same txn ; relay publishes it.
CDC : tail the DB log (Debezium) → stream changes as events.
Inbox : consumer-side dedupe table.
Saga : long-running distributed txn = local txns + compensating actions (refund, release stock). No 2PC.
EDA Brokers compared
Kafka distributed log ; partitions, consumer groups, offsets, retention + replay ; high throughput
RabbitMQ smart broker; exchanges + routing keys; per-message ack; task queues
SQS / SNS managed queue / fan-out topic (AWS); FIFO variant
Pub/Sub GCP managed pub/sub; push or pull
EventBridge event bus with rules/filters, SaaS integrations
NATS / Redis Streams lightweight, low-latency messaging
Kafka: parallelism ≤ #partitions per consumer group.
STREAM Stream processing
Batch (bounded, high latency) vs stream (unbounded, low latency).
Windows: tumbling (fixed, no overlap) · sliding (overlap) · session (gap-based).
Event time vs processing time ; watermarks handle late data.
Backpressure : slow consumer signals producer to slow down.
Lambda (batch + speed layers) vs Kappa (stream only, replay the log).
Tools: Flink, Kafka Streams, Spark Structured Streaming, Beam.
CLOUD Service models
IaaS VMs, networks, disks (EC2, Compute Engine)
CaaS managed containers (EKS, GKE, AKS, Cloud Run, Fargate)
PaaS push code, platform runs it (App Engine, Heroku, App Service)
FaaS functions on events (Lambda, Cloud Functions)
SaaS finished product (Gmail, Salesforce)
Shared responsibility: provider secures the cloud, you secure what's in it (IAM, data, config).
Region ⊃ Availability Zones (isolated DCs). Multi-AZ for HA, multi-region for DR.
CLOUD AWS · GCP · Azure
Need AWS GCP Azure
VM EC2 Compute Engine Virtual Machines
Functions Lambda Cloud Functions Functions
K8s EKS GKE AKS
Containers Fargate / App Runner Cloud Run Container Apps
Object S3 Cloud Storage Blob Storage
SQL RDS / Aurora Cloud SQL / Spanner Azure SQL
NoSQL DynamoDB Firestore / Bigtable Cosmos DB
Queue SQS Pub/Sub Service Bus
CDN CloudFront Cloud CDN Front Door
Warehouse Redshift BigQuery Synapse / Fabric
AI Bedrock / SageMaker Vertex AI Azure AI Foundry
CLOUD 12-Factor app (short)
One codebase, many deploys · explicit deps · config in env .
Backing services as attached resources · strict build → release → run .
Stateless processes · port binding · scale out via processes.
Disposability : fast start, graceful shutdown · dev/prod parity.
Logs as event streams (stdout) · admin tasks as one-off processes.
K8S Containers & Kubernetes
Image / container immutable template / running instance (namespaces + cgroups)
Pod smallest unit; 1+ containers sharing network
Deployment desired replicas + rolling updates
Service stable virtual IP / DNS for pods
Ingress / Gateway L7 HTTP routing into the cluster
ConfigMap / Secret config / sensitive config
HPA autoscale on CPU / custom metrics
Liveness vs readiness restart me vs don't send me traffic yet
StatefulSet stable identity + storage (DBs)
DaemonSet one pod per node (log agents)
Helm / Kustomize packaging / overlays for manifests
K8s is a reconciliation loop : desired state vs actual state.
CLOUD Serverless
Event-triggered, auto-scaled, pay per invocation , scale to zero.
Cold starts, execution time limits, concurrency caps, harder local debugging.
Must be stateless ; state lives in DB / object store / cache.
Watch: DB connection storms (use proxies/pools), fan-out cost surprises.
Edge functions (Cloudflare Workers, Vercel/Lambda@Edge): run close to the user.
IaC Infra as Code & GitOps
Terraform/OpenTofu : declarative HCL, state file , plan → apply, detect drift .
Pulumi / CDK : IaC in real languages. CloudFormation / Bicep : native.
Ansible : config management (mutable, procedural).
GitOps (Argo CD, Flux): Git is the source of truth; controller syncs cluster to repo.
Immutable infra : replace, don't patch. Cattle, not pets.
CLOUD HA & Disaster Recovery
RTO = how long to recover. RPO = how much data you can lose.
DR tiers: backup/restore → pilot light → warm standby → active-active (cost ↑, RTO ↓).
Availability math: 99.9% ≈ 8.8 h/yr · 99.99% ≈ 53 min/yr. Serial deps multiply (0.99×0.99 = 0.98).
No single points of failure; health checks + automatic failover.
Chaos engineering : inject failure deliberately to prove resilience.
FinOps: spot/preemptible, reserved/savings plans, right-size, watch egress costs, tag everything.
SD The interview loop
1 Requirements : functional + non-functional (scale, latency, consistency, availability).
2 Estimate : QPS, storage, bandwidth, read:write ratio.
3 API : key endpoints / events.
4 Data model : entities, access patterns → store choice.
5 High-level : clients → LB → services → cache → DB → queue.
6 Deep dive : the hardest part (hot keys, fan-out, consistency).
7 Bottlenecks & tradeoffs : SPOFs, scaling, monitoring, failure modes.
Drive the conversation. State assumptions out loud.
SD Numbers & napkin math
L1 / RAM ~1 ns / ~100 ns
SSD random read ~100 µs
Same-DC round trip ~0.5 ms
Cross-continent ~150 ms
1 day 86,400 s ≈ 105 s
1M req/day ≈ 12 req/s (peak ×2–10)
100M DAU × 10 req ≈ 12k QPS avg
Powers 210 ≈103 KB · 220 MB · 230 GB · 240 TB
Single box ~10k+ simple RPS app; Postgres ~10k TPS tuned
SD Scaling & load balancing
Vertical (bigger box, simple, ceiling) vs horizontal (more boxes, needs stateless services).
L4 LB (TCP, fast, blind) vs L7 LB (HTTP-aware: path routing, headers, TLS termination).
Algorithms: round robin · weighted · least connections · IP hash · consistent hashing .
Sticky sessions = scaling smell; move session to Redis/JWT.
Autoscaling on CPU, queue depth or custom metrics; scale-in carefully.
SD Caching
Cache-aside app reads cache → miss → DB → fill. Most common.
Read-through cache loads from DB itself
Write-through write cache + DB synchronously (consistent, slower)
Write-back write cache, flush later (fast, risk of loss)
Eviction LRU · LFU · TTL · FIFO
Stampede hot key expires, herd hits DB → lock / jittered TTL / stale-while-revalidate
Layers browser → CDN → reverse proxy → app (in-mem) → Redis → DB
"Two hard things: cache invalidation and naming things."
SD Replication & sharding
Leader-follower : writes to leader, reads scale on replicas → replication lag .
Multi-leader : multi-region writes → conflict resolution (LWW, CRDTs).
Leaderless (Dynamo/Cassandra): quorum W + R > N.
Sharding : range (scans, hotspots) · hash (even, no ranges) · directory (flexible).
Consistent hashing : ring + virtual nodes → adding a node moves ~1/N keys.
Hot partitions (celebrity user) → key salting, split hot keys.
SD Rate limiting
Token bucket : refill at rate r, burst up to capacity. Most common.
Leaky bucket : smooth constant outflow.
Fixed window (edge bursts) · sliding log (exact, memory-heavy) · sliding counter (approx, cheap).
Distributed: Redis + Lua / atomic INCR. Return 429 + Retry-After.
def allow(now):
tokens = min(cap, tokens + (now - last) * rate); last = now
if tokens >= 1: tokens -= 1; return True
return False
SD Classic designs: the key trick
URL shortener base62(ID) or hash + collision check; 301 vs 302; read-heavy → cache
News feed fan-out on write (push) vs on read (pull); hybrid for celebrities
Chat WebSockets, presence service, per-conversation ordering, offline store
Typeahead trie / prefix index + top-K cache per prefix
Unique IDs Snowflake: time | machine | sequence; UUIDv7 sortable
Notifications queue per channel, retries, user prefs, dedupe
Web crawler URL frontier, politeness, dedupe (Bloom filter)
File storage chunking, content hashing, metadata DB + blob store
SD Consistency & consensus
CAP : during a Partition, choose Consistency or Availability.
PACELC : …Else (normal), Latency vs Consistency.
Models: linearizable > sequential > causal > read-your-writes > eventual .
Consensus : Raft / Paxos (etcd, ZooKeeper) → leader election, replicated log, majority quorum.
Vector clocks detect concurrent updates; CRDTs merge without conflicts (collab editing).
2PC : atomic across nodes but blocking; prefer Sagas across services.
SQL Must-know queries
-- top earner per department (window fn)
SELECT * FROM (
SELECT e.*, ROW_NUMBER() OVER (
PARTITION BY dept_id ORDER BY salary DESC) rn
FROM employees e) t
WHERE rn = 1;
-- depts with > 5 people
SELECT dept_id, COUNT(*) FROM employees
GROUP BY dept_id HAVING COUNT(*) > 5;
WITH recent AS (SELECT ... ) SELECT ... FROM recent;
Logical order: FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.
JOINs: INNER · LEFT · RIGHT · FULL · CROSS · self-join. Anti-join: LEFT JOIN … WHERE b.id IS NULL.
RANK (gaps) vs DENSE_RANK vs ROW_NUMBER; LAG/LEAD for deltas.
DB Indexes & query perf
B-tree (range + equality) · hash (equality) · GIN/inverted (full-text, JSON) · LSM (write-heavy stores).
Composite left-prefix: idx (a,b,c) helps a, a,b, not b alone.
Covering index : answers query from index only.
EXPLAIN red flags: full table scan, filesort / temp table, no key used.
N+1 : query in a loop → batch with IN (...) / JOIN / dataloader.
Indexes speed reads, slow writes and use space. Index for your access patterns.
DB Transactions & isolation
ACID : Atomic · Consistent · Isolated · Durable.
Level Prevents
Read uncommitted nothing
Read committed dirty reads (Postgres default)
Repeatable read + non-repeatable reads (MySQL default)
Serializable + phantoms, write skew
MVCC : readers don't block writers (snapshots).
Optimistic (version column, retry on conflict) vs pessimistic (SELECT … FOR UPDATE).
Deadlock : lock cycle; DB kills a victim. Fix: consistent lock order, short txns, retry.
DB Picking a store
Relational Postgres, MySQL: joins, ACID, the safe default
Document MongoDB: flexible JSON, aggregate-shaped reads
Key-value Redis, DynamoDB: O(1) by key, massive scale
Wide-column Cassandra, Bigtable: write-heavy, time-ordered
Graph Neo4j: relationship traversal
Search Elasticsearch/OpenSearch: inverted index, full-text
Time-series TimescaleDB, InfluxDB: metrics
Vector pgvector, Pinecone, Qdrant, Weaviate: similarity search
Normalize (3NF, no update anomalies) for writes; denormalize for read speed.
DATA Analytics stack
OLTP (many small txns, row store) vs OLAP (big scans, columnar store).
ETL (transform before load) vs ELT (load raw, transform in warehouse with dbt).
Lake (raw files) · Warehouse (structured, SQL) · Lakehouse (Iceberg/Delta on object storage).
Star schema : fact table + dimension tables.
Parquet: columnar, compressed, predicate pushdown.
API Styles compared
REST resources + HTTP verbs, cacheable GETs, simple. Over/under-fetch.
GraphQL typed schema, client picks fields, one endpoint. N+1 resolvers, caching harder.
gRPC Protobuf over HTTP/2, fast, streaming, codegen. Service-to-service.
WebSocket full-duplex persistent connection (chat, games)
SSE server → client stream over HTTP (LLM token streaming!)
Webhook server calls you on events; verify signatures
SOAP XML + WSDL, rigid, legacy enterprise
API REST design rules
Nouns, plural: GET /users/42/orders. Verbs come from HTTP.
Idempotent: GET, PUT, DELETE, HEAD. Not: POST (use an Idempotency-Key header), PATCH (usually).
Safe (no side effects): GET, HEAD, OPTIONS.
Pagination: offset (simple, drifts) vs cursor (stable, scalable).
Versioning: URL /v2 or header; never break clients silently.
Caching: ETag + If-None-Match → 304.
2xx 200 OK · 201 Created · 204 No Content
3xx 301 permanent · 302/307 temporary · 304 not modified
4xx 400 bad · 401 unauthenticated · 403 forbidden · 404 · 409 conflict · 422 invalid · 429 too many
5xx 500 · 502 bad gateway · 503 unavailable · 504 gateway timeout
WEB What happens when you hit Enter
DNS (cache → resolver → root → TLD → authoritative) → IP.
TCP 3-way handshake → TLS handshake (cert, key exchange) → HTTP request.
CDN / LB → server → response → browser parses HTML → CSS/JS → render (DOM + CSSOM → layout → paint).
HTTP/2 : multiplexed streams on one TCP. HTTP/3 : over QUIC (UDP), no head-of-line blocking.
CORS : browser enforces cross-origin rules via preflight OPTIONS.
ALGO Big-O of data structures
Structure Access Search Insert Delete
Array 1 n n (end: 1*) n
Linked list n n 1 (at node) 1
Hash map – 1 avg 1 avg 1 avg
Balanced BST log n log n log n log n
Heap top: 1 n log n log n
Trie – L L L
Sorts: merge O(n log n) stable · quick O(n log n) avg / n² worst · heap O(n log n) · counting/radix O(n+k).
* amortized. Always state time and space.
ALGO Problem → pattern
sorted array / pair sum two pointers, binary search
contiguous subarray/string sliding window
subarray sum = k prefix sum + hash map
top / kth K heap of size K (or quickselect)
all combos / perms backtracking
shortest path, unweighted BFS
weighted, non-negative Dijkstra
dependencies / ordering topological sort
connected groups union-find / DFS
optimal + overlapping subproblems dynamic programming
next greater element monotonic stack
overlapping intervals sort by start, merge
prefix lookups trie
"min max" / "max min" binary search on the answer
ALGO Templates
def lower_bound(a, x): # first i with a[i] >= x
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < x: lo = mid + 1
else: hi = mid
return lo
def longest_unique(s): # sliding window
seen, l, best = {}, 0, 0
for r, ch in enumerate(s):
if seen.get(ch, -1) >= l: l = seen[ch] + 1
seen[ch] = r; best = max(best, r - l + 1)
return best
def bfs(start):
dist, q = {start: 0}, deque([start])
while q:
u = q.popleft()
for v in graph[u]:
if v not in dist: dist[v] = dist[u] + 1; q.append(v)
return dist
ALGO Dynamic programming
Define state → transition → base case → answer location.
Top-down (recursion + memo) is easy to write; bottom-up (table) avoids stack depth and can compress space.
Classics: climbing stairs, coin change, 0/1 knapsack, LIS, LCS, edit distance, house robber, unique paths.
@cache
def coins(n): # min coins for n
if n == 0: return 0
return min((coins(n - c) + 1 for c in C if c <= n), default=inf)
ALGO Graphs
BFS / DFS O(V+E); BFS = shortest in unweighted
Dijkstra non-negative weights, heap: O(E log V)
Bellman-Ford negative weights, detects negative cycles: O(VE)
Floyd-Warshall all pairs: O(V³)
Topo sort Kahn's (in-degree queue) or DFS post-order; cycle = impossible
Union-Find path compression + union by rank ≈ O(α(n))
MST Kruskal (sort edges + UF) / Prim (heap)
A* Dijkstra + heuristic (maps, games)
ALGO Coding round playbook
1 Clarify inputs, sizes, constraints. 2 Walk an example by hand.
3 State brute force + Big-O. 4 Optimize (what's repeated work? sort? hash? heap?).
5 Code cleanly, talk while typing. 6 Dry-run and test.
Edge cases: empty, one element, duplicates, negatives, overflow, already sorted, huge input, unicode.
Say "fine at 1k, fatal at 1M" to show you think about scale.
CONC Concurrency core
Concurrency = dealing with many things (structure). Parallelism = doing many at once (execution).
Process (own memory) · thread (shared memory) · coroutine / green thread (user-space, cheap).
Race condition : result depends on timing. Fix: mutex, atomics, immutability, confinement.
Deadlock needs all 4 (Coffman): mutual exclusion, hold-and-wait, no preemption, circular wait. Break one (lock ordering).
Livelock (busy, no progress) · starvation (never scheduled).
Primitives: mutex · RW lock · semaphore · condition variable · CAS (lock-free) · barriers.
Visibility : without a memory barrier/volatile/atomic, other threads may see stale values.
CONC Models & patterns
Event loop + non-blocking I/O (Node, asyncio, Netty): great for I/O-bound; never block the loop.
Actors (Erlang, Akka, Orleans): private state, communicate by messages.
CSP (Go): processes + channels.
Futures / promises : placeholder for a later value.
Producer-consumer with a bounded queue = built-in backpressure.
Thread pool : bound concurrency; size ≈ cores (CPU) or higher (I/O).
Structured concurrency : child tasks can't outlive parent scope (Kotlin, Java 21+, Trio).
SEC OWASP → defense
Broken access ctrl #1. Check authz server-side on every object (IDOR)
Injection (SQLi) parameterized queries, never string-concat
XSS context-aware output encoding, CSP header
CSRF SameSite cookies, anti-CSRF tokens
SSRF allowlist outbound URLs, block metadata IPs
Insecure deserial. never deserialize untrusted native objects
Crypto failures TLS everywhere, strong algos, no homemade crypto
Misconfiguration no default creds, least privilege, no verbose errors
Vulnerable deps SCA scanning, SBOM, pin + update
SEC AuthN · AuthZ · OAuth
AuthN = who are you. AuthZ = what may you do.
Session cookie (server state, easy revoke) vs JWT (stateless, signed; hard to revoke → short TTL + refresh token).
OAuth 2.0 = delegated authorization. OIDC = identity layer on top (ID token).
Flows: Authorization Code + PKCE (apps, SPAs) · Client Credentials (service-to-service).
RBAC (roles) vs ABAC (attributes/policies) vs ReBAC (relationships, Zanzibar).
MFA , passkeys / WebAuthn (phishing-resistant), SSO via SAML/OIDC.
SEC Crypto & hygiene
Encoding format change, no secrecy (Base64)
Hashing one-way (SHA-256). Passwords: argon2 / bcrypt + salt
Symmetric one shared key, fast (AES-GCM)
Asymmetric public/private (RSA, ECC): key exchange, signatures
HMAC keyed hash → integrity + authenticity (webhooks)
Secrets vault / KMS, never in git, rotate
Zero trust never trust network location; verify every request
Least privilege minimal permissions for users, services, CI tokens
Supply chain SBOM, signed artifacts (Sigstore), lockfiles
TEST Testing essentials
Pyramid: many unit → fewer integration → few E2E. (Trophy: favor integration.)
Contract tests (Pact): consumer/provider agree on API without full E2E.
TDD: red → green → refactor. BDD: Given / When / Then.
Doubles: dummy · stub (canned answers) · fake (working lite impl) · spy (records calls) · mock (verifies expectations).
Property-based (Hypothesis, fast-check): random inputs, assert invariants.
Mutation testing : do your tests catch injected bugs?
Coverage ≠ quality. Flaky tests erode trust: quarantine, fix the timing/order dependency.
AAA : Arrange, Act, Assert. Test behavior, not implementation.
OPS Delivery
CI merge often, build + test every commit
CD delivery (deployable) vs deployment (auto to prod)
Trunk-based short-lived branches + flags over long feature branches
Rolling replace instances gradually
Blue-green two envs, atomic switch, instant rollback
Canary small % of traffic, watch metrics, widen
Feature flag decouple deploy from release
Shadow mirror prod traffic to new version, discard responses
Semver MAJOR (breaking) . MINOR (feature) . PATCH (fix)
Expand/contract backward-compatible DB migrations in steps
SRE Observability
Three pillars: logs (events) · metrics (aggregates) · traces (request path). OpenTelemetry standardizes them.
RED (services): Rate, Errors, Duration. USE (resources): Utilization, Saturation, Errors.
Golden signals: latency, traffic, errors, saturation.
SLI (measure) → SLO (target) → SLA (contract). Error budget = 1 − SLO; spend it on velocity.
Watch p95/p99 , not averages. Alert on user-facing symptoms, not causes.
Structured logs + correlation / trace IDs across services.
RCA Debugging & incidents
1 Reproduce (minimal, deterministic). No repro, no confident fix.
2 What changed? Deploys, config, traffic, dependencies. Roll back first , debug second.
3 Bisect (git bisect, toggle components).
4 Instrument: logs, traces, profiler, slow-query log.
5 Hypothesis → prove it. Correlation ≠ cause.
6 Fix the cause, add a regression test.
7 Blameless postmortem: impact → timeline → root cause (5 whys) → action items.
"It's slow": walk the layers: client → CDN → LB → app → cache → DB → downstream.
ML Fundamentals
Supervised (labeled: classify / regress) · unsupervised (clustering, dim. reduction) · self-supervised (labels from data itself, how LLMs pretrain) · reinforcement (reward).
Train / validation / test split. Tune on validation, report on test once.
Overfitting (memorizes, high variance) vs underfitting (too simple, high bias).
Fixes: more data, regularization (L1 sparse / L2 small weights), dropout, early stopping, simpler model.
Cross-validation (k-fold) for small data.
Data leakage : test info bleeding into training → fake-great metrics.
ML Metrics
Precision TP / (TP+FP): of flagged, how many right? (spam filter)
Recall TP / (TP+FN): of real, how many caught? (cancer screen)
F1 harmonic mean of P and R
Accuracy misleading on imbalanced data (99% "not fraud")
ROC-AUC / PR-AUC threshold-free ranking quality; PR for rare positives
MAE / RMSE regression error; RMSE punishes big misses
Imbalance resample, class weights, pick the right metric
ML Classic algorithms
Linear / logistic reg. baseline, interpretable
Decision tree if/else splits; overfits alone
Random forest bagging many trees → robust
Gradient boosting XGBoost / LightGBM: king of tabular data
SVM max-margin boundary, kernels
k-NN vote of nearest neighbors
k-means clustering into k centroids
PCA linear dimensionality reduction
Naive Bayes fast text classification baseline
DL Deep learning
Neural net = layers of weighted sums + non-linear activations (ReLU, GELU; softmax → probabilities).
Loss (cross-entropy, MSE) → backprop computes gradients → optimizer (SGD, Adam) updates weights.
Learning rate : the most important hyperparameter. Warmup + decay schedules.
Epoch = one pass over data; batch = examples per update.
Architectures: CNN (images) · RNN/LSTM (sequences, legacy) · Transformer (everything now).
Stability: normalization (LayerNorm), residual connections, gradient clipping.
LLM How LLMs work
Tokens : subword pieces (BPE). ~4 chars ≈ 1 token in English. Pricing and limits are per token.
Embeddings : tokens → vectors where meaning ≈ direction.
Self-attention : every token weighs every other token (Q·K → weights over V). Cost O(n²) in length.
Decoder-only Transformer , trained on next-token prediction (pretraining), then post-trained to follow instructions.
Context window : max tokens in + out per call (the model's working memory).
Inference : autoregressive, one token at a time; KV cache avoids recomputing past tokens.
Scaling laws : loss falls predictably with more params, data, compute.
LLM Prompting & sampling
Temperature randomness; 0 ≈ deterministic, higher = creative
Top-p / top-k sample only from the likeliest tokens
System prompt role, rules, format, persistent instructions
Zero / few-shot no examples / a few examples in the prompt
In-context learning learns the task from the prompt, no weight updates
Chain-of-thought reason step by step; reasoning models do it natively (test-time compute)
Structured output JSON schema / tool schemas for reliable parsing
Context engineering curating exactly what goes into the window
Prompt injection untrusted text hijacks instructions; isolate + least-privilege tools
LLM Prompt vs RAG vs fine-tune
Prompting first: cheapest, instant iteration.
RAG when the model needs knowledge (private, fresh, citable).
Fine-tuning when you need behavior/format/style baked in, or a smaller cheaper model.
SFT (supervised fine-tuning on examples) · LoRA / QLoRA (PEFT: train tiny adapter matrices, not all weights).
RLHF : reward model from human preferences → RL. DPO : preference optimization without RL. RLAIF / Constitutional AI : AI feedback guided by principles.
Distillation : big teacher model trains small student.
RAG Retrieval-augmented generation
# ingest
chunks = split(docs, size=500, overlap=50)
store.upsert([(c.id, embed(c.text), c.meta) for c in chunks])
# query
hits = store.search(embed(q), k=20) # ANN: HNSW
hits = rerank(q, hits)[:5] # cross-encoder
answer = llm(f"Answer only from:\n{hits}\n\nQ: {q}")
Similarity: cosine / dot product over embeddings.
Hybrid search = BM25 keywords + vectors → better recall on names/IDs.
Quality levers: chunking strategy, metadata filters, reranking, query rewriting.
Evaluate: retrieval recall@k, answer faithfulness / groundedness , citation accuracy.
GraphRAG: retrieve over a knowledge graph for multi-hop questions.
AGENT Agents & tool use
while not done: # the agent loop
msg = llm(history, tools=TOOLS)
if msg.tool_call:
result = run(msg.tool_call) # sandboxed, permissioned
history += [msg, result]
else: done = True
Tool / function calling : model emits structured calls; your code executes them.
ReAct : reason → act → observe, repeat.
MCP (Model Context Protocol): open standard to plug tools & data into any AI app.
Memory : short-term (context) vs long-term (vector store, files).
Multi-agent : orchestrator + specialized subagents working in parallel.
Guardrails , human-in-the-loop approvals, sandboxing, least-privilege credentials.
Workflow (fixed steps) vs agent (model picks steps). Use the simplest that works.
LLMOps Shipping AI to prod
Evals are the test suite: golden datasets, LLM-as-judge , human review, regression gates in CI.
Latency: TTFT (time to first token) + tokens/sec. Stream responses (SSE).
Cost: input vs output tokens, prompt caching , semantic caching, batch APIs, model routing (small model first, escalate).
Quantization (int8/int4, GGUF) shrinks models for cheaper/local inference.
Hallucination mitigation: grounding/RAG, citations, "say I don't know", validation of outputs.
MLOps: feature store, model registry, data/model drift monitoring, retraining pipelines.
AI-SD Design an AI assistant
Ingestion: connectors → clean → chunk → embed → vector + keyword index; respect ACLs per doc.
Serving: API → auth → LLM gateway (routing, retries, rate limits, keys, cost tracking).
Orchestration: query rewrite → retrieve → rerank → prompt → generate → cite.
Safety: input/output guardrails, PII redaction, prompt-injection defense.
Quality loop: offline evals + online feedback (thumbs, edits) → improve.
Scale: streaming, caching, async jobs for long tasks, fallbacks when a provider is down.
AI Buzzword decoder
GenAI models that generate text, images, audio, code
Foundation model big general pretrained model, adapted to many tasks
Multimodal text + image + audio + video in/out
Diffusion generate by iteratively denoising (images, video)
GAN / VAE older generative models: adversarial / latent-space
MoE mixture of experts: only some params active per token
SLM small language model; on-device, cheap
Open-weights weights downloadable (Llama, Mistral, Qwen, DeepSeek)
Hallucination fluent but false output
Grounding tying answers to trusted sources
Emergent ability skill appearing only at larger scale
Test-time compute spend more inference "thinking" for better answers
Synthetic data model-generated training data
Copilot AI assistant embedded in a workflow
Agentic AI that plans and takes multi-step actions
Vibe coding building by prompting, reviewing little code
AGI hypothetical human-level general intelligence
AI Responsible AI
Alignment : model does what humans intend, safely.
Bias & fairness : skewed data → skewed outcomes; measure across groups.
Explainability : SHAP, LIME, feature importance; needed in regulated domains.
Privacy : PII redaction, data retention, don't train on customer data without consent.
Governance : model cards, audit trails, risk tiers (EU AI Act).
Red teaming : adversarially probe for jailbreaks and harmful output.
SOFT STAR answers
S ituation (1 line) → T ask (your goal) → A ction ("I" , most detail) → R esult (numbers) → L earning.
Prep 6–8 stories that flex: conflict, failure, ambiguity, leadership without authority, tough tradeoff, mentoring, biggest impact, disagreeing with a manager.
Failure story: real mistake, own it, show what changed after.
2 minutes per story. Let them dig in.
SOFT Senior signals
"It depends" → say on what , then pick one and justify.
Name the pattern + where you'd use it + how it fails .
Think in tradeoffs : latency vs consistency, cost vs speed, simple vs flexible.
Mention ops: monitoring, rollback, migration, on-call impact.
Ask them: how do you ship to prod? what does on-call look like? what would make me succeed in 6 months? biggest tech debt?
TERMS Distributed / correctness
Idempotency repeat = same result; key dedupes retries
At-least-once + idempotent consumer ≈ exactly-once
Eventual consist. replicas converge; stale reads expected
ACID / BASE txn guarantees / basically-available soft-state
CAP on partition pick Consistency or Availability
Optimistic / pess. version check vs lock up front
Split brain two leaders after a partition; fencing tokens
Clock skew never trust wall clocks for ordering
Bloom filter "maybe in set" / "definitely not", tiny memory
TERMS Performance
Latency / throughput time per request / requests per time
P95 / P99 tail latency: what users feel; averages lie
Backpressure consumer signals "slow down"
Cache stampede herd of misses on one expired key
Amortized average cost over a sequence of ops
Little's law L = λW (in-flight = rate × time)
Amdahl's law speedup capped by the serial part
Head-of-line one slow item blocks the queue
TERMS Ops & reliability
MTTR / MTBF time to recover / between failures
Circuit breaker stop calling a failing dependency; fail fast
Graceful degradation serve partial results over errors
Retry storm retries amplify outage; backoff + budgets
Toil manual, repetitive ops work: automate it
Runbook step-by-step incident procedure
Blast radius how much breaks when this breaks
Shift left test/secure earlier in the lifecycle
Platform eng. internal developer platform, golden paths
★ The thesis
Every answer: clarify → simplest thing that works → where it breaks → how you'd know → what you'd change .
Concepts are language-agnostic. Syntax is lookup, judgment is the job.
Name it · place it · break it · fix it.
no cards match. Try fewer words, or press Esc
×
What are you interviewing for?
We'll show the cards that matter most at that level. You can switch anytime from the header.
Junior fundamentals, coding round, one language deep
Mid own features: patterns, data, APIs, intro design
Senior system design, distributed tradeoffs, leadership
Architect boundaries, NFRs, evolution, strategy
Skip, show me everything