← Ramp Interview Insights

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

Senior
Jun 2026

Summary

System design round at Ramp for a software engineer role. The main problem was building a spreadsheet cell system with formula dependencies, which sounds manageable until you actually start thinking through the update propagation and cycle detection pieces.

Questions Asked (5)

Q1

Design a spreadsheet system where cells can hold literal values or formulas referencing other cells. How do you represent dependencies, handle updates when a cell changes, and detect or reject cycles?

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

My first instinct was to just store a map of cell name to value and call it a day.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and scale, then model cells as nodes in a directed graph where edges represent dependencies. Explain how to store formulas, evaluate them with topological ordering, and handle updates via incremental recomputation while detecting cycles using DFS or Kahn's algorithm.

Pro tip: Mention that cycle detection can be integrated into the dependency graph construction, and that incremental updates should only recompute affected cells, not the entire sheet, to maintain performance at scale.

1. Clarify Requirements and Scale

Ask about expected sheet size, update frequency, and whether real-time collaboration is needed. This informs choices like in-memory vs. persistent storage and incremental vs. full recomputation.

2. Design Data Structures

Represent each cell with its raw content (literal or formula) and a parsed dependency list. Use a graph (adjacency list) to track dependencies and reverse dependencies for efficient updates.

3. Handle Evaluation and Updates

Evaluate cells using topological sorting to ensure dependencies are computed first. On change, mark affected cells dirty and recompute only those in topological order.

4. Detect and Reject Cycles

During dependency graph construction or evaluation, use DFS with recursion stack or Kahn's algorithm to detect cycles. Reject the update that introduces a cycle and notify the user.

5. Discuss Trade-offs and Optimizations

Compare eager vs. lazy evaluation, incremental vs. full recomputation, and memory vs. speed trade-offs. Mention optimizations like memoization and batching updates.

Key Points to Mention

  • Directed graph representation with adjacency lists for dependencies and reverse dependencies
  • Topological sorting for evaluation order and cycle detection (DFS or Kahn's algorithm)
  • Incremental recomputation: only recompute cells affected by a change
  • Cycle detection strategies: DFS with recursion stack, Kahn's algorithm, or union-find for undirected (but not suitable here)
  • Handling of formula parsing and evaluation (e.g., using an expression parser or AST)
  • Trade-offs: eager vs. lazy evaluation, memory overhead of storing dependencies, and scalability considerations

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 cell ranges like A1 through A10 in formulas?

System DesignTechnical Trade-offs
Author's notes

Didn't have a clean answer ready.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the current design and how formulas are represented, then propose extending the parser to recognize range syntax and the evaluator to handle ranges as collections. Discuss trade-offs between eager evaluation (expanding ranges into individual cells) and lazy evaluation (iterating over ranges on demand), and how to handle dependencies and updates.

Pro tip: Emphasize that ranges should be treated as first-class objects in the formula engine, enabling optimizations like vectorized operations and efficient dependency tracking, which is crucial for performance in a spreadsheet-like system.

1. Clarify requirements and current design

Ask questions to understand the existing formula parsing and evaluation architecture, and confirm that ranges are not currently supported. Identify how cell references and formulas are represented.

2. Extend the parser and AST

Modify the grammar to recognize range syntax (e.g., A1:A10) and introduce a Range node in the abstract syntax tree. Ensure the parser can handle ranges in various contexts (e.g., function arguments, arithmetic).

3. Design range representation and evaluation

Decide on a data structure to represent a range (e.g., start and end cell coordinates) and how to evaluate it. Consider whether to expand ranges into lists of cells or keep them as lazy iterators for efficiency.

4. Handle dependencies and updates

Update the dependency graph to track ranges as dependencies. When a cell within a range changes, ensure dependent formulas are recalculated. Discuss strategies for efficient invalidation and recalculation.

5. Discuss trade-offs and optimizations

Compare eager vs. lazy evaluation, memory usage, and performance. Mention potential optimizations like vectorized operations, caching, and handling large ranges without blowing up memory.

Key Points to Mention

  • Parser changes: adding grammar rules for range syntax and AST node for ranges.
  • Range representation: using start/end coordinates or a rectangular region, and whether to materialize cells.
  • Evaluation strategies: eager expansion vs. lazy iteration, and implications for memory and performance.
  • Dependency tracking: how ranges affect the dependency graph and recalculation logic.
  • Error handling: invalid ranges, out-of-bounds, and circular dependencies involving ranges.
  • Optimizations: vectorized operations, caching, and incremental updates for large ranges.

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

Q3

How would you make recalculation incremental rather than recomputing everything on each change?

System DesignAlgorithms & Data Structures
Author's notes

This is where I felt most out of my depth.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the context: what kind of recalculation is this (e.g., spreadsheet, data pipeline, UI rendering)? Then propose a dependency graph to track which computations depend on which inputs, so only affected nodes are recomputed. Finally, discuss implementation details like topological ordering, dirty marking, and incremental algorithms (e.g., dynamic programming, memoization).

Pro tip: Mention that incremental recomputation isn't just about performance—it also reduces the risk of inconsistent state and enables real-time updates. Also, be prepared to discuss trade-offs like memory overhead for dependency tracking and complexity of invalidation logic.

1. Clarify the problem and constraints

Ask questions to understand the system: what is being recalculated, how often changes occur, what are the latency and consistency requirements? This ensures your solution fits the context.

2. Model dependencies as a graph

Represent computations as nodes and dependencies as edges. This allows you to identify which parts of the computation are affected by a change.

3. Implement change propagation

When an input changes, mark dependent nodes as dirty and recompute only those in topological order. Use techniques like memoization or dynamic programming to avoid redundant work.

4. Optimize and handle edge cases

Consider batching updates, cycle detection, and incremental algorithms for specific operations (e.g., incremental view maintenance). Discuss how to handle deletions or structural changes.

5. Evaluate trade-offs and alternatives

Compare with full recomputation: when is incremental worth the complexity? Mention memory overhead, invalidation cost, and potential for bugs. Suggest monitoring and fallback strategies.

Key Points to Mention

  • Dependency graph and topological sorting
  • Dirty marking and invalidation propagation
  • Memoization and caching of intermediate results
  • Incremental algorithms (e.g., for aggregations, joins, or UI diffing)
  • Trade-offs: memory vs. speed, complexity vs. maintainability
  • Real-world examples: React's virtual DOM diffing, spreadsheet engines, incremental view maintenance in databases

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

Q4

How would you safely cache computed cell values, and when would you invalidate the cache?

System DesignTechnical Trade-offs
Author's notes

Tied this back to the dirty-flag idea.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the context—what kind of cells (e.g., spreadsheet formulas, database computed columns) and the scale/performance requirements. Then describe a caching strategy that includes cache key design, storage, and invalidation triggers, emphasizing correctness and safety. Finally, discuss trade-offs between different invalidation approaches and how you would handle edge cases like circular dependencies.

Pro tip: Demonstrate awareness of the 'cache invalidation is hard' problem by proposing a versioned or dependency-based invalidation system, and mention how you would monitor cache hit rates and staleness to detect issues in production.

1. Clarify requirements and context

Ask questions to understand the system: what are cells, how are they computed, what are the consistency and latency requirements, and what is the scale? This shows you avoid premature optimization.

2. Design the cache

Propose a cache key (e.g., cell ID + version or hash of dependencies), a storage mechanism (in-memory, Redis, etc.), and a strategy for populating the cache (lazy vs. eager).

3. Define invalidation triggers

Explain when to invalidate: when dependencies change, on a schedule, or via explicit invalidation. Discuss trade-offs between eager and lazy invalidation.

4. Ensure safety and correctness

Address concurrency (e.g., locking or atomic operations), fallback to recomputation on cache miss, and handling of stale data. Mention versioning or timestamps to avoid race conditions.

5. Discuss trade-offs and monitoring

Compare invalidation strategies (TTL vs. event-driven), and explain how you would monitor cache effectiveness and correctness (e.g., hit rate, staleness metrics).

Key Points to Mention

  • Cache key design: include cell identifier and a version or hash of dependencies to ensure uniqueness.
  • Invalidation strategies: time-based (TTL), event-based (on dependency change), or manual invalidation.
  • Dependency tracking: maintain a graph of cell dependencies to know what to invalidate when a cell changes.
  • Concurrency control: use locks or atomic operations to prevent race conditions during cache updates.
  • Fallback mechanism: on cache miss or invalidation, recompute the value and repopulate the cache.
  • Monitoring: track cache hit/miss ratios and staleness to detect performance or correctness issues.

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

Q5

How does your design change if multiple users can edit cells concurrently?

System DesignTechnical Trade-offs
Author's notes

Last follow-up and probably the one I handled worst.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the current single-user design and the requirements for concurrent editing (e.g., real-time collaboration, conflict resolution, consistency). Then propose a shift to a distributed architecture with conflict-free replicated data types (CRDTs) or operational transformation (OT), and discuss trade-offs like latency, complexity, and offline support.

Pro tip: Mention that you would first consider the business context—Ramp's financial data requires strong consistency and auditability, so you might lean towards a server-authoritative model with OT rather than peer-to-peer CRDTs, and highlight how you'd handle conflicts with a clear merge strategy.

1. Clarify requirements and constraints

Ask about the expected number of concurrent users, latency tolerance, offline support, and consistency requirements (e.g., strong vs eventual). This ensures the design aligns with business needs.

2. Identify the core challenge

Explain that concurrent edits introduce conflicts (e.g., two users editing the same cell) and require a mechanism to merge changes while preserving user intent and data integrity.

3. Choose a concurrency control strategy

Compare approaches like locking (pessimistic), optimistic concurrency with versioning, operational transformation (OT), and conflict-free replicated data types (CRDTs). Discuss their trade-offs in terms of latency, complexity, and consistency.

4. Design the system architecture

Outline components: a real-time communication layer (WebSockets), a central server or peer-to-peer sync, a conflict resolution engine, and a data store that supports versioning or CRDTs. Consider scalability and fault tolerance.

5. Address edge cases and trade-offs

Discuss handling offline edits, network partitions, undo/redo, and audit trails. Highlight how the chosen approach affects user experience and system complexity.

Key Points to Mention

  • Conflict resolution techniques: OT vs CRDTs, with pros and cons (e.g., OT requires central server, CRDTs are decentralized but can have metadata overhead).
  • Consistency models: strong consistency vs eventual consistency, and how they impact user experience and system design.
  • Real-time communication: WebSockets, server-sent events, or polling for propagating changes.
  • Data versioning and optimistic concurrency: using version numbers or timestamps to detect and resolve conflicts.
  • Scalability considerations: sharding, load balancing, and handling a large number of concurrent users.
  • Auditability and compliance: ensuring all changes are logged and traceable, which is crucial for financial applications like Ramp.

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