Design a Recipe and Inventory Ordering Service

Quick Overview

Design an object-oriented recipe service where nested dishes consume raw inventory and an order either succeeds atomically or changes nothing. The prompt tests typed references, cycle detection, quantity expansion, overflow handling, concurrent stock updates, immutable views, and explicit replacement and query semantics.

Design a Recipe and Inventory Ordering Service

Company: StackAdapt

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: easy

Interview Round: Technical Screen

# Design a Recipe and Inventory Ordering Service ## Scenario Design an object-oriented service with recipes, supplies, and orders. A recipe has a unique name, a stored preparation time, and ingredient requirements with positive integer quantities. A supply entry represents the available count of a raw ingredient. A recipe may use another recipe as an ingredient, so ordering a dish recursively consumes the required raw supplies. For this exercise, recipe dependencies must be acyclic. `placeOrder(recipeName)` returns `true` only when the recipe exists, its dependency graph is valid, and all required raw inventory can be decremented atomically; otherwise it returns `false` and changes nothing. A getter that filters by preparation time uses each recipe's stored time rather than summing nested times. If you choose different semantics, state them before designing the API. ### Part 1: Model recipes, ingredient references, and supply Define the core types, invariants, and public operations such as `addRecipe`, `addSupply`, `placeOrder`, and query methods. #### What This Part Should Cover - Unique identifiers or namespace rules for recipes and raw ingredients. - Positive quantities, nonnegative stock, and preparation-time validation. - A typed way to distinguish a raw ingredient reference from a nested recipe reference. - Whether add operations replace, reject, or version an existing definition. - Encapsulation that prevents callers from mutating stored objects behind the service. ```hint Make references unambiguous A plain ingredient-name string becomes ambiguous if a recipe and a raw supply can share the same name. ``` ### Part 2: Validate and expand nested recipes Explain how adding or ordering a recipe detects cycles and turns nested requirements into aggregate raw-ingredient quantities. #### What This Part Should Cover - Missing references and direct or indirect dependency cycles. - Multiplication and aggregation when the same raw ingredient appears through several paths. - Integer overflow or maximum-quantity handling. - Memoization or another way to avoid repeatedly expanding shared sub-recipes. ```hint Track traversal states Treat recipe expansion as a graph problem and distinguish nodes currently being visited from nodes already completed. ``` ### Part 3: Make `placeOrder` atomic Design the check-and-decrement operation so insufficient stock or concurrent orders cannot produce partial or negative inventory. #### What This Part Should Cover - Expanding and aggregating all raw requirements before changing stock. - Checking every required count before applying any decrement. - A locking, transaction, or version-check strategy for concurrent calls. - Clear failure behavior for unknown dishes, invalid graphs, overflow, and insufficient stock. ```hint Close the concurrency gap Separating validation from mutation is necessary but not sufficient if another order can modify stock between those steps. ``` ### Part 4: Define getters and tests Specify useful read methods, including a query for recipes with preparation time greater than a threshold, and the tests needed for boundary cases. #### What This Part Should Cover - Deterministic ordering and immutable return values. - Whether the threshold comparison is strict or inclusive. - Tests for nested quantities, shared ingredients, missing references, cycles, exact stock, insufficient stock, and concurrent orders. - Behavior after recipe replacement or supply replenishment. ```hint Turn ambiguity into a contract Make every ambiguous boundary visible in a method contract before writing its test. ``` ### What a Strong Answer Covers A strong design uses explicit types and invariants, validates the recipe graph, expands nested recipes without double counting, and performs inventory updates atomically. It declares replacement and failure semantics, returns safe deterministic views, and tests graph, arithmetic, stock, and concurrency boundaries. ### Follow-up Questions - How would you support ordering more than one serving at a time? - What changes if recipes and inventory definitions must be versioned? - How would you reserve stock for an order that is prepared asynchronously? - How would you expose the exact shortage without weakening atomicity?

Quick Answer: Design an object-oriented recipe service where nested dishes consume raw inventory and an order either succeeds atomically or changes nothing. The prompt tests typed references, cycle detection, quantity expansion, overflow handling, concurrent stock updates, immutable views, and explicit replacement and query semantics.

|Home/Software Engineering Fundamentals/StackAdapt
StackAdapt logo
StackAdapt
Apr 4, 2026, 12:00 AM
easySoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
1
0

Design a Recipe and Inventory Ordering Service

Scenario

Design an object-oriented service with recipes, supplies, and orders. A recipe has a unique name, a stored preparation time, and ingredient requirements with positive integer quantities. A supply entry represents the available count of a raw ingredient. A recipe may use another recipe as an ingredient, so ordering a dish recursively consumes the required raw supplies.

For this exercise, recipe dependencies must be acyclic. placeOrder(recipeName) returns true only when the recipe exists, its dependency graph is valid, and all required raw inventory can be decremented atomically; otherwise it returns false and changes nothing. A getter that filters by preparation time uses each recipe's stored time rather than summing nested times. If you choose different semantics, state them before designing the API.

Part 1: Model recipes, ingredient references, and supply

Define the core types, invariants, and public operations such as addRecipe, addSupply, placeOrder, and query methods.

What This Part Should Cover Guidance

  • Unique identifiers or namespace rules for recipes and raw ingredients.
  • Positive quantities, nonnegative stock, and preparation-time validation.
  • A typed way to distinguish a raw ingredient reference from a nested recipe reference.
  • Whether add operations replace, reject, or version an existing definition.
  • Encapsulation that prevents callers from mutating stored objects behind the service.

Part 2: Validate and expand nested recipes

Explain how adding or ordering a recipe detects cycles and turns nested requirements into aggregate raw-ingredient quantities.

What This Part Should Cover Guidance

  • Missing references and direct or indirect dependency cycles.
  • Multiplication and aggregation when the same raw ingredient appears through several paths.
  • Integer overflow or maximum-quantity handling.
  • Memoization or another way to avoid repeatedly expanding shared sub-recipes.

Part 3: Make placeOrder atomic

Design the check-and-decrement operation so insufficient stock or concurrent orders cannot produce partial or negative inventory.

What This Part Should Cover Guidance

  • Expanding and aggregating all raw requirements before changing stock.
  • Checking every required count before applying any decrement.
  • A locking, transaction, or version-check strategy for concurrent calls.
  • Clear failure behavior for unknown dishes, invalid graphs, overflow, and insufficient stock.

Part 4: Define getters and tests

Specify useful read methods, including a query for recipes with preparation time greater than a threshold, and the tests needed for boundary cases.

What This Part Should Cover Guidance

  • Deterministic ordering and immutable return values.
  • Whether the threshold comparison is strict or inclusive.
  • Tests for nested quantities, shared ingredients, missing references, cycles, exact stock, insufficient stock, and concurrent orders.
  • Behavior after recipe replacement or supply replenishment.

What a Strong Answer Covers Guidance

A strong design uses explicit types and invariants, validates the recipe graph, expands nested recipes without double counting, and performs inventory updates atomically. It declares replacement and failure semantics, returns safe deterministic views, and tests graph, arithmetic, stock, and concurrency boundaries.

Follow-up Questions Guidance

  • How would you support ordering more than one serving at a time?
  • What changes if recipes and inventory definitions must be versioned?
  • How would you reserve stock for an order that is prepared asynchronously?
  • How would you expose the exact shortage without weakening atomicity?
Loading comments...