← DoorDash Interview Insights

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

Senior
Jul 2026

Summary

DoorDash system design round focused entirely on building an in-memory path registry, kind of like a mini filesystem. The problem started simple but the follow-ups kept stacking and by the end I was juggling subtree deletion rules and watch callbacks at the same time.

Questions Asked (4)

Q1

Design an in-memory hierarchical path registry that supports creating a path with an integer value and retrieving a value by path (returning -1 if the path doesn't exist). The root '/' exists implicitly, a path can only be created if its parent exists, and re-creating an existing path should fail.

System DesignAlgorithms & Data StructuresAPI & Integrations
Author's notes

I went straight to a trie-backed structure with a hashmap at each node for children.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and edge cases, then propose a trie-like tree structure where each node represents a path segment and stores an optional value. Discuss operations (create, get) with time and space complexity, and handle error cases such as missing parent or duplicate path.

Pro tip: Mention that you would use a sentinel value (e.g., null or a boolean flag) to distinguish between a path that exists with value -1 and a non-existent path, since -1 is a valid value. This shows attention to detail and avoids ambiguity.

1. Clarify Requirements and Edge Cases

Ask questions to confirm: path format (e.g., '/a/b'), whether values can be negative, what happens if parent doesn't exist, and if paths are case-sensitive. Confirm that root '/' is implicit and cannot be created.

2. Design Data Structure

Propose a tree where each node has a map of child name to node, and an optional value. Explain that this trie-like structure allows efficient lookup and insertion by splitting the path into segments.

3. Define Operations and Error Handling

Describe create(path, value): traverse from root, ensure parent exists, then add child node with value; return false if path already exists or parent missing. Describe get(path): traverse and return value if exists, else -1.

4. Analyze Complexity and Optimizations

State that both operations take O(k) time where k is number of path segments, and O(total nodes) space. Mention potential optimizations like path compression or caching frequently accessed paths.

5. Discuss Extensions and Trade-offs

Consider follow-ups: concurrency (thread-safety), persistence, or supporting deletion. Discuss trade-offs between using a tree vs. a hash map with full path strings (simpler but less efficient for hierarchical operations).

Key Points to Mention

  • Use a trie (prefix tree) to represent hierarchical paths, with each node storing a map of children and an optional value.
  • Handle edge cases: creating root, missing parent, duplicate path, and path with trailing slash.
  • Distinguish between non-existent path and path with value -1 by using a separate existence flag or sentinel.
  • Time complexity: O(k) for both create and get, where k is the number of segments in the path.
  • Space complexity: O(n) where n is total number of nodes created.
  • Consider concurrency and thread-safety if the registry will be accessed by multiple threads.

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

Q2

How would you extend the design to support update and delete operations, including rules around subtree deletion?

System DesignTechnical Trade-offsAlgorithms & Data Structures
Author's notes

Update was easy to tack on.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the current design and the data model (e.g., tree structure, parent-child references, indexes). Then propose update and delete operations with clear semantics, focusing on subtree deletion rules (cascade vs. orphan prevention) and consistency mechanisms (transactions, soft deletes, async cleanup). Finally, discuss trade-offs around performance, concurrency, and data integrity.

Pro tip: Demonstrate awareness of real-world constraints: propose soft deletes with a background hard-delete job to avoid long locks, and mention how you'd handle concurrent updates using optimistic locking or versioning. This shows you think beyond the happy path.

1. Clarify requirements and current design

Ask about the existing data model (e.g., adjacency list, nested sets, materialized paths) and expected update/delete patterns (frequency, scale, consistency needs). Confirm whether subtree deletion should be cascading or restricted.

2. Define update semantics and implementation

Specify what fields can be updated (e.g., node value, parent change) and how to handle moves (reparenting) without breaking tree integrity. Propose using transactions and locking (e.g., SELECT FOR UPDATE) or optimistic concurrency control.

3. Design delete operations with subtree rules

For subtree deletion, choose between cascade (delete all descendants) or restrict (prevent if children exist). Implement cascade via recursive CTE or application-level traversal, and consider soft delete (mark as deleted) to avoid immediate data loss.

4. Address consistency, concurrency, and performance

Ensure atomicity with transactions, handle concurrent updates/deletes via locking or versioning, and optimize for performance (e.g., batch deletes, background jobs for hard deletes, indexing on parent_id).

5. Discuss trade-offs and alternatives

Compare hard vs. soft delete, synchronous vs. asynchronous cleanup, and different tree models (e.g., adjacency list vs. closure table) for update/delete efficiency. Mention monitoring and rollback strategies.

Key Points to Mention

  • Cascade vs. restrict deletion rules and how to enforce them (e.g., foreign key constraints, application logic).
  • Soft delete pattern: adding an 'is_deleted' flag and filtering queries, with periodic hard deletion.
  • Concurrency control: optimistic locking (version column) or pessimistic locking (SELECT FOR UPDATE) to prevent lost updates.
  • Performance considerations: recursive queries (CTEs), batch processing, and indexing on parent_id for efficient subtree operations.
  • Transaction boundaries: ensuring atomicity for multi-row updates/deletes, and handling partial failures.
  • Reparenting a node: updating parent references and potentially updating materialized paths or closure tables.

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

Q3

How would you add wildcard query support to the path registry, so a query like '/a/*/c' can match multiple paths?

Algorithms & Data StructuresSystem Design
Author's notes

Blanked for a second here.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: what wildcard semantics are needed (e.g., '*' matches exactly one segment or any number of segments), and whether the registry is static or dynamic. Then propose a solution that balances lookup efficiency and update cost, such as a trie with wildcard branches or a regex-based approach, and discuss trade-offs.

Pro tip: Mention that wildcard matching can explode combinatorially; suggest limiting wildcards to a single segment or using a trie with a dedicated wildcard child to keep lookups efficient. Also, consider precompiling patterns or caching results for repeated queries.

1. Clarify requirements and constraints

Ask whether '*' matches exactly one path segment or any number of segments, and whether the registry is read-heavy or write-heavy. This determines the appropriate data structure and algorithm.

2. Choose a data structure

Propose a trie (prefix tree) where each node represents a path segment, and wildcard '*' is treated as a special child. Alternatively, consider a regex-based approach if patterns are complex.

3. Design insertion and lookup algorithms

For insertion, add the path segments to the trie, creating a wildcard branch when '*' is encountered. For lookup, traverse the trie, branching into both exact and wildcard children when a wildcard is present.

4. Analyze complexity and trade-offs

Discuss time complexity: O(k) for exact match, but wildcard matching may explore multiple branches, potentially exponential in worst case. Suggest optimizations like memoization or limiting wildcards.

5. Consider extensions and edge cases

Address multiple wildcards, overlapping patterns, and dynamic updates. Mention that if patterns are known in advance, a compiled regex or automaton could be more efficient.

Key Points to Mention

  • Trie data structure with wildcard support
  • Wildcard semantics: single-segment vs multi-segment matching
  • Time complexity and potential combinatorial explosion
  • Optimizations: memoization, caching, or limiting wildcards
  • Alternative approaches: regex, glob patterns, or finite automata
  • Handling dynamic updates and concurrency if registry is mutable

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

Q4

How would you implement watch callbacks that fire when a specific path or any path within a subtree changes?

System DesignTechnical Trade-offsAPI & Integrations
Author's notes

This one was genuinely fun to think through.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: what kind of data store (e.g., hierarchical config, file system, in-memory tree) and what consistency guarantees are needed. Then propose a design that supports both exact-path watches and subtree watches, using a trie or prefix tree to efficiently match paths and notify callbacks. Finally, discuss trade-offs around performance, scalability, and consistency.

Pro tip: Mention that you would use a trie to store watchers, where each node represents a path segment, and callbacks are stored at nodes. For subtree watches, you can store a flag at the node and traverse descendants to notify. This shows you understand efficient data structures for path-based operations.

1. Clarify Requirements

Ask about the data model (e.g., hierarchical key-value store), expected scale, and consistency requirements (e.g., immediate vs. eventual).

2. Design Data Structures

Propose a trie (prefix tree) to map paths to watchers. Each node stores callbacks for exact path watches and a flag/list for subtree watches.

3. Implement Watch Registration

For exact path, insert callback at the corresponding node. For subtree, mark the node as a subtree watch root and store callback there.

4. Implement Change Notification

On a change at path P, traverse from root to P, collecting exact watchers at P and subtree watchers at ancestors. Also, if P is a subtree watch root, notify its descendants.

5. Discuss Trade-offs and Optimizations

Address performance (e.g., O(k) where k is path depth), memory, and potential optimizations like caching or batching notifications.

Key Points to Mention

  • Use of a trie (prefix tree) for efficient path matching
  • Distinction between exact path watches and subtree watches
  • Notification propagation: ancestors for subtree watches, descendants for subtree root changes
  • Handling concurrent modifications and thread safety
  • Scalability considerations: number of watchers, depth of tree, frequency of changes
  • Trade-offs between immediate vs. batched notifications and consistency guarantees

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