Shopping Cart
Level: Intermediate 30–60 minConcepts: StateBusiness Rules
Solutions: C# | TypeScript | Python
Implement a shopping cart system that handles products, quantities, pricing, and various types of discounts. The system should be able to calculate totals, apply discounts, and handle special cases like bulk pricing and promotional offers.
Requirements
- Add and remove items from the cart
- Update quantities of items
- Calculate subtotal for each item
- Calculate total for the entire cart
- Apply different types of discounts:
- Percentage-based discounts
- Fixed amount discounts
- Buy X get Y free offers
- Bulk pricing (e.g., buy 3 or more for a special price)
- Handle special cases:
- Items with limited stock
- Items that can’t be combined with certain discounts
- Maximum quantity limits per item
Hint
Start by implementing the basic cart operations (add, remove, update) and then gradually add the discount logic. Consider using the Strategy pattern for different types of discounts. Think about how to handle the order of discount application and how to validate that discounts are being applied correctly.
Bonus
- Implement a loyalty points system
- Add support for different currencies and exchange rates
- Implement a tax calculation system
- Add support for shipping costs and different shipping methods
- Implement a coupon code system
- Add support for saving carts and returning to them later
(Bonus features — loyalty, currency, tax, shipping, coupons, saved carts — are deliberately out of scope for the reference implementations below. They would each warrant their own collaborator or aggregate; the reference focuses on the core Cart + LineItem + DiscountPolicy vocabulary.)
Reference Walkthrough
This kata ships as a Mode F (Agent Full-Bake) reference: one commit per language, with a design-rationale walkthrough explaining why the domain came out the shape it did (Money and Quantity as value types, DiscountPolicy as a strategy hierarchy, ProductBuilder and CartBuilder for scenario setup).
All three implementations satisfy the same eighteen scenarios in SCENARIOS.md.
Related reading
- TDD Already Does BDD, Without the Gherkin
BDD wasn't a discovery. It was a rebrand of what disciplined TDD was already doing. Test data builders, factory hierarchies, and mock-driven collaboration tests are the scenarios, and they evolve alongside the code instead of rotting beside it. - The Contract Test Is the Only Witness the Agent Cannot Author
A test the agent wrote against code the same agent wrote shares the agent's blind spot: a misunderstanding in the implementation becomes a matching misunderstanding in the test, the bar goes green, and the bug ships certified. Consumer-driven contract tests are the only category where a second team publishes the assertion the first team has to satisfy. That separation of authorship is exactly what tamper-resistant test design demanded, applied at the integration seam. - Test Deletion Is a Privileged Operation
The cheapest way for an agent to make a failing test pass is to delete it. That is logical for the agent and catastrophic for the codebase. Tests are append-only by default. Deletion needs a human author, a separate commit, and a separate review.