← Harvey Interview Insights

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

Senior
May 2026

Summary

Got a system design coding question at Harvey for a software engineer role. The problem was building an in-memory spreadsheet engine from scratch, which sounds manageable until you get into propagation and cycle detection.

Questions Asked (2)

Q1

Design and implement an in-memory spreadsheet engine that supports named cells, integer literals, and formulas that sum cell references. get_cell must be O(1) using cached values, and set_cell must propagate updates to all dependent cells.

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

The caching requirement is what trips you up first.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and constraints, then propose a design using a dependency graph and topological order for updates. Explain how caching ensures O(1) reads and how set_cell propagates changes efficiently, discussing trade-offs and edge cases.

Pro tip: Mention that you would use a reverse dependency graph to track which cells depend on a changed cell, enabling efficient propagation. Also, discuss handling cycles and the trade-off between eager and lazy evaluation.

1. Clarify Requirements and Constraints

Ask about expected scale, update frequency, formula complexity, and whether cycles are allowed. Confirm that get_cell must be O(1) and set_cell should propagate updates.

2. Design Data Structures

Propose storing cell values in a hash map for O(1) access. For formulas, maintain a dependency graph (forward and reverse) to track relationships between cells.

3. Implement get_cell and set_cell

get_cell returns cached value from the map. set_cell updates the cell, then propagates changes to dependents using topological order, updating cached values.

4. Handle Edge Cases and Optimizations

Discuss cycle detection, error handling, and potential optimizations like lazy evaluation or batching updates. Consider memory vs. speed trade-offs.

5. Analyze Complexity and Trade-offs

Explain time complexity: get_cell O(1), set_cell O(k) where k is number of affected cells. Discuss trade-offs between eager and lazy propagation, and scalability.

Key Points to Mention

  • Use a hash map for O(1) get_cell access.
  • Maintain a dependency graph (forward and reverse) to track cell relationships.
  • Propagate updates using topological sorting to ensure correct order.
  • Detect and handle cycles to prevent infinite loops.
  • Consider trade-offs between eager and lazy evaluation for updates.
  • Discuss scalability and potential optimizations for large spreadsheets.

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

Q2

How do you detect and handle dependency cycles in the spreadsheet engine, and how do you ensure the engine stays in a valid state if a set_cell call is rejected?

Algorithms & Data StructuresSystem Design
Author's notes

This is the part I fumbled the most.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Explain that you detect cycles using a directed graph of cell dependencies and a DFS-based cycle detection algorithm, and that you reject set_cell calls that would introduce a cycle. Emphasize that you ensure atomicity by validating the entire change before mutating any state, so the engine remains consistent if the call is rejected.

Pro tip: Mention that you perform cycle detection incrementally on the affected subgraph rather than the whole graph for performance, and that you log rejected calls with enough context to debug user errors without compromising engine integrity.

1. Model dependencies as a directed graph

Represent cells as nodes and formula references as directed edges. This allows cycle detection and impact analysis.

2. Detect cycles before committing changes

When set_cell is called, simulate the update and run DFS or topological sort on the affected subgraph to check for cycles.

3. Reject invalid updates atomically

If a cycle is detected, reject the set_cell call without modifying any cell values or dependency edges, ensuring the engine remains in its previous valid state.

4. Maintain consistency and provide feedback

Return a clear error to the caller and optionally log the cycle path. Ensure that no partial updates occur and that the engine's state is unchanged.

5. Optimize for performance and scalability

Use incremental cycle detection on the affected subgraph, and consider caching or memoization to avoid full-graph scans on every update.

Key Points to Mention

  • Directed graph representation of cell dependencies
  • DFS-based cycle detection with recursion stack or topological sort
  • Atomic validation: check before mutate to preserve engine state
  • Incremental cycle detection on affected subgraph for efficiency
  • Error handling and user feedback for rejected set_cell calls
  • Consistency guarantees: no partial updates, engine remains valid

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