← Uber Interview Insights

Uber·Software Engineer·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
Apr 2026

Summary

Uber system design screen focused on a single problem: a rolling event counter with some surprisingly deep follow-up on cleanup strategies and concurrency. Not a brutal round but the trade-off discussion caught me more off guard than the coding part did.

Questions Asked (4)

Q1

Design an in-memory rolling event counter that supports recording events by timestamp and querying how many events occurred in the last 300 seconds.

System DesignAlgorithms & Data StructuresTechnical Trade-offs
Author's notes

The base implementation wasn't too bad.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Clarify requirements (e.g., timestamp granularity, concurrency, memory constraints) and then propose a data structure that supports efficient insertion and range queries, such as a deque of timestamps or a time-bucketed ring buffer. Discuss trade-offs between precision, memory, and performance, and consider concurrency and cleanup of old events.

Pro tip: Mention that you can use a circular buffer with second-level buckets to achieve O(1) time and fixed memory, but note the trade-off in precision; this shows you think about real-world constraints like high throughput and memory limits.

1. Clarify Requirements

Ask about expected event rate, timestamp precision, concurrency needs, and memory constraints to tailor the solution.

2. Choose Data Structure

Select a structure like a deque of timestamps for exact counting or a ring buffer of time buckets for approximate counting with fixed memory.

3. Design Operations

Define how to record an event (append timestamp, evict old entries) and query the count (remove outdated events, return size).

4. Analyze Trade-offs

Compare time/space complexity, precision, and concurrency handling between approaches, and justify your choice.

5. Handle Edge Cases

Discuss out-of-order timestamps, clock skew, thread safety, and cleanup strategies for stale data.

Key Points to Mention

  • Use a deque (double-ended queue) to store timestamps and remove events older than 300 seconds on each query or insertion.
  • Consider a time-bucketed ring buffer (e.g., 300 buckets of 1 second each) for O(1) operations and fixed memory, with a trade-off in precision.
  • For high concurrency, use locks, lock-free structures, or sharding by time or thread.
  • Amortized O(1) time per operation by evicting old events lazily or on each operation.
  • Memory usage grows with event rate for exact counting; bounded for bucketed approach.
  • Handle out-of-order events by either rejecting them or using a more complex structure like a balanced tree.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

What are the trade-offs between cleaning up expired events lazily (on read) versus running a background thread to periodically purge them?

Technical Trade-offsSystem Design
Author's notes

This is where the conversation got interesting.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the system context (e.g., read/write patterns, latency requirements, scale) and then compare the two approaches across dimensions like latency, resource usage, consistency, and operational complexity. Conclude with a recommendation that balances trade-offs, possibly a hybrid approach.

Pro tip: Mention that the choice often depends on the read-to-write ratio and the cost of stale data; for high-read systems, lazy cleanup can reduce write amplification, but for systems with strict consistency, background purge is safer.

1. Clarify requirements and context

Ask about the system's read/write patterns, latency SLAs, data volume, and consistency requirements to ground the discussion.

2. Analyze lazy cleanup (on read)

Discuss how lazy cleanup works: expired events are filtered out or deleted when read. Highlight pros (no background overhead, simple) and cons (read latency, stale data if not read, potential write amplification on delete).

3. Analyze background purge

Explain periodic background jobs that scan and delete expired events. Cover pros (predictable cleanup, lower read latency) and cons (resource contention, complexity, potential for missed purges if job fails).

4. Compare trade-offs across dimensions

Evaluate both approaches on latency, throughput, resource utilization, consistency, operational complexity, and cost. Use concrete examples or metrics if possible.

5. Recommend a solution

Propose a choice or hybrid approach (e.g., lazy cleanup for hot data, background purge for cold data) and justify it based on the clarified requirements.

Key Points to Mention

  • Read latency impact: lazy cleanup adds overhead to read path, while background purge keeps reads fast.
  • Resource utilization: background purge consumes CPU/IO periodically, lazy cleanup spreads cost but may cause spikes.
  • Consistency and staleness: lazy cleanup may return expired data if not read, background purge ensures timely removal.
  • Operational complexity: background purge requires scheduling, monitoring, and failure handling; lazy cleanup is simpler but may hide issues.
  • Scalability: lazy cleanup scales with read load, background purge scales with data volume and purge frequency.
  • Hybrid approaches: e.g., lazy cleanup with periodic compaction, or time-based partitioning with drop partitions.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

How does stale data affect the correctness of the count, and under what conditions could your implementation return a wrong answer?

System DesignTechnical Trade-offs
Author's notes

Blanked for a second here.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining what 'stale data' means in your system and how it can arise (e.g., replication lag, caching, eventual consistency). Then explain how staleness impacts the correctness of a count operation, focusing on the specific implementation details and the conditions under which the count could be wrong. Conclude by discussing trade-offs and potential mitigations.

Pro tip: Acknowledge that in distributed systems, perfect consistency is often impractical; instead, discuss how to bound staleness and its impact, and how to design the system to tolerate it (e.g., using quorum reads/writes or versioning). This shows you understand real-world trade-offs.

1. Define staleness and its sources

Explain what stale data means in your context (e.g., data that is not the latest due to replication lag, caching, or asynchronous updates) and identify where it can occur in your system.

2. Describe the count implementation

Briefly outline how the count is computed (e.g., scanning a distributed store, using a counter service, or aggregating from multiple sources) and how it interacts with potentially stale data.

3. Analyze impact on correctness

Explain how stale data can lead to an incorrect count: undercounting if updates are missed, overcounting if duplicates are read, or inconsistency if different replicas are read.

4. Identify conditions for wrong answers

List specific scenarios where the implementation could return a wrong answer, such as during network partitions, high write load causing lag, cache invalidation delays, or read from stale replicas.

5. Discuss trade-offs and mitigations

Talk about how to balance consistency and availability, and mention techniques like quorum reads, versioning, or using CRDTs to reduce staleness impact.

Key Points to Mention

  • Replication lag and eventual consistency models
  • Read-your-writes consistency and monotonic reads
  • Impact of caching layers and TTLs
  • Quorum-based reads/writes (e.g., in Dynamo-style systems)
  • Idempotency and deduplication to handle retries
  • Monitoring and alerting on staleness metrics

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How would you handle concurrency if multiple threads are calling record() and count() simultaneously?

System DesignTechnical Trade-offs
Author's notes

Said synchronized blocks first, then walked it back to a ReentrantReadWriteLock since multiple readers should be fine concurrently.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: what consistency guarantees are needed, expected throughput, and whether record() and count() must be linearizable. Then discuss concurrency control mechanisms like locks, atomics, or lock-free data structures, and explain trade-offs between correctness, performance, and scalability.

Pro tip: Mention that you would first try to avoid shared mutable state altogether (e.g., thread-local counters aggregated later) because the fastest lock is no lock. Also, relate your answer to Uber's scale by noting that contention becomes a bottleneck at high throughput, so you'd measure and profile before optimizing.

1. Clarify requirements and constraints

Ask about consistency needs (e.g., is it okay if count() is slightly stale?), expected read/write ratio, and latency/throughput targets. This determines whether you need strong consistency or can use eventual consistency.

2. Identify shared state and race conditions

Explain that record() likely updates a counter or data structure, while count() reads it. Without synchronization, you get lost updates or inconsistent reads.

3. Evaluate concurrency control options

Discuss coarse-grained locks (simple but poor scalability), fine-grained locks (better but complex), atomic variables (e.g., AtomicLong for simple counters), and lock-free structures (e.g., ConcurrentHashMap, LongAdder).

4. Analyze trade-offs

Compare options on correctness, performance, scalability, and complexity. For example, LongAdder reduces contention via striping but count() may not be exact; locks guarantee exactness but hurt throughput.

5. Propose a solution and justify

Recommend a specific approach based on requirements, e.g., use LongAdder for high-throughput counting with approximate reads, or a ReentrantReadWriteLock if exact counts are needed and reads are frequent.

Key Points to Mention

  • Atomicity and visibility issues (e.g., lost updates, stale reads)
  • Lock granularity and contention (coarse vs. fine-grained locking)
  • Java concurrency utilities: AtomicLong, LongAdder, ConcurrentHashMap, StampedLock
  • Lock-free and wait-free algorithms (e.g., CAS loops)
  • Performance implications: throughput, latency, scalability under contention
  • Alternative designs: thread-local accumulation, sharding, or async aggregation

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.