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.