eBay Software Engineer Interview Prep Guide
Everything eBay actually asks Software Engineer candidates — concept walkthroughs, worked examples, and the real interview questions, drawn from candidate reports. Free to read.
Last updated

Focus most on senior C++ infrastructure/storage preparation: system design is your lowest self-rating at 3/5, and your platform activity also leans heavily toward system design with 11 views versus 7 coding views. You're already strong on general coding and fundamentals at 4/5, so graphs, ranking, SQL, and basic language concepts stay lighter unless they intersect storage-style C++ implementation. The eBay-specific emphasis is marketplace-scale consistency: idempotent APIs, cache/database conflicts, buying-and-selling flows, trust/safety risk, and storage-backed infrastructure design. With one month before recruiter contact, budget roughly 60% of prep for system design/storage, 25% for C++ coding implementation practice, and 15% for senior ownership stories.
Technical Screen — 28 min
System Design
- API Idempotency And Concurrency Control (Focus) — covered in depth under Onsite below.
Software Engineering Fundamentals
-
C++ Systems Programming For Infrastructure (Focus) — covered in depth under Onsite below.
-
C++ Concurrency And Memory Model (Focus) — covered in depth under Onsite below.
-
Linux Networking And Performance Fundamentals (Focus) — covered in depth under Onsite below.
Take-home Project — 3 min
Coding & Algorithms
Your coding rating is strong, but C++ storage roles still reward clean mutable in-memory modeling and complexity tradeoff explanations.
What's being tested
These problems test building and manipulating hierarchical in-memory trees (file-system trees and tries) and reasoning about graph dependencies and cache eviction policies. Expect to show correct state modeling, path traversal, efficient per-operation complexity, and cycle detection/topological ordering.
Patterns & templates
-
Trie node with
`Map<char,Node>`children and boolean`isWord`— insert/search inO(L)time, where L is word length; watch memory vs compression tradeoffs. -
In-memory filesystem: represent directories as nodes with
`Map<string,Node>`children and leaf files storing content; split paths once, then iterate/recursively traverse. -
Copy/append file ops: keep file content as
`StringBuilder`/byte buffer for repeated`addContent`to avoidO(n^2)string copies. -
LRU cache: combine doubly-linked list +
`HashMap<key,node>`forO(1)get/put and eviction; update-on-access to head, evict tail. -
Cycle detection / dependencies: use DFS with 3-color marking or Kahn's algorithm (queue of zero in-degree) — both
O(V+E)time; be explicit about tie-breaking. -
Topological ordering: Kahn gives deterministic order if you use a
`PriorityQueue`for lexicographic stable results. -
Path & permission edge cases: normalize redundant slashes,
`..`, empty segments; decide on absolute vs relative semantics before coding.
Common pitfalls
Pitfall: Using naive string concatenation in repeated file writes leads to quadratic time and TLE on large content. Use buffered appends.
Pitfall: Forgetting to update both map and linked-list pointers in LRU removes can corrupt the structure; always update both atomically.
Pitfall: Running DFS without a visited-color scheme misclassifies back-edges and misses cycles in directed dependency graphs.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions
Onsite — 78 min
System Design
API Idempotency And Concurrency Control
Focus areaFocus area — System design is your 3/5 area, and senior infrastructure interviews often probe retries, races, consistency, and safe state transitions.

What's being tested
Candidates must show practical mastery of idempotency, concurrency control, and state management for HTTP APIs and caches under real-world failure modes. Interviewers look for the ability to specify a clear API contract, pick a consistency model, design deduplication and conflict-resolution mechanisms that scale, and reason about operational concerns (latency, storage, GC, observability). The fitness-for-purpose tradeoffs (optimistic vs pessimistic locking, synchronous vs async dedupe, cache invalidation patterns) are central.
Core knowledge
-
Idempotency definition and contract: an operation is idempotent if applying it multiple times has the same effect as once: . Use an idempotency-key header and reason about an idempotency window (e.g., 24–72 hours) rather than forever.
-
Idempotency-store pattern: persist (
idempotency-key→ request-fingerprint, response, timestamp). On duplicate key return stored response (HTTP 200/409 depending contract). Tradeoff: storage grows with unique keys; enforce TTL/GC. -
Deduplication strategies: strong (store whole response and check synchronously) vs best-effort (de-duplicate downstream via eventual reconciliation). Strong dedupe gives correctness but adds latency and DB writes per request.
-
Optimistic concurrency: use a version/CAS field or
WHERE version = vupdate/upsert pattern to detect and abort concurrent writes. Works well at high throughput and avoids long locks. Example:UPDATE ... SET state=?, version=version+1 WHERE id=? AND version=?. -
Pessimistic locking: use distributed locks (
Zookeeper,etcd,RedisRedLock,Postgresadvisory locks) for critical sections; higher latency and risk of deadlocks but simpler correctness for complex multi-row updates. -
Database isolation: know
serializable,repeatable read,read committedsemantics inPostgresand when to rely on DB transactions vs application-level CAS.serializableprevents anomalies but can increase retries. -
Cache consistency patterns: cache-aside with invalidation on write, write-through, and write-behind. For concurrent writers, prefer invalidation plus a short TTL or version-based checks to avoid stale reads.
-
Conflict resolution choices: last-writer-wins (by timestamp), merge logic, or application-level arbitration. Always design with monotonic version stamps or vector clocks if multi-master is involved.
-
Storage/scale tradeoffs: a simple idempotency table works up to millions of keys per region; beyond that shard by key, compress payloads, or store only hashes and response refs. Enforce TTL: typical window 24–72 hours to bound storage.
-
Latency vs consistency: synchronous dedupe and strong locking increase
p99latency; if sub-100msp99is required, favor optimistic checks and async recovery pipelines for rare conflicts. -
Observability & SLOs: instrument idempotency-hit-rate, conflict-rate (CAS failures), retry counts, mean/95/99 latencies, and GC lag for idempotency-store. Design alarms for rising conflict or dedupe misses.
-
Failure and retry semantics: define API behavior for network failures (client retrying when server returned a 5xx vs timed out). Document whether retrying with same key is expected to be safe; prefer idempotency-key requirement for non-idempotent operations.
Tip: choose a default idempotency window and document it in the API; include key TTL and GC in SLAs so clients know when to regenerate keys.
Worked example — Design an Ad Assignment API
First 30s framing: ask whether assignments are per-user or global, expected QPS and p99 latency targets, acceptable staleness, what constitutes a duplicate (exact same request body or semantic idempotency?), and whether clients can supply an Idempotency-Key. Skeleton answer pillars: (1) API contract — require Idempotency-Key header, return 200 with existing assignment if duplicate; (2) Store design — Postgres assignments table with id, user_id, ad_id, state, version, and an idempotency_keys table mapping key→assignment_id,response,timestamp; (3) Concurrency — use optimistic version updates + DB unique constraints to detect races; (4) Cache & performance — Redis cache-aside for reads, invalidate on write with version stamps; (5) Observability/GC — metrics on dedupe-hit, CAS-failures, and background job to GC idempotency entries after TTL. One tradeoff to flag: synchronous dedupe (check idempotency table before processing) guarantees correctness but adds a DB hit and may increase p99; an alternative is accept occasional duplicate processing and reconcile asynchronously if low-impact. Close by noting next steps: shard idempotency store by client or user, add benchmarks for QPS, and implement chaos tests simulating client retries and partial failures.
A second angle — Handle cache-update conflicts in distributed services
The focus shifts to cache–database consistency: same tools apply (version stamps, CAS, invalidation) but the main constraint is stale reads and high read QPS. Prefer versioned writes: increment a monotonic version in Postgres and propagate (version, payload) to Redis. On cache miss read DB; on write, update DB within a transaction then publish an invalidation message (or write-through to cache). For heavy contention, Redis's WATCH/MULTI provide optimistic atomic updates; for multi-row invariants, use DB transactions and then asynchronous cache invalidation. Another option is write-through with synchronous cache update to avoid invalidation races at the cost of write latency. Instrument stale-hit ratio and tail-latency impact of invalidations.
Common pitfalls
Pitfall: Treating idempotency as a client-only contract. Relying on clients to pick unique keys without server-side storage or checks leads to undetectable duplicates; always persist keys and responses (or hashes) server-side with TTL.
Pitfall: Picking locks by default. Suggesting distributed locks as the first solution ignores latency and availability costs; interviewers prefer optimistic CAS unless multi-row transactional invariants demand pessimistic locking.
Pitfall: Forgetting GC and storage growth. Designing an idempotency store without TTL/compaction leads to unbounded growth; state this up front and propose shard/TTL/compact-hashing or archival strategies.
Connections
Candidates should be ready to pivot to related topics: distributed transactions / sagas for multi-service updates, exactly-once delivery semantics in message systems (Kafka transactions), and observability/chaos testing to validate retry and conflict behavior.
Further reading
-
[Designing Data-Intensive Applications — Martin Kleppmann] — chapters on replication, consistency, and distributed transactions are directly relevant.
-
Stripe Idempotency Best Practices (blog/docs) — a concrete, industry-standard idempotency-key contract and tradeoffs.
Practice questions
Cache Design And Consistency
Focus areaFocus area — This matches both eBay-scale systems and storage-adjacent roles where stale reads, invalidation, and write ordering are common probes.

What's being tested
Candidates must demonstrate practical mastery of cache design and consistency tradeoffs in distributed backends: detecting stale reads, resolving concurrent updates, and choosing invalidation/refresh strategies that meet latency and correctness SLAs. Interviewers probe reasoning about cache–DB coherence, concurrency control (versioning / CAS), and operational patterns (distributed locks, idempotency, cache stampede mitigation) a backend engineer would implement.
Core knowledge
-
Cache-aside vs read-through vs write-through: cache-aside gives explicit app-driven loads/evictions, read/write-through delegates to
`Redis`/`Memcached`; choose based on write amplification and failure modes. -
Write strategies: write-through (synchronous write to cache + DB), write-back (lazy DB flush), write-around (write to DB, skip cache). Each trades latency, durability, and complexity; write-back risks lost writes on cache failure.
-
Consistency models: strong (linearizability) vs eventual; strong requires synchronization (locks/consensus), eventual accepts bounded staleness — quantify SLA (e.g., staleness ≤ 5s).
-
Invalidation patterns: explicit invalidation (publish invalidation events), time-based TTL, and version-based (compare object version or vector clock). Explicit invalidation plus short TTL reduces stale window.
-
Versioning & CAS: store a monotonic version or
`etag`in cache/DB. Use compare-and-swap (CAS) to ensure updates only apply if version matches; supports last-write-wins or application-defined resolution. -
Distributed coordination: use
`etcd`/`ZooKeeper`/`Consul`or`Redis`-based locks for critical sections; prefer optimistic (CAS) over heavy locking for high read throughput; evaluate lock leader election cost and single-point bottlenecks. -
Cache stampede mitigation: techniques include request coalescing, probabilistic early refresh, mutex per-key, and SYNCHRONIZED reads; avoid naive all-clients-refresh bursts on miss.
-
Eviction & admission: combine LRU/LFU eviction with admission filters (e.g., TinyLFU); for large item variance, use segmented caches or size-aware LRU.
-
Topology & routing: consistent hashing for sharded caches to minimize reshuffle; for global user state use local caches + async invalidations or a distributed cache with cross-datacenter replication.
-
Observability & SLOs: measure
`cache hit rate`,`stale-read rate`,`write-success-after-invalidation`, and`p99`latencies for cache vs DB; instrument invalidation lag and version mismatches. -
Quantify staleness: if updates are Poisson with rate λ and TTL = T, stale-read probability ≈ . Use to pick TTL so stale probability ≤ target.
Tip: prefer idempotency keys for write APIs so retries/backfills don't double-apply when cache and DB sequences diverge.
Worked example — Handle cache-update conflicts in distributed services
First 30 seconds: ask which operations are reads vs writes, required consistency (strong vs eventual), QPS and write-rate, failure modes, and existing systems (`Redis`, `Postgres`) and if a pub/sub (e.g., `Kafka`) exists for invalidations. Skeleton answer pillars: (1) pick a consistency goal and SLA, (2) choose an update pattern (cache-aside with explicit invalidation vs write-through), (3) implement concurrency control (versioning + CAS or distributed lock), and (4) mitigate operational problems (stampede, split-brain, monitoring). For many e-commerce flows prefer “write to DB, publish invalidation event, update cache lazily” with a version token in both cache and DB; writers perform a DB write and publish an invalidation, readers check cache version and fall back to DB on mismatch. A concrete tradeoff to flag: using distributed locks (e.g., `Redis` `SETNX`) simplifies races but can add latency and failure surface — favor optimistic CAS when write contention is low. Close by noting tests: simulate partition, measure stale-read window, and say “if more time, add per-key request coalescing and a dead-letter for failed invalidations.”
A second angle — Solve Dependency, Prefix, and Cache Problems
When constraints shift toward algorithmic properties (low-memory prefix lookups or dependency graphs), caching choices change: use compact in-memory structures (e.g., trie for prefix) with TTLs for derived results, and maintain a dependency graph to track which keys must be invalidated when a source changes. For problems with many derived entries, implement reverse dependency edges and publish targeted invalidation messages rather than global flushes. If the working set is too big for single-node `Memcached`, prefer sharded caches with consistent hashing and use small TTLs plus versioned keys to coordinate dependent invalidations efficiently.
Common pitfalls
Pitfall: Choosing TTLs blindly — picking a long TTL reduces DB load but raises stale-read risk; quantify staleness using update rate and target stale probability rather than gut feel.
Pitfall: Relying on naive distributed locks — locks can exacerbate latency and create single-point bottlenecks; if you propose locks, describe lease expiry, clock skew, and failure handling.
Pitfall: Omitting idempotency or version checks — without versioning, concurrent retries or replayed invalidation messages can cause lost updates or cache inconsistency; always design for safe retries.
Connections
Interviewers may pivot to distributed transactions / two-phase commit when strong atomicity is required, or to change-data-capture (CDC) and eventing (`Kafka`) for invalidation propagation. They may also ask about capacity planning for cache clusters, or observability topics like tracing cache miss-to-db paths and `p99` degradation.
Further reading
-
Designing Data-Intensive Applications — Martin Kleppmann — strong chapters on replication, consistency, and caches.
-
Amazon Dynamo paper / All Things Distributed posts — practical tradeoffs for eventual consistency and versioning.
-
Martin Fowler — Two Hard Things (Cache Invalidation & Naming Things) — concise discussion of why invalidation is difficult.
Practice questions
Large-Scale Marketplace System Design
Focus areaFocus area — Even for infrastructure roles, eBay interviewers expect awareness of marketplace flows, consistency boundaries, inventory, and operational scale.

What's being tested
Interviewers probe the candidate's ability to design a reliable, scalable two-sided marketplace backend that balances availability, consistency, security, and operational complexity. They're looking for system decomposition skills (services, data models, APIs), datastore and caching choices for different access patterns, and pragmatic tradeoffs around payments/escrow, media storage, search/ranking, and fraud prevention. Also evaluated: capacity planning, failure modes, and how you instrument and evolve the system.
Core knowledge
-
Entity data model: represent core objects (
User,Listing,Order,Payment,Review) with clear ownership and lifecycle; normalize vs denormalize where read latency matters; expected cardinalities (users U, listings L ~ millions). -
Datastore choices: use
Postgresfor transactional operations and metadata with strong ACID; use wide-column store likeCassandraorDynamoDBfor high-write catalogs and denormalized read patterns at massive scale. -
Search & discovery: index listings in
Elasticsearchfor full-text, faceting, and geo queries; keep the search index eventually consistent and design changefeeds to sync DB → index. -
Media handling: store images/video in
S3(or object store), serve via CDN forp99latency, and use background jobs for thumbnails and content moderation. -
Payments & escrow: isolate payments in a dedicated service; follow idempotency patterns (
idempotency-key), avoid distributed transactions—use local DB transactions plus compensating actions or an escrow state machine for holding funds. -
Consistency models: choose strong consistency for order/payment state transitions; accept eventual consistency for catalog visibility and search to maximize availability and throughput.
-
Scaling & sharding: shard user-related state by
user_id; shard listings by category or geo when L > ~10M; use consistent hashing for stateless services and caches. -
Caching patterns: front-line
Rediscaching for hot listing and user sessions; cache invalidation via pub/sub/event notifications when writes occur. -
Messaging and integration: use
Kafkaor stream platform for durable changefeeds, async workflows, and audit trails; partition by entity key for ordering guarantees. -
Realtime interactions: use
WebSocketor SSE for live bidding/notifications; keep these paths lightweight and stateless (token-based auth). -
Security & compliance: PCI DSS constraints require tokenized card storage through external providers (
Stripe/Adyen); minimize scope of systems that handle raw card data. -
Observability & SLOs: measure
p50/p95/p99latencies, error rates, and business metrics (conversion, gross merchandise volume); design tracing for cross-service transactions.
Worked example — Design an online marketplace for buying and selling
Start by clarifying scope: fixed-price vs auctions, primary/secondary goods, expected scale (daily active users, listings), geographic footprint, and who handles payments/returns. Organize the design around five pillars: (1) data model and persistence for Listings/Orders/Users; (2) API layer and service boundaries (Listing Service, Order Service, Payment Service, Search Service, Media Service); (3) search & discovery with Elasticsearch and changefeed sync; (4) payments & escrow with idempotency, state machine, and external PSP integration; (5) operational concerns (moderation, fraud detection, observability). Explicit tradeoff: using a single ACID DB for everything simplifies correctness but won't scale—prefer Postgres for payments and a denormalized read-store for catalog queries, accepting eventual consistency in search and feeds. When describing order flow, show how you avoid distributed two-phase commit: perform local DB transaction to lock inventory, call PSP to authorize with idempotency, and use compensating actions on failure. Close by saying: if time permits, diagram APIs, show example DB schemas, define SLOs and capacity numbers, sketch event schemas for Kafka, and outline a phased rollout and load-testing plan.
A second angle — auction-style marketplace or high-frequency bidding
If bids and auctions are in scope, real-time constraints dominate. The architecture shifts toward low-latency pub/sub (WS gateways), strong sequencing of bid operations, and optimistic concurrency with fast conflict resolution. You'd place the auction state in a low-latency store (in-memory shard per auction with persistence), use ordered Kafka partitions for bid events, and prioritize consistency for the current highest bid while still making historical events eventually consistent. This requires careful cost analysis: supporting thousands of concurrent auctions needs sticky routing and autoscaling of WS gate nodes, while replayable event logs enable dispute resolution and audit.
Common pitfalls
Pitfall: Designing everything as ACID with distributed transactions — tempting but usually unnecessary; it causes latency, complexity, and operational burden. Instead, use local transactions plus explicit state machines and compensating actions for cross-service workflows.
Pitfall: Ignoring fraud and moderation in the architecture — assuming "we'll add it later" leads to costly refactors. Build pluggable moderation and fraud scoring hooks into listing creation and payment flows from the start.
Pitfall: Overfocusing on micro-optimizations instead of SLOs — naming microservice boundaries without defining SLOs and capacity targets leads to unclear scaling decisions; define
p99latency and throughput goals first.
Connections
Interviewers can pivot to adjacent topics like search relevance and ranking (how to incorporate ML features into ranking pipelines), payments infrastructure (tokenization, chargeback workflows, reconciliation), or data pipelines for analytics and experimentation that rely on the system's changefeed.
Further reading
-
Designing Data-Intensive Applications — Martin Kleppmann — architecture patterns for consistency, streams, and data models that map directly to marketplace challenges.
-
Stripe Engineering Blog — practical guidance on payments, idempotency, and operational patterns for handling money at scale.
Practice questions
Distributed Storage Architecture
Focus areaFocus area — Your Senior Storage Software Engineer target makes partitioning, replication, quorum behavior, failure recovery, and consistency tradeoffs essential.

What's being tested
Interviewers probe your ability to design a reliable, scalable, and maintainable distributed storage architecture for application workloads: choosing partitioning, replication, consistency, durability, and storage engine tradeoffs. They want to see system decomposition, latency/throughput calculations, failure-mode reasoning, and clear operational requirements (SLAs, workload shape). At eBay this maps to building backend services that store catalog, listings, and transaction metadata with predictable p99 latency and data durability guarantees.
Core knowledge
-
Partitioning: range vs consistent hashing; consistent hashing reduces re-sharding pain and hot-spotting; quantify: throughput roughly scales with partition count until per-node CPU or I/O becomes the bottleneck.
-
Replication strategies: synchronous (strong consistency) vs asynchronous (higher throughput, potential data loss); use quorum rules where is replicas, read quorum, write quorum.
-
Consensus algorithms: Raft and Paxos for leader-based strong-consistency; leader commit latency = leader election + majority ack; expect extra RTT per write for durability in leader-sync modes.
-
Storage engines: LSM-tree (
RocksDB/LevelDB) for write-heavy workloads and high write amplification during compaction; B-tree for random-read heavy, lower write amplification. -
Compaction & tombstones: garbage collection cost can spike; tombstones (deletes) require careful GC windows to avoid resurrecting deletes in eventual-consistency setups.
-
Consistency models: strong/linearizable, sequential, causal, and eventual; read-after-write guarantees require leader reads or appropriate quorum choices; state what you’ll provide and how clients should be informed.
-
Data durability and failure modes: durability probability increases with replication factor but costs storage; consider erasure coding for large-object cost-efficiency vs CPU/repair complexity.
-
Rebalancing and data movement: moving a partition costs network I/O; estimate time = partition_size / available_replication_bandwidth and plan throttling to keep
p99latency. -
Metadata scalability: centralized metadata managers (masters) simplify coordination but are single points; masterless (Dynamo-style) scales better but complicates coordination and repairs.
-
Conflict resolution: use vector clocks, last-write-wins, or CRDTs depending on tolerance for lost updates vs complexity of merges.
-
Multi-region design: active-passive reduces cross-region latencies; multi-active requires conflict resolution and either global consensus or per-region leader + cross-region replication.
-
Operational metrics: track
p50/p95/p99latency, write-throughput, compaction stall times, replication lag, and repair backlog to detect hotspots early.
Worked example — "Design a distributed key-value store"
First 30s: ask workload: read/write ratio, object sizes, expected QPS, latency SLOs (e.g., p99 < 50ms), data durability (RPO/RTO), single or multi-region. Skeleton answer pillars: (1) partitioning with consistent hashing and virtual nodes for balancing, (2) replication using Raft per partition for strong consistency (or Dynamo-style quorums if availability prioritized), (3) storage engine choice: LSM-tree for write-heavy or B-tree for read-heavy, (4) rebalancing and metadata via a small metadata service, (5) monitoring/operational concerns (compaction tuning, backpressure). Tradeoff to flag: choosing Raft yields linearizable reads/writes but adds an RTT on writes and a leader bottleneck — acceptable for strict correctness but costly at very high write QPS. Close with: if I had more time I'd detail compaction strategy, per-partition capacity planning, shard split heuristics, and a failure-injection plan to validate p99 SLAs.
A second angle — "Design an object storage system (S3-like) for large blobs"
Frame differences: objects are large (MB–GB), favor multipart upload, and storage economics push toward erasure coding rather than 3× replication. Key design shifts: chunking objects into blocks, storing block metadata separately, implementing multi-part commits to provide resumability, and background repair (reconstruction after drive/node loss). Consistency model can be weaker for object head/list operations (eventual) while PUT/GET semantics are linearizable per object if required. Operationally, optimize for throughput and streaming reads; caching and CDN integration matter more than per-object low-latency metadata reads.
Common pitfalls
Pitfall: Ignoring metadata scale.
Designs that shard only data but centralize metadata (object index, partition map) break at millions of keys; propose scalable metadata (partitioned or hierarchical) and quantify its expected size and lookup latency.
Pitfall: Choosing consensus without workload questions.
Picking Raft by default without knowing read-heavy or geo-replicated needs can cause needless latency; state your consistency-latency tradeoff and justify the chosen protocol.
Pitfall: Underestimating compaction and repair costs.
A tempting answer is “use LSM for writes” without accounting for compaction IO spikes and repair bandwidth during rebalancing; include throttles, backoff, and operational knobs.
Connections
Interviewers may pivot to distributed transactions (two-phase commit, MVCC), caching/CDN strategies for read amplification, or hardware-aware design (NVMe, SSD wear-leveling) to optimize latency and cost. Be prepared to discuss monitoring/SLIs and how design choices affect alerting and SLOs.
Further reading
-
Designing Data-Intensive Applications — Martin Kleppmann — canonical, covers replication, partitioning, consistency tradeoffs.
-
Dynamo: Amazon’s Highly Available Key-value Store — practical masterless design patterns and anti-entropy.
-
Raft Consensus Algorithm — clear, implementable consensus protocol description.
Practice questions
Storage Engine Internals
Focus areaFocus area — Storage roles may go below API design into WALs, compaction, indexes, snapshots, durability, and read/write amplification.
What's being tested
Interviewers are probing your practical understanding of storage-engine building blocks: how data is laid out on disk, how writes survive crashes, how reads stay fast under heavy write load, and the tradeoffs between competing designs. eBay cares because backend services must store and serve huge volumes reliably and with predictable latency; the interviewer wants to see that you can pick appropriate primitives and reason about performance, durability, and operational costs for production systems.
Core knowledge
-
B-tree vs LSM-tree: B-trees excel at random reads and in-place updates (good for OLTP); LSM-trees (log-structured merge trees) optimize for high write throughput via memtable + immutable SSTables and background compaction.
-
Memtable and SSTable: LSM write path: write to memtable (in-memory), append to
WAL, then flush immutable SSTable files; SSTables support merges during compaction and are immutable on disk. -
Write-ahead log (WAL) and fsync semantics: durability requires persisting the WAL; group-commit reduces syscalls. Know the cost: durable commit typically involves an
fsync(~ms latency) unless batched. -
Compaction tradeoffs: compaction reduces read amplification and reclaims space but causes CPU/disk I/O spikes, write amplification (extra bytes written), and needs throttling to avoid latency spikes.
-
Write amplification, read amplification, space amplification: quantify where possible — LSMs may have write amplification >1 depending on compaction strategy; tune levels/size ratios to balance. Lowering write amplification usually increases read cost.
-
Crash recovery patterns: replay WAL, apply checkpoints, reconcile partially flushed files; beware of torn writes — use checksums, file versioning, atomic rename, and directory-level sync ordering.
-
Concurrency control: MVCC enables lock-free reads with multiple versions; alternatives include page latches or fine-grained locks for in-place structures like B-trees. Consider isolation vs latency tradeoffs.
-
Bloom filters: probabilistic filter on SSTables reduces unnecessary disk reads; store one per file/level and size for desired false-positive rate using bits.
-
Caching & page replacement: hot-data caching (page cache vs application cache) matters; implement LRU or CLOCK, and size to avoid eviction storm during compaction or bulk loads.
-
Tombstones & GC: LSMs mark deletes as tombstones and only reclaim space during compaction; heavy delete workloads can increase compaction pressure and read cost.
-
File formats and checksums: each SSTable/segment should include checksums and a footer index for atomic file scans and quick recovery; use versioned filenames and atomic renames to publish files.
-
Tip: measure
p50/p95/p99latencies separately for reads/writes and track write-amplification and compaction I/O as production SLO signals.
Worked example — "Design a storage engine for a key-value store with crash recovery and efficient reads"
First 30 seconds: clarify durability SLOs (sync-on-every-write vs periodic), expected workload (read-heavy vs write-heavy), dataset size vs memory, and expected concurrency. Skeleton answer pillars: (1) persistent write path (in-memory memtable + WAL append), (2) on-disk layout (SSTables with levelled/size-tiered compaction), (3) read path (memtable lookup, Bloom filters, level scanning), and (4) crash recovery and metadata publishing (WAL replay and atomic file moves). A key tradeoff to flag: choose levelled compaction to reduce read amplification at the cost of higher write amplification, or size-tiered for lower write cost but slower reads — justify by workload. Also discuss operational controls: compaction throttling, scheduling, and compaction backpressure to protect tail latencies. Close by saying: "if I had more time I'd add metrics (write-amplification, compaction-lag), implement prioritized compaction for hot keys, and sketch test plans including crash-injection and long-running throughput tests."
A second angle — "Compare B-tree and LSM-tree designs for a mixed OLTP workload with frequent point-read and range scan patterns"
Same primitives apply but constraints shift: with many small point-updates and frequent range scans, B-tree can be preferable due to in-place updates and cheaper range iteration; LSM-tree needs read-merge across levels causing range-scan cost and higher tail latency. Emphasize hybrid mitigations: implement a read-only memtable or level compaction hints, maintain a sparse index in memory for SSTables, or use smaller levels to bound range-scan cost. Discuss concurrency: B-tree benefits from latch coupling and range locks for scans, while LSM benefits from MVCC-style versioning to present consistent snapshots during compaction. Conclude that workload profile (point vs range ratio, write bursts, and latency SLOs) should determine the choice, and propose microbenchmarks to validate.
Common pitfalls
Pitfall: Optimizing only for throughput. Engineers often design for maximum writes/sec (e.g., huge memtable flush size) which amplifies read latency and compaction spikes; instead expose tunables and prioritize SLOs for tail latency.
Pitfall: Ignoring partial-write modes. A tempting but wrong shortcut is trusting file renames without checksums; this fails on torn writes. Always include checksums, atomic file publish (rename after
fsyncdirectory), and WAL replay guarantees.
Pitfall: Over-indexing in memory. Storing full in-memory primary indexes for massive datasets wastes RAM; use sparse indexes, sampled offsets, or a two-tier index (in-memory hash to SSTable id + on-disk block index) to bound memory while keeping lookups efficient.
Connections
Interviewers may pivot to adjacent topics like distributed replication (raft-based WAL shipping and leader/follower semantics), storage-level compaction coordination in multi-tenant clusters, or backup/restore patterns (snapshot + WAL incremental backups). Be ready to discuss how single-node storage choices affect distributed consistency and recovery.
Further reading
- RocksDB design notes /
Facebookpapers — practical LSM implementation and tuning guidance.
Practice questions
Software Engineering Fundamentals
Focus area — You explicitly target eBay roles listing C++, including infrastructure and storage, so implementation fluency should be front and center.

What's being tested
Interviewers are probing practical mastery of writing high-performance, correct C++ system code for infrastructure: safe concurrency, predictable memory behavior, and observability under load. Expect to demonstrate applying the C++ memory model, correct synchronization (`std::atomic`, fences), resource ownership patterns (RAII, `std::unique_ptr`/`std::shared_ptr`), and performance engineering (cache locality, allocation strategies, profiling). They want crisp tradeoffs: simple correct design vs low-latency/high-throughput optimizations and how you'd validate them.
Core knowledge
-
C++ memory model (C++11+): understand sequential consistency,
`memory_order_seq_cst`,`memory_order_acquire`/`release`,`memory_order_relaxed`, and when fences are necessary to enforce happens-before relationships for lock-free algorithms. -
Atomics and lock-free primitives:
`std::atomic<T>`,`compare_exchange_weak`/`strong`, ABA problem, and practical limits: lock-free for pointers/integers is common; complex structures usually need synchronization. -
Mutexes and locking strategies:
`std::mutex`,`std::shared_mutex`, and`std::unique_lock`; know coarse-grain vs fine-grain locking, lock striping, and deadlock-avoidance by lock ordering. -
Ownership & lifetime: RAII, Rule of Five,
`std::unique_ptr`for exclusive ownership,`std::shared_ptr`atomic refcounts cost ~20–40ns per operation; prefer`unique_ptr`+ explicit sharing when throughput matters. -
Undefined behavior (UB) traps: strict aliasing, iterator invalidation, data races (even read/write), use of
`std::launder`/placement new; UB can invalidate reasoning and optimizations. -
Memory/layout & locality: object packing/padding,
`alignas`,`offsetof`; avoid false sharing by padding hot data to cache-line (typically 64 bytes); prefer SoA vs AoS for vectorized access. -
Allocators and fragmentation: general-purpose
`new`/`malloc`may be a bottleneck at high concurrency; use pooled allocators, thread-local arenas, or`jemalloc`for heavy-allocation workloads to reduce contention. -
I/O and syscalls for infra services: use async multiplexing (
`epoll`/`kqueue`), nonblocking sockets, and zero-copy (`sendfile`/`splice`) where appropriate to reduce context switches and copies. -
Profiling, sanitizers, and observability: iterate with
`perf`/`flamegraphs`,`clang-tidy`,`clang-asan`/`ubsan`for UB,`tsan`for data races,`valgrind`for memory errors; add`p99`/`p95`latency metrics and structured tracing. -
Concurrency testing & correctness: deterministic unit tests are insufficient; use stress tests, fuzzers, model checkers, and death tests; log invariants and fail-fast on invariant violations.
-
Performance tradeoffs quantification: always attach numbers — e.g., switching
`std::mutex`to lock-free atomics may reduce latency by X% but increase code complexity and risk; measure before optimizing.
Tip: For low-latency paths, prefer single-producer-single-consumer (SPSC) designs and per-thread buffers to avoid shared contention.
Worked example — "Implement a thread-safe LRU cache in C++"
First 30 seconds: clarify capacity, required concurrency level (single writer vs many readers), eviction policy ties, persistence, and TTLs. Frame success criteria: correctness (no races), throughput (ops/sec), and eviction latency. Skeleton answer pillars: data structures (hash map + doubly-linked list for recency), concurrency model (coarse `std::mutex` vs striped locks vs `std::shared_mutex` for readers), and memory management (store values in `std::unique_ptr` to avoid copies). Explicit tradeoff: a single global `std::mutex` is simplest and safe but serializes access — acceptable for small caches, not for high throughput; lock striping or per-bucket locks increase parallelism but complicate eviction across buckets. Mention implementation details: move semantics for values, careful handling of iterator invalidation when removing nodes, and constant-time eviction via list splicing. Close by saying: if more time, I'd add benchmarks vs real workload, a TTL background reaper, and consider a segmented LRU (multiple independent LRU shards) to reduce contention.
A second angle — "Design a high-throughput logging ring buffer"
This problem stresses the same foundations but with different constraints: single-producer-single-consumer (SPSC) vs multiple producers changes choice of primitives. For SPSC, a circular buffer with two `std::atomic<size_t>` indices works; use `memory_order_relaxed` for head/tail in tight loops and `memory_order_acquire/release` when crossing ownership. Avoid false sharing by padding indices to separate cache lines. If multiple producers are required, use `compare_exchange` on write position or a producer queue per thread to avoid contention. Also cover blocking vs spinning: use `futex`/`condition_variable`/`eventfd` to sleep when empty/full, and measure whether busy-waiting is acceptable for your latency targets.
Common pitfalls
Pitfall: Thinking
`std::shared_ptr`is free — analysts often overuse`std::shared_ptr`without considering atomic refcounting cost; for hot paths replace with`std::unique_ptr`+copy-on-write or manual ref management.
Pitfall: Not asking about failure and memory constraints — ignoring eviction policies, TLS size, or crash-consistency can make an otherwise-correct design unusable in production.
Pitfall: Equating "passes unit tests" with correctness — missed concurrency bugs surface only under stress; always run TSan, long-running stress tests, and real-load profiling.
Connections
Interviewers may pivot to adjacent areas: memory allocators and how allocator design affects fragmentation and throughput, or networking stack choices (`epoll` vs async IO) for services. They might also ask about distributed consistency implications when a local cache is used across nodes.
Further reading
-
C++ Concurrency in Action (Anthony Williams) — authoritative on the C++ memory model and concurrency idioms.
-
Herb Sutter — “Atomic<> Weapons” — blog posts on atomics, memory ordering, and practical C++ concurrency guidance.
Practice questions
C++ Concurrency And Memory Model
Focus areaFocus area — Senior C++ infrastructure interviews often probe threads, mutexes, atomics, lifetimes, memory ordering, and race-free design.

What's being tested
Interviewers probe your practical mastery of the C++ memory model and concurrency primitives: safe coordination between threads, the distinction between atomic and non-atomic accesses, and how memory-ordering choices affect correctness and performance. They want evidence you can reason about data races, pick the right synchronization (locks vs lock-free), and justify tradeoffs (latency, throughput, complexity) for real code. For eBay-scale services this maps to building correct, low-latency thread-safe components (caches, queues, metrics collectors) that won't misbehave under contention.
Core knowledge
-
Data race: simultaneous conflicting accesses (at least one write) to the same scalar object without synchronization cause undefined behavior; prevent with
std::atomicor locks likestd::mutex. -
Happens-before: a directed relation guaranteeing visibility; a release store on one thread and an acquire load on another create a happens-before edge so prior writes become visible.
-
Memory orders:
std::memory_order_seq_cst,acq_rel/acquire/release, andrelaxeddefine visibility and reordering; useacquire/releasefor most producer-consumer andseq_cstonly when global ordering needed. -
Atomic operations:
std::atomic<T>::load/store/exchangeandcompare_exchange_weak/strongare the building blocks for lock-free algorithms;compare_exchange_weakmay spuriously fail and is for loops. -
Atomic fences:
std::atomic_thread_fenceenforces ordering without a particular atomic variable; use for fine-grained ordering when needed. -
Locks vs lock-free: mutex (
std::mutex) provides simplicity and composability; lock-free (using atomics) can give lower latency but adds complexity, ABA issues, and harder memory reclamation. -
ABA problem: in compare-and-swap loops a pointer can be A→B→A and fool CAS; mitigate with versioned pointers (tagged counters), hazard pointers, or epoch-based reclamation.
-
Lock-free/wait-free: lock-free guarantees system progress; wait-free guarantees per-thread progress. Most practical designs aim for lock-free; wait-free is rare and complex.
-
Lazy init idioms: prefer Meyers' singleton (function-local static) for safe lazy init in modern C++; double-checked locking must use correct atomics and
memory_orderto be safe. -
Destruction & lifetime: static/dynamic init order, destruction races, and safe reclamation are common tripwires; prefer explicit shutdown paths or shared ownership (
shared_ptr) when threads may outlive producers. -
Performance tradeoffs:
relaxedcan avoid fences for counters where only per-thread accumulation and occasional aggregation occurs; useacquire/releasefor correctness-critical synchronization. -
Debugging tips: tools like
ThreadSanitizer(TSAN) detect data races; perf counters (p99,throughput) measure contention; TSAN/UBSan are essential pre-commit checks.
Worked example — "Implement a thread-safe lazy singleton using double-checked locking in C++11"
First 30 seconds: clarify whether construction must be lazy, whether exceptions from constructor are allowed, and lifetime guarantees (program exit vs explicit destroy). State assumptions: single-instantiation globally; threads may concurrently request instance. Skeleton answer pillars: (1) prefer Meyers' singleton if allowed (function-local static), (2) if implementing DCL, use std::atomic<Singleton*> for the pointer and a std::mutex for initialization, (3) perform an initial atomic.load with memory_order_acquire, then if null lock the mutex and check again, then atomic.store with memory_order_release. Flag an explicit tradeoff: DCL is more error-prone than function-local statics and can fail if incorrect memory orders are used. Show correctness touchpoint: acquire load pairs with release store to ensure fully-constructed object is visible. Close: mention exception-safety (use std::unique_ptr during construction) and that with more time you'd explain destruction ordering, consider std::shared_ptr for controlled lifetime, or prefer the simple static approach unless lazy init control is mandatory.
A second angle — lock-free stack using atomics and ABA concerns
Frame: now constraints change — no locks allowed, push/pop must be low-latency under contention. Use std::atomic<Node*> head with compare_exchange_weak loops for push/pop. Key differences: memory reclamation becomes the hardest part — freeing a popped node can reintroduce ABA, so mention hazard pointers, epoch-based reclamation, or pointer-tagging as mitigation. Another important angle is ordering: release on push store and acquire on pop load suffice for data visibility; but some platforms may require seq_cst for correctness if relying on global ordering invariants. Explicitly call out tradeoff: lock-free yields better throughput at high concurrency but increases code complexity and maintenance cost.
Common pitfalls
Pitfall: assuming
std::atomic<T>makes composite operations atomic — reads/writes of the atomic itself are atomic, but a sequence of operations (check-then-act) requires explicit synchronization such as CAS or a mutex.
Pitfall: using
relaxedmemory order for correctness-sensitive synchronization —relaxedprovides no ordering guarantees and will cause subtle visibility bugs when used instead ofacquire/release.
Pitfall: using double-checked locking without proper memory orders — a plain load/store can reorder so another thread sees a non-null pointer before the object construction completes, leading to UB; always pair
memory_order_acquireload withmemory_order_releasestore or usestd::call_once/function-local static.
Connections
Interviewers often pivot to adjacent topics: concurrency testing and profiling (ThreadSanitizer, stress tests, contention hotspots), and memory reclamation schemes (hazard pointers, epoch/RCU). They may also connect to higher-level designs like thread pools and async patterns (std::async, std::future) or distributed concurrency concerns (sharding to reduce contention).
Further reading
-
cppreference: atomic — concise reference of
std::atomicAPIs and semantics. -
cppreference: memory_order — summary table of memory orders and guarantees.
-
Herb Sutter — Atomic Weapons — practical explanation of C++ atomic pitfalls and guidance.
Practice questions
Focus area — Infrastructure roles commonly expect practical knowledge of latency, throughput, sockets, I/O, profiling, resource limits, and production debugging.

What's being tested
Interviewers expect you to reason about building low-latency, high-throughput networked services on Linux: knowing how the TCP/IP stack, socket options, and OS scheduling interact with application architecture. They probe measurement-first troubleshooting, tradeoffs between blocking threads and event-driven IO, and concrete tuning steps to reduce tail latency and increase throughput.
Core knowledge
-
TCP vs UDP:
TCPprovides reliable, ordered delivery and congestion control; UDP is connectionless and lower-overhead. Choose UDP for simple idempotent datagrams or when application handles loss and ordering. -
Bandwidth-Delay Product (BDP): BDP = bandwidth * RTT; tune send/receive buffers (
SO_RCVBUF,SO_SNDBUF) and congestion window to keep the pipe full for high throughput. -
MSS and MTU: MSS (max segment size) ≤ MTU - headers; fragmentation increases latency and CPU. Prefer path-MTU discovery and avoid forcing fragmentation.
-
Nagle, delayed ACKs, TCP_NODELAY: Nagle's algorithm batches small writes;
TCP_NODELAYdisables it. For small request/response RPCs, disable Nagle to avoid head-of-line delays; balance with extra packets. -
Connection lifecycle:
SYN,SYN-ACK,ACKhandshake plusTIME_WAITsemantics; many short-lived connections cause ephemeral-port exhaustion andTIME_WAITaccumulation — use connection pooling orSO_REUSEPORT/keepalives. -
Scaling models: thread-per-connection scales poorly past thousands (context switch costs); event-driven (
epoll,kqueue,io_uring) or hybrid thread-pool models handle C10k+ efficiently with fewer syscalls. -
IO system calls and zero-copy: Syscalls and copies cost CPU; use zero-copy primitives (
sendfile,splice,mmap) to reduce user/kernel copies for large transfers and lower CPU per-byte. -
Congestion control and loss: Linux uses loss- or delay-based algorithms (e.g., Cubic). Packet loss or bufferbloat triggers retransmits and
p99spikes. Profile with RTT and loss metrics, not only averages. -
Latency metrics and tail behavior: Track
p50,p95,p99and SLOs separately; the mean hides spikes. Tail often caused by GC, lock contention, scheduling, or network retransmit rather than steady-state throughput limits. -
Profiling and debugging tools: Use
perffor CPU hotspots,stracefor syscall latency,tcpdump/Wiresharkfor packet-level traces,ss/netstatfor socket states, and eBPF-based tools for low-overhead tracing.
Worked example — "Design a high-throughput TCP server for small RPCs"
Frame the problem: ask QPS, average/request size, target p99 latency, TLS requirement, client distribution, hardware (NICs, cores), and whether requests are idempotent. Organize the answer around (1) architecture: event-loop with worker thread-pool, SO_REUSEPORT to scale accept on multiple cores; (2) latency tuning: set TCP_NODELAY, small socket buffers tuned to BDP, and disable Nagle if requests are small; (3) throughput: reuse connections, use sendfile/zero-copy for large responses, and keep per-connection memory pooled to avoid allocations; (4) observability: instrument p50/p95/p99, collect per-core CPU, packet loss, and syscall latency. Explicit tradeoff: an async, epoll-based design minimizes context switches but increases complexity (callback/state machines); a thread-per-connection model is simpler but will saturate CPU and cause p99 tail when scaled. Close by proposing a short benchmarking plan (wrk/netperf), followed by profiling (perf, tcpdump) and iterative tuning of kernel buffers and accept backlog; if time allows, add TLS session resumption or consider hardware TLS offload.
A second angle — "Why is p99 latency high while average latency is low?"
Same fundamentals apply but focus on tail causes and measurement. Start by verifying measurement fidelity: ensure histograms, not just mean. Investigate GC/event-loop pauses, lock contention, CPU steal on noisy neighbors, retransmits and TCP fast retransmit timers, and bufferbloat causing variable RTTs. Collect traces: capture slow requests with stack traces + packet traces to correlate application stalls and network events. Mitigations include isolating cores (NUMA-aware allocation), reducing single-threaded critical sections, applying backpressure/load-shedding, using smaller request batches, and tuning kernel queuing discipline (e.g., fq_codel) to reduce bufferbloat.
Common pitfalls
Pitfall: Optimizing for mean latency instead of tail metrics.
Many candidates tune throughput or average latency; interviewers expect plans forp95/p99and mitigation strategies for rare but high-impact spikes.
Pitfall: Jumping to micro-optimizations without measurement.
Don't change socket options or data structures blindly — first reproduce the problem with benchmarks and trace data (perf,tcpdump), then apply targeted fixes.
Pitfall: Missing system-level constraints (ephemeral ports, accept backlog).
A design that opens/tears down connections for each RPC will hitTIME_WAIT, port exhaustion, or accept-queue drops; propose pooling and kernel parameter adjustments as part of your design.
Connections
Interviewers may pivot to distributed-systems topics like retries/backoff and idempotency, or to observability (tracing, distributed traces) when discussing latency sources. They might also ask about TLS performance implications or how cloud networking (service meshes/load balancers) changes your architecture.
Further reading
-
[TCP/IP Illustrated, Volume 1 — W. Richard Stevens] — canonical deep-dive on TCP mechanics and behavior.
-
[High Performance Browser Networking — Ilya Grigorik] — excellent chapters on BDP, TCP, and how OS/network interact; pragmatic tuning advice.
Practice questions
Behavioral & Leadership
Focus area — At 14 years and senior-level targets, ownership, incidents, tradeoffs, and measurable impact stories need polished, concrete preparation.

What's being tested
Interviewers are probing technical leadership and day-to-day service ownership: your ability to design, operate, and improve a production service end-to-end while influencing cross-functional partners. They want clear evidence you can set and measure reliability (tradeoffs between availability, latency, and cost), run effective incident response, drive pragmatic technical decisions, and communicate impact with metrics. Expect emphasis on concrete examples: architecture choices, incidents you owned, measurable outcomes, and lessons translated into process or code.
Core knowledge
-
Service Ownership: owning code, runtime, and metrics for a bounded service: deploys, rollbacks, runbooks, on-call rotation, and long-term technical debt prioritization relative to business impact.
-
Incident Response: first 15–30 minutes goals (safety, mitigation, customer communication), Triage → Mitigate → Restore → Postmortem; use a runbook for repeatable incidents.
-
Observability: three pillars—logs, metrics, and traces. Instrument high-cardinality metadata sparingly; capture request ids for distributed traces (
`OpenTelemetry`,`Jaeger`). -
SLIs / SLOs / SLAs: define an SLI (e.g., success rate, latency
`p99`), set an SLO (e.g., 99.9%), and understand SLA legal/financial implications. Uptime math: uptime = 1 − downtime/total; 99.9% ≈ 8.76 hours downtime/year. -
MTTR and error budget: MTTR = total downtime / number of incidents; track to show reliability trend. Use an error budget to balance shipping velocity and stability.
-
Release strategies: feature flags, canary releases, and gradual rollout to limit blast radius; prefer roll-forward over rollback when stateful changes are involved.
-
Resilience patterns: idempotency for retries, exponential backoff for client retries, circuit breaker to avoid cascading failures, bulkhead to isolate resources, and rate limiting at ingress.
-
Data/schema migrations: use expand-contract pattern for online schema changes, backfills with idempotent workers, and blue/green or shadow writes to avoid breaking consumers.
-
Scalability tradeoffs: vertical vs horizontal scaling, caching (in-memory, CDN) when read-heavy, sharding/partitioning strategies when writes exceed single-node limits (shard at ~10M rows per shard depending on workload).
-
Measurement & impact: tie technical work to business/technical metrics (reduce
`p99`latency by X ms, increase throughput by Y RPS, reduce MTTR from A to B). Show baseline, change, and confidence intervals if using A/B style experiments. -
Cross-functional influence: how to align product, SRE, QA, and legal for rollouts; document decisions, own tradeoffs, and escalate when boundaries cross teams.
-
Postmortem discipline: blameless postmortem, clear RCA depth (what, why, fix, action owner, timeline), and verification steps to avoid recurrence.
Worked example — "Describe services you built and lessons learned"
In the first 30 seconds clarify scope: "Do you want a single end-to-end service I owned or multiple? Target scale (RPS, data size) and the critical SLOs?" Frame the answer around four pillars: context (purpose, scale, stack), architecture (key components and tradeoffs), reliability/operational practices (SLOs, monitoring, incident examples), and impact + lessons (metrics and what changed). Skeleton: 1) one-line service summary and constraints (e.g., synchronous checkout service, ~2k RPS), 2) architecture choices (sync vs async, DB choice, caching), 3) a concrete incident and how the team responded (MTTR, mitigation), 4) measurable outcomes and one or two lessons (e.g., added canaries and reduced `p99` by X). Call out one tradeoff explicitly — for example, choosing synchronous consistency for simpler ordering at the cost of higher latency, and why that matched business needs. Close with "if more time" items: deeper architecture diagram, sample runbook excerpts, or demo of monitoring dashboards and the rollout plan for a major migration.
A second angle — "Answer senior behavioral questions"
When answering senior behavioral prompts, focus less on low-level code and more on how you influenced outcomes: describe the problem, stakeholders, constraints, decision process, and measurable results. Emphasize leadership moves (mentoring engineers, negotiating with PMs, changing team priorities) and show technical judgment by documenting alternatives considered and why you rejected them. Use the STAR structure but make the Situation and Task succinct; spend most time on the Action (your architectural/operational choices) and Result (quantified improvement, follow-up changes). Highlight tradeoffs you balanced — for example, accelerating delivery vs maintaining an error budget — and show how you institutionalized learning (runbooks, tooling, postmortems).
Common pitfalls
Pitfall: Telling a success story without measurable outcomes. Interviewers need numbers — cite baselines, deltas, and time windows (e.g., reduced MTTR from 3 hours to 30 minutes within two sprints).
Pitfall: Over-emphasizing product or business rationale while skipping technical ownership. As an engineer, focus on the architecture, reliability practices, and how you implemented or enforced them.
Pitfall: Blaming people or vague "we fixed it" statements in incident narratives. Be specific about actions, tradeoffs, and follow-up fixes; demonstrate a blameless postmortem mindset and concrete prevention steps.
Connections
Interviewers may pivot to deeper system design (scaling a service to 10k RPS), Site Reliability Engineering practices (`SLO`/`error budget` enforcement), or CI/CD and test strategy for safe rollouts (`feature flags`, automated canaries). Be ready to show code-level ownership (deploy scripts, health checks) or to walk an architecture diagram end-to-end.
Further reading
-
Site Reliability Engineering (Google) — canonical practices on SLOs, incident response, and postmortems.
-
[Release It! by Michael T. Nygard] — practical resilience patterns (circuit breakers, bulkheads) and real-world failure stories.
Practice questions
Coding & Algorithms
- Hierarchical In-Memory Data Structures — covered in depth under Take-home Project below.