Design a Checkout Price Engine with Pluggable Percent, Fixed and Buy-X-Get-Y Discounts
Company: Amazon
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Onsite
Build the checkout price engine for an e-commerce platform. Given a cart, compute the final price by applying discounts, and return the final total.
- A cart contains line items. Each line item has a `productId`, a `unitPrice` and a `quantity`.
- The customer has a tier: `standard` or `premium`.
- There are three kinds of discount: `PERCENT_OFF`, `FIXED_OFF` and `BUY_X_GET_Y`.
This is an object-oriented design round. The interviewer cares most about how the classes fit together, and expects you to state the main flow of computing the total in one sentence before you start creating classes. The discussion then moves into code: how eligibility is checked, where discounts are actually applied, and two of the discount implementations.
### Constraints and Clarifications
- Write code in a language of your choice. The later parts ask for real method bodies, not only a class diagram.
- How the customer tier affects pricing, whether several discounts can apply to one item, and what `FIXED_OFF` and `BUY_X_GET_Y` attach to are not specified. Ask, and state the policy you implement.
### Clarifying Questions
- How does the customer tier interact with discounts: are some discounts restricted to premium customers, or do premium customers get a different rate?
- Can several discounts apply to the same line item? If so, do they add up, apply one after another, or does only the best one apply?
- Is `FIXED_OFF` an amount off each unit, off each eligible line, or off the whole cart?
- For `BUY_X_GET_Y`, are the free units the same product, and must they already be in the cart?
- How should prices be represented and rounded, and can a line's price ever go below zero?
### Part 1 — How the classes fit together
State the compute-total flow in one sentence, then present the classes and how they connect: what represents the cart and its line items, what represents a discount, and what orchestrates the calculation.
```hint One sentence first
Describe the loop in plain words: what is visited, what each discount is asked, and what is subtracted from what. The classes should follow from that sentence.
```
#### What This Part Should Cover
- A one-sentence main flow, stated before any class
- A common discount abstraction that lets new discount kinds be added without changing the engine
- Clear ownership: data objects for the cart, line item and customer, and one engine that orchestrates
- Where the customer tier enters the calculation
### Part 2 — Eligibility and where discounts are applied
How is `isEligible` used, and where exactly is a discount applied: which function does it, and what does it return? Then show what `isEligible` looks like for the percentage-off discount, with a concrete example.
```hint Whether versus how much
Keep the question "does this discount apply to this item for this customer?" separate from "how much does it take off?", and decide which object asks each one.
```
#### What This Part Should Cover
- The call sequence between the engine, `isEligible` and `apply`
- A concrete percentage-off eligibility rule, with an example of an item that qualifies and one that does not
- What `apply` returns, and why it does not modify the cart
- How the discounts on one item are combined and bounded
### Part 3 — Implement percentage-off
Write `apply` for the percentage-off discount.
```hint Money is not a float
Decide the unit you store prices in, and where rounding happens, before you multiply by a percentage.
```
#### What This Part Should Cover
- The correct discount for a whole line (unit price times quantity)
- An explicit money representation and rounding rule
- Validation of the percentage
### Part 4 — Implement buy-X-get-Y
Next, implement buy-X-get-Y. Unlike the other two kinds, it does not take a stated rate or amount off the price; it makes some units free.
```hint Count the free units
Work out how many units are free for quantities just below, exactly at, and just above a multiple of the deal size, then turn that count into money.
```
#### What This Part Should Cover
- A correct count of free units for any quantity, including a partial group
- Conversion of the free units into a discount amount
- Edge cases: a quantity below the threshold, and the same product split across several lines
### What a Strong Answer Covers
- A design in which adding a fourth discount kind changes no existing class
- Separation of eligibility, amount calculation and orchestration
- Explicitly stated policies for tier, stacking, fixed-off scope and rounding
- Correct, runnable method bodies for percentage-off and buy-X-get-Y
- Testability: a small cart whose total can be checked by hand
### Follow-up Questions
- How would you add a cart-level discount, such as an amount off when the cart subtotal exceeds a threshold?
- Two promotions must never combine on the same item. How would you model exclusivity and priority?
- How would you return an itemized receipt that explains every discount that applied and why the others did not?
- How would you make discount rules configurable at runtime without redeploying code?
Overview: An object-oriented design exercise to build a checkout price engine that applies percent-off, fixed-amount and buy-X-get-Y discounts to cart line items for standard and premium customers. It tests how discount classes, eligibility checks and the engine fit together, and asks for working percent-off and buy-X-get-Y implementations.
Read the full Amazon Software Engineer interview experience this question came from