← DoorDash Interview Insights

DoorDash·Software Engineer·Technical Phone Screen·Intermediate

Intermediate
Jun 2026

Summary

DoorDash software engineering interview that was pretty heavy on debugging and systems thinking. Three distinct problems back to back, and the cache one at the end felt almost like a relief after wrestling with the hash map.

Questions Asked (3)

Q1

You're given a round-robin node selector that occasionally returns unavailable nodes. Debug and fix it: the index needs to persist across calls in a thread-safe way, status checks shouldn't rely on raw string comparisons, and you need to define what happens when every node is down. Then write a unit test covering the case where one node is unavailable.

Root Cause AnalysisTechnical Trade-offsAlgorithms & Data Structures
Author's notes

This took longer than I'd like to admit.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements and constraints, then walk through the existing code to identify the three issues: index persistence, status check, and all-nodes-down behavior. Propose a thread-safe design using an atomic counter and an enum for node status, define a clear fallback (e.g., throw an exception or return null), and write a unit test that mocks one node as unavailable to verify the selector skips it.

Pro tip: Mention that you would use an AtomicInteger for the index and an enum for node status to avoid string comparisons, and that you would define a custom exception for the all-nodes-down case to make the failure explicit and testable.

1. Clarify requirements and constraints

Ask about thread-safety expectations, how node status is determined, and what should happen when all nodes are down (e.g., throw exception, return null, or block).

2. Identify and fix the index persistence issue

Replace any local or non-persistent index with a thread-safe atomic counter (e.g., AtomicInteger) that increments modulo the number of nodes, ensuring round-robin behavior across calls.

3. Replace string-based status checks with an enum

Introduce an enum (e.g., NodeStatus { AVAILABLE, UNAVAILABLE }) and update the selector to check the enum instead of raw strings, improving type safety and performance.

4. Define all-nodes-down behavior

Decide on a clear contract: throw a custom exception (e.g., NoAvailableNodeException) or return a sentinel value, and document it. Ensure the selector checks all nodes before failing.

5. Write a unit test for one unavailable node

Create a test with a mock node list where one node is UNAVAILABLE, call the selector multiple times, and assert that the unavailable node is never returned and the round-robin order is correct among available nodes.

Key Points to Mention

  • Thread-safety: use AtomicInteger or synchronized block for index persistence.
  • Enum for node status to avoid string comparison pitfalls (typos, case sensitivity).
  • All-nodes-down behavior: throw a custom exception or return null, and document it.
  • Round-robin algorithm: increment index modulo number of nodes, skip unavailable nodes.
  • Unit test: mock nodes with one unavailable, verify selector skips it and cycles through available ones.
  • Edge cases: empty node list, all nodes unavailable, concurrent calls.

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

Q2

You're handed a buggy custom hash map implementation. Diagnose and fix problems related to key hashing versus equality, collision handling, resizing and rehashing behavior, and iterator correctness.

Root Cause AnalysisAlgorithms & Data StructuresTechnical Trade-offs
Author's notes

Genuinely the hardest part of the whole thing.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the hash map's contract and invariants, then systematically test each component (hashing/equality, collisions, resizing, iterators) with targeted cases to isolate bugs. Fix issues in order of dependency, ensuring that changes to hashing or equality don't break collision handling or resizing, and validate with unit tests after each fix.

Pro tip: Emphasize the importance of the equals/hashCode contract and demonstrate how a violation can cause subtle, hard-to-reproduce bugs; mention that you'd write tests first to catch regressions.

1. Understand the contract and invariants

Review the hash map's expected behavior: keys that are equal must have the same hash, collisions must be handled, resizing must preserve mappings, and iterators must be fail-fast or consistent. Identify which invariants are likely violated based on symptoms.

2. Diagnose hashing and equality issues

Check if the key's hashCode and equals methods are consistent and correctly used. Look for bugs like using == instead of equals, not overriding hashCode when equals is overridden, or mutable keys.

3. Examine collision handling

Inspect the collision resolution strategy (e.g., chaining or open addressing). Verify that insertion, lookup, and deletion correctly handle collisions, and that the load factor is maintained.

4. Analyze resizing and rehashing

Check the resize trigger (load factor threshold) and the rehashing process. Ensure all entries are rehashed into the new table without losing or duplicating entries, and that the new capacity is appropriate.

5. Validate iterator correctness

Test iterators for expected behavior: they should traverse all elements, reflect concurrent modifications appropriately (e.g., throw ConcurrentModificationException), and not skip or repeat elements.

Key Points to Mention

  • The equals/hashCode contract: equal objects must have equal hash codes, and hashCode must be consistent with equals.
  • Collision resolution techniques (separate chaining vs. open addressing) and their impact on performance and correctness.
  • Load factor and resizing: when to resize, how to rehash, and ensuring all entries are transferred correctly.
  • Iterator fail-fast behavior and how to detect concurrent modification (e.g., modCount).
  • Common pitfalls: using mutable keys, not handling null keys, incorrect bucket index calculation (e.g., using modulo with negative hash).
  • Testing strategies: unit tests for each component, edge cases (empty map, single element, many collisions), and performance considerations.

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

Q3

Implement a simple in-memory cache backed by a map, supporting get and set operations with optional TTL or size-based eviction. Write basic tests for it.

System DesignAlgorithms & Data Structures
Author's notes

After the hash map question this felt manageable.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements: which eviction policy (TTL, LRU, or both), concurrency needs, and expected operations. Then design a class with a map for storage, a doubly-linked list for LRU order, and a min-heap or timing wheel for TTL. Implement get/set with O(1) average time, and write unit tests covering basic operations, eviction, and edge cases.

Pro tip: Mention that you'd use a doubly-linked list for O(1) LRU updates and a min-heap for TTL, but note that a timing wheel is more efficient for many timers. Also, discuss thread-safety with a mutex or sharded locks, and how you'd test concurrency.

1. Clarify Requirements

Ask about eviction policies (TTL, LRU, LFU), maximum size, concurrency, and whether persistence is needed. Confirm expected operations and performance goals.

2. Design Data Structures

Choose a map for key-value storage. For LRU, combine with a doubly-linked list; for TTL, use a min-heap or timing wheel. Explain how to achieve O(1) get/set.

3. Implement Core Operations

Write get and set methods, handling eviction when size exceeds limit or TTL expires. Ensure thread-safety if required, using locks or concurrent structures.

4. Write Tests

Create unit tests for basic get/set, eviction under size limit, TTL expiration, and edge cases like updating existing keys and concurrent access.

5. Discuss Trade-offs and Extensions

Talk about time/space complexity, alternative eviction policies, and how to scale (e.g., sharding, distributed cache). Mention monitoring and metrics.

Key Points to Mention

  • O(1) average time complexity for get and set using hash map and doubly-linked list.
  • TTL implementation with lazy deletion or active expiration using a min-heap or timing wheel.
  • Thread-safety considerations: mutex, read-write lock, or concurrent hash map with striped locks.
  • Eviction policies: LRU, LFU, or FIFO, and how to combine with TTL.
  • Testing strategies: unit tests for correctness, edge cases, and concurrency stress tests.
  • Trade-offs between memory usage and eviction accuracy, and potential for memory leaks if TTL not cleaned.

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