← Waymo Interview Insights

Waymo·Frontend Engineer·Technical Phone Screen·Senior

SeniorPrefer not to say
Jul 2026Remote

Summary

Waymo frontend round where they handed me a single React problem and just... let me sit with it. The prompt was deliberately vague and the whole thing felt more like a design conversation than a coding test.

Questions Asked (6)

Q1

Build a simplified single-player Battleship board in React with click-to-cycle cell states and a status panel that tracks which ships are sunk.

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

The thing that tripped me up first was state modeling.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and constraints, then outline a component architecture with a clear data model for the board and ships. Focus on state management, efficient updates, and deriving sunk status, while discussing trade-offs and edge cases.

Pro tip: Demonstrate production thinking by discussing memoization to prevent unnecessary re-renders of the grid and using a normalized state structure for O(1) ship lookups.

1. Clarify Requirements

Ask about board size, ship configurations, cell state cycle order, and whether the status panel should update in real-time. Confirm if any persistence or reset functionality is needed.

2. Design Data Model

Define a 2D array for cell states (e.g., empty, ship, hit, miss) and a separate structure for ships with their coordinates and sunk status. Consider using a Map for ship lookup by cell.

3. Plan Component Architecture

Break down into Board, Cell, and StatusPanel components. Decide where state lives (likely in a parent Board component) and how to pass down handlers efficiently.

4. Implement State Updates

Use immutable updates for cell state changes. On click, cycle the cell state and check if any ship becomes fully hit, updating its sunk status accordingly.

5. Optimize and Discuss Trade-offs

Memoize Cell components to avoid re-renders. Discuss trade-offs between storing derived state vs. computing on the fly, and between using a single state object vs. multiple useState hooks.

Key Points to Mention

  • Immutable state updates to ensure React re-renders correctly.
  • Deriving sunk status from ship coordinates and hit cells rather than storing it separately.
  • Using React.memo or useCallback to optimize performance for a large grid.
  • Handling edge cases like clicking a sunk ship's cell or cycling through states in a defined order.
  • Considering accessibility (e.g., aria-labels for cells) and responsive design.
  • Discussing potential extensions like multiplayer or AI opponent to show scalability thinking.

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

Q2

How would you structure the React components for the grid and the ship status panel, and where should state live?

System DesignTechnical Trade-offs
Author's notes

I went with a single parent owning all state and passing down props.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements and constraints of the grid and ship status panel, such as real-time updates, performance needs, and component reusability. Then propose a component hierarchy that separates presentational and container components, and discuss where state should live based on ownership and update frequency. Finally, justify your choices with trade-offs around performance, maintainability, and scalability.

Pro tip: Emphasize that state should be lifted to the closest common ancestor only when necessary, and consider using React context or a state management library for global state like ship status if it's shared across many components. Also, mention memoization techniques to prevent unnecessary re-renders in the grid.

1. Clarify requirements

Ask about the grid's size, update frequency, and interactivity, and the ship status panel's data sources and update rate. This ensures your design meets actual needs.

2. Define component hierarchy

Break down the UI into components: a Grid container, GridCell components, a ShipStatusPanel, and possibly a shared parent. Decide which components are presentational vs. container.

3. Determine state ownership

Identify what state is needed (e.g., grid data, ship status) and where it should live. Lift state to the closest common ancestor if shared, or keep it local if only one component needs it.

4. Optimize performance

Discuss strategies like React.memo, useCallback, and virtualization for the grid to handle frequent updates efficiently. Consider using context or Redux for global state if needed.

5. Discuss trade-offs

Explain the pros and cons of your choices, such as prop drilling vs. context, local state vs. global state, and how they affect maintainability and performance.

Key Points to Mention

  • Separation of concerns: presentational vs. container components
  • Lifting state up to the closest common ancestor
  • Using React context or state management for global state (e.g., ship status)
  • Performance optimizations: React.memo, useMemo, useCallback, virtualization
  • Trade-offs between local and global state management
  • Real-time updates and handling frequent state changes

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

Q3

How does your click handler update a cell's state correctly even under rapid successive clicks?

Technical Trade-offsAlgorithms & Data Structures
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 scenario: is this a React component, vanilla JS, or another framework? Then explain how you ensure state updates are based on the latest state, not stale closures, by using functional updates or refs. Finally, discuss how you handle rapid clicks to avoid race conditions, such as batching or debouncing, and how you verify correctness with tests.

Pro tip: Mention that in React, using the functional form of setState (e.g., setCellState(prev => ...)) avoids stale state issues, but if you need the absolute latest value synchronously, a ref can be used. Also, note that React 18's automatic batching can affect timing, so be explicit about your assumptions.

1. Clarify the environment and constraints

Ask or state the framework (React, Vue, vanilla JS) and whether the cell state is local or global. This determines the tools available (e.g., hooks, refs, event delegation).

2. Explain the stale state problem

Describe how rapid clicks can cause multiple handlers to read the same outdated state value, leading to lost updates. This shows you understand the core issue.

3. Present your solution for correct state updates

Detail how you use functional updates (e.g., setState(prev => ...)) or a ref to always operate on the latest state. If using a ref, explain how you keep it in sync.

4. Address rapid successive clicks

Discuss strategies like debouncing, throttling, or disabling the button during processing to prevent race conditions. Mention if you rely on framework batching or event loop behavior.

5. Verify and test

Explain how you would test this scenario, such as with unit tests simulating rapid clicks or using React Testing Library's fireEvent. Mention edge cases like double-click or async updates.

Key Points to Mention

  • Functional state updates (e.g., setState(prev => ...)) to avoid stale closures
  • Using refs to access the latest state synchronously when needed
  • React 18 automatic batching and its impact on multiple setState calls
  • Debouncing or throttling click handlers to limit rapid invocations
  • Disabling the button or using a loading state to prevent concurrent updates
  • Testing with simulated rapid clicks to ensure correctness

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

Q4

How would you handle edge cases like overlapping ship coordinates, repeated clicks cycling back to empty, and resetting the board?

Adaptability & AmbiguityTechnical Trade-offs
Author's notes

Reset was easy since sunk status is derived.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the game rules and expected behavior for each edge case, then propose a state management strategy that handles them deterministically. Emphasize defensive programming, clear state transitions, and testability, while acknowledging trade-offs between simplicity and robustness.

Pro tip: Mention that you'd write unit tests for these edge cases first (TDD) to ensure they're handled correctly and to document expected behavior. This shows maturity and a proactive approach to quality.

1. Clarify Requirements

Ask questions to understand the exact rules: Can ships overlap? What should happen on repeated clicks? Is reset expected to clear all state? This ensures you're solving the right problem.

2. Design State Model

Propose a state representation that prevents invalid states, such as a 2D array for the board and a separate structure for ship positions. Use immutable updates to avoid side effects.

3. Handle Edge Cases

For overlapping ships, validate placement before committing. For repeated clicks, cycle through states (empty -> ship -> hit -> empty) or prevent invalid transitions. For reset, reinitialize state to initial values.

4. Implement with Tests

Write unit tests for each edge case to verify behavior. Use a testing library like Jest to simulate clicks and assert state changes.

5. Discuss Trade-offs

Acknowledge trade-offs: e.g., allowing overlapping ships simplifies placement but may complicate hit detection. Choose based on game requirements and user experience.

Key Points to Mention

  • State management with immutable data structures (e.g., using arrays or objects with spread operator)
  • Validation logic for ship placement to prevent overlaps
  • Click handling with a state machine or cycling logic (empty -> ship -> hit -> empty)
  • Reset functionality that reinitializes the board and ship positions
  • Unit testing edge cases with Jest or similar
  • Trade-offs between simplicity and robustness, and how to communicate them

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

Q5

If the grid scaled to 1000x1000, what would you change about rendering and sunk-detection to keep it performant?

System DesignTechnical Trade-offs
Author's notes

Mentioned virtualization for rendering and switching from a full-scan sunk check to an incremental counter per ship updated on each click.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the current rendering and sunk-detection implementation, then identify bottlenecks at 1000x1000 scale. Propose a combination of spatial partitioning, level-of-detail rendering, and optimized data structures, while discussing trade-offs between accuracy and performance.

Pro tip: Mention that sunk-detection can be approximated using a coarse grid or bounding volumes, and only refined for cells near the water surface, showing you understand how to balance precision with performance.

1. Clarify current implementation and scale

Ask about the existing rendering technique (e.g., canvas, WebGL) and sunk-detection algorithm to understand what needs optimization. Confirm the grid size and performance targets.

2. Identify bottlenecks

Analyze where the performance issues would arise: number of draw calls, memory usage, detection complexity. Consider both rendering and detection separately.

3. Propose rendering optimizations

Suggest techniques like spatial partitioning (quadtree), frustum culling, level-of-detail (LOD), and batching to reduce draw calls and only render visible cells.

4. Propose sunk-detection optimizations

Recommend using a coarse grid for broad-phase detection, then refine only near boundaries. Use spatial hashing or bounding volume hierarchies to reduce checks.

5. Discuss trade-offs and next steps

Acknowledge trade-offs between accuracy and performance, and suggest profiling and incremental improvements. Mention potential use of Web Workers for offloading detection.

Key Points to Mention

  • Spatial partitioning (quadtree, spatial hashing) for both rendering and detection
  • Level-of-detail (LOD) rendering to reduce geometry for distant cells
  • Frustum culling and occlusion culling to avoid rendering off-screen cells
  • Batching draw calls and using instanced rendering in WebGL
  • Broad-phase and narrow-phase collision detection for sunk-detection
  • Offloading heavy computations to Web Workers to keep UI responsive

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

Q6

How would you test this component, and which parts deserve pure unit tests versus rendered component tests?

Technical Trade-offsAPI & Integrations
Author's notes

Pure unit tests for the cycling logic and sunk detection since those are just functions.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the component's responsibilities and dependencies, then propose a testing strategy that balances speed and confidence. Explain which parts are pure logic (unit tests) and which require rendering (component tests), justifying each choice with trade-offs.

Pro tip: Emphasize that unit tests should cover pure functions and business logic, while component tests should focus on user interactions and integration with child components. Mention that avoiding over-testing implementation details keeps tests maintainable.

1. Clarify the component

Ask questions to understand the component's purpose, props, state, and external dependencies (e.g., APIs, context). This ensures your testing strategy is tailored to its actual behavior.

2. Identify pure logic

List parts that are pure functions, utilities, or state reducers that can be tested in isolation without rendering. These are ideal for fast unit tests.

3. Identify rendering and interaction

Determine which parts involve rendering, user events, or integration with child components. These require component tests using a library like React Testing Library.

4. Define test cases

For each category, outline specific test cases: unit tests for edge cases and logic branches; component tests for rendering output, user interactions, and conditional rendering.

5. Discuss trade-offs

Explain why you split tests this way, mentioning speed, reliability, and maintenance. Acknowledge that some overlap is okay but avoid redundant tests.

Key Points to Mention

  • Pure functions and business logic should be unit tested for speed and isolation.
  • Component tests should verify rendering, user interactions, and integration with child components.
  • Use React Testing Library for component tests to encourage testing from the user's perspective.
  • Mock external dependencies (e.g., API calls) in component tests to keep them deterministic.
  • Avoid testing implementation details (e.g., internal state) to reduce brittleness.
  • Consider the testing pyramid: many unit tests, fewer component tests, and even fewer end-to-end tests.

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