← Box Interview Insights

Box·Software Engineer·Onsite - Coding / Algorithms·Intermediate

Intermediate
May 2026

Summary

Two-hour coding round at Box for a software engineer role. The whole thing was building a leaky bucket rate limiter, first a basic version, then extending it to handle concurrency. You also had to write your own tests, which I wasn't expecting.

Questions Asked (2)

Q1

Implement a leaky bucket rate limiter from scratch, starting with a basic single-threaded version.

Algorithms & Data StructuresSystem Design
Author's notes

They gave a class template to start from, which helped, but the actual logic was all on me.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: what does the leaky bucket control (requests per second), what happens when the bucket is full (reject or queue), and the bucket capacity and leak rate. Then design a simple class with a bucket level and a timestamp, and implement a method that refills the bucket based on elapsed time and checks if a request can be admitted. Finally, discuss how to extend to multi-threading and distributed systems.

Pro tip: Mention that you would use a monotonic clock (e.g., System.nanoTime() in Java) to avoid issues with system clock adjustments, and that you would encapsulate the rate limiter as a thread-safe component even in the single-threaded version to ease future extension.

1. Clarify requirements and constraints

Ask about the expected rate (requests per second), bucket capacity, behavior when the bucket is full (reject, queue, or block), and whether the bucket leaks at a constant rate or only when requests arrive. Confirm if the implementation should be thread-safe or if a single-threaded version is sufficient for now.

2. Design the data model and algorithm

Define a class with fields: current water level (double), last leak timestamp, capacity, and leak rate. The algorithm: on each request, compute elapsed time since last update, subtract leaked amount (elapsed * leak rate) from the water level, clamp to zero, then check if adding the request (1 unit) would exceed capacity. If not, add and allow; else reject.

3. Implement the single-threaded version

Write the code in your chosen language, using a monotonic clock for timestamps. Ensure the leak calculation is correct and that the bucket level never goes negative. Include a method like `allowRequest()` that returns a boolean.

4. Test with edge cases

Walk through scenarios: burst of requests up to capacity, requests after idle period (bucket should be empty), requests at exactly the leak rate, and requests when bucket is full. Verify that the limiter behaves as expected.

5. Discuss extensions and trade-offs

Mention how to make it thread-safe (e.g., using locks or atomic operations), how to handle distributed rate limiting (e.g., using Redis with Lua scripts), and compare leaky bucket with token bucket. Also discuss precision and performance considerations.

Key Points to Mention

  • Leaky bucket vs token bucket: leaky bucket enforces a smooth output rate, while token bucket allows bursts up to capacity.
  • Use of monotonic clock to avoid issues with system time changes.
  • Handling of fractional water levels and leak rate as a double for precision.
  • Thread-safety considerations: even if single-threaded now, design for future concurrency (e.g., synchronized methods or atomic variables).
  • Distributed rate limiting: using a centralized store like Redis with atomic operations to share state across instances.
  • Trade-offs: memory usage, precision, and performance impact of frequent timestamp checks.

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

Q2

Extend your leaky bucket implementation to be thread-safe and support concurrent access.

System DesignTechnical Trade-offs
Author's notes

This is where I started second-guessing myself.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the concurrency requirements and constraints, then discuss synchronization options like mutexes or atomics, and finally explain how to minimize lock contention while maintaining correctness. Emphasize trade-offs between simplicity, performance, and scalability.

Pro tip: Mention that you would first measure the actual contention level before optimizing, as premature optimization can lead to unnecessary complexity. Also, consider using lock-free techniques only if profiling shows the lock is a bottleneck.

1. Clarify requirements and constraints

Ask about expected throughput, number of threads, and whether strict rate limiting is required. This determines the appropriate synchronization strategy.

2. Choose a synchronization primitive

Evaluate options like mutex, atomic operations, or read-write locks based on the access pattern. For a leaky bucket, a mutex is often sufficient, but atomics can be used for simple counters.

3. Implement thread-safe operations

Ensure that all state modifications (e.g., token count, last leak time) are protected. Use lock guards or atomic operations to prevent race conditions.

4. Optimize for performance

Reduce lock contention by using fine-grained locking, lock-free data structures, or sharding if necessary. Consider batching requests or using a dedicated thread for leaking.

5. Test and validate

Write stress tests with multiple threads to verify correctness and measure performance. Use tools like ThreadSanitizer to detect data races.

Key Points to Mention

  • Mutex vs. atomic operations: when to use each
  • Lock contention and its impact on scalability
  • Read-write locks for read-heavy workloads
  • Lock-free algorithms and their complexity
  • Testing for thread safety (e.g., stress tests, sanitizers)
  • Trade-offs between accuracy and performance in rate limiting

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