Discover the Operations
What can happen to it? Add, remove, change quantity, view, total, clear — sorted into create / read / update / delete / domain actions, each with inputs, state read, state changed, output, side effects and errors. Pure logic before database, network and UI.
The cart's state is items of { productId, quantity }. What can happen to it? Add an item, remove one, change a quantity, view the items, calculate the total, clear it. Six sentences of behaviour, in words, before a single function signature.
Sort the operations into CREATE, READ, UPDATE, DELETE and DOMAIN ACTIONS. The cart fits mostly into CRUD with "calculate total" as a domain action — but "reserve stock" and "check out" are domain actions that CRUD would mangle, and not every domain should be modelled as four verbs on a table.
Every operation, analysed the same six ways: inputs, state read, state changed, output, side effects, errors. Add item takes a product id and a quantity, reads the items and the catalog, changes one entry, returns the cart, has no side effects in V0, and fails on an unknown product or a non-positive quantity. Six answers per operation, and the function writes itself.
Cart state plus an operation gives a new cart state. Get that right as a plain function in memory — no database, no network, no UI — because every one of those wraps behaviour that must already work, and each one added first makes the behaviour harder to see and impossible to test alone.
Each operation promises something and refuses something: add item promises one entry per product and refuses a non-positive quantity or an unknown product, leaving the cart untouched. Written as a contract — given, promises, refuses — the operation is already most of an API contract, and the endpoint can only keep promises the operation made.