Impl. LoopGENERALSTAGE-SPECIFICILLUSTRATIVE

The Implementation Loop

I need X → what is X → what information → what can happen → what rules → what examples → how to represent → which data structure → what each operation does → pseudocode → one operation → tests from the examples → edge cases → integrate. Fourteen steps, and code is the eleventh.

The situation, the reflex, and why it stalls

Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.

The question

You have a concept in English and you want an implementation you can defend. What is the sequence of steps from the one to the other, and which step are you actually on?

The situation

You accept that the cart should be understood before it is coded, and you have a sentence saying what it is. Now what? You could list fields, or draw boxes, or write a test, or write the class anyway — and each feels equally like the next step, which means none of them is obviously the next step.

The reflex

Write the class with the fields you can think of and the methods you can name, and fill in the bodies as you go. The class is a container for everything else; having it feels like having a plan, and each empty method looks like a to-do item.

Why it stalls

The class has fields nobody challenged — productName, price, total — so the cart duplicates the catalog and keeps a total that can drift from its items. Nobody asked "does an operation read this?" because there was no step at which to ask.

What the reflex produces — and fails to produce
  • The class has fields nobody challenged — productName, price, total — so the cart duplicates the catalog and keeps a total that can drift from its items. Nobody asked "does an operation read this?" because there was no step at which to ask.
  • The method bodies are written from intuition rather than from examples, so "add" appends unconditionally and the duplicate-entry bug ships. There was no step where "[ Laptop × 1 ] + Laptop" was written down, so the rule it exposes was never found.
  • The data structure was chosen by the class syntax — an array because that is what items: CartItem[] autocompletes to — with no idea what the operations cost, and no idea whether it matters.
  • Integration is attempted with all six operations at once, so when the badge shows the wrong count the bug could be in any of them.
ProblemUnderstandRequirementsConstraintsUnknownsDecompositionSmallest StepModelExperimentObserveDebugLearnIterate

The move

Precisely enough to apply it to a problem you have never seen — not a slogan.

  • Treat implementation as a derivation with a fixed order: meaning, then the information the concept needs, then what can happen to it, then the rules that must always hold, then concrete examples, then a representation of the state, then a data structure chosen with the operations in view, then each operation as inputs / reads / changes / output, then pseudocode, then one operation in code, then tests from the examples, then edge cases, then integration. Each step's output is the next step's input, which is why the order is not negotiable and why skipping a step shows up two steps later.
  • At every moment know which step you are on. "I am on step six, representation, and I have not written examples" is diagnostic: go back one. Most stuckness in implementation is being on step ten with step four undone.
  • Let the examples do the discovering. The rules and the edge cases are not invented in the abstract; they fall out of writing "[ Laptop × 1 ] · add Laptop" and asking what the shopper expects. A loop that starts from examples finds its rules early and cheaply.
  • Implement one operation, run its examples as tests, and only then take the next operation. The loop is a loop because integration reveals requirements — the badge wants a count, so "view" needs to exist — and each of those goes back to the top as a new operation, not a patch.

The loop as a ladder

Each level exists because the level below it needs its output. Read the because column: it is the argument for the order, and it is also the diagnostic — if you cannot produce a level's output, the level above is incomplete.

From "I need a cart" to an integrated addItem
  1. 1 · What is it?
    A temporary collection of products the user intends to purchase.A word cannot be implemented; a meaning says which information and operations belong and which do not.
  2. 2 · What information?
    items[] of productId + quantity; owner depends on version; total, createdAt, productName challenged out.Operations read and change state; without the state list, no operation can be described.
  3. 3 · What can happen?
    add, remove, change quantity, view, total, clear.The operations decide which representation is cheap and which rules matter.
  4. 4 · What rules?
    quantity > 0; one entry per product; unknown product rejected; total never negative.Rules become validations, and validations are lines of code the operation must contain.
  5. 5 · What examples?
    [] + Laptop → [ Laptop × 1 ]; [ Laptop × 1 ] + Laptop → [ Laptop × 2 ]; add × 0 → rejected.Examples check the rules and become the tests; a rule without an example is a belief.
  6. 6–7 · Represent and choose
    A list of entries; an array, because a cart is small and shown in insertion order (O(n) find).Only with the operations known can a structure be judged by what it costs them.
  7. 8–9 · Each operation, then pseudocode
    addItem: inputs, reads, changes, output, errors → six lines of pseudocode.Pseudocode fixes the branches — exists / does not exist — before syntax can hide them.
  8. 10–11 · One operation, then tests
    addItem in TypeScript; tests from add-again and invalid-zero.One tested operation proves the shape; six untested ones prove nothing.
  9. 12–13 · Edge cases, integrate
    to-zero becomes a removal; the product page calls addItem and reads the count.Integration reveals the next operation — a count for the badge — which re-enters at level 3.

The loop as a pipeline, with how each step fails

The same sequence, read for its failure modes. The failsBy column is what you see two steps later when a step was skipped — the symptom to work backwards from.

Symptoms of a skipped step
  1. 1
    Meaning

    One sentence a shopper would agree with.

    fails by Fields and operations that belong to checkout or the catalog creep into the cart.

  2. 2
    State, challenged

    Each field named with the operation that reads it.

    fails by A stored total drifts from the items; a stored name goes stale after a rename.

  3. 3
    Operations

    Verbs with inputs / reads / changes / output / errors.

    fails by A class with fields and no methods, or methods whose errors were never listed.

  4. 4
    Rules from examples

    Before/after cases; rules read off the surprising ones.

    fails by The duplicate-entry bug: add appends because nobody wrote "[ Laptop × 1 ] + Laptop".

  5. 5
    Representation

    A structure chosen against the operations, cost annotated.

    fails by A map because it is "faster", with a JSON conversion nobody wanted, for a cart of five entries.

  6. 6
    One operation → tests → integrate

    addItem, then its examples as tests, then the page calls it.

    fails by All six operations wired at once; the wrong badge count could be any of them.

The pipeline is per operation. The second time around it is faster, because meaning and state do not change; only the operation does.

Which operation first, and a different valid order

The loop says one operation at a time; it does not say which. The order below starts with the operation that carries the most rules, because that is where the examples teach the most. Starting elsewhere is defensible, and the device says when.

Operations of the cart, one possible order
  1. 1
    addItem

    because Three of the four V0 rules live here; implementing it first exercises the find, the append and both rejections.

  2. 2
    getItems

    because The badge and the page need to see what add did; a read makes the first integration possible.

  3. 3
    removeItem, then changeQuantity

    because changeQuantity to 0 is defined as a removal, so removal has to exist first.

  4. 4
    total

    because It needs a way to price a product — the catalog — which is the first dependency outside the cart, and better met once the cart itself works.

  5. 5
    clear

    because Trivial, and only needed when checkout exists to call it.

a different valid order View-first: implement getItems and total against a hand-built cart literal before any mutation, when the page is the risky part — for example when a designer is waiting on the cart's shape. You get the rendering integrated on day one and the mutations, with their rules, second.

The implementation ladder

Concept, examples, pseudocode, code, tests, production — for the concept this lesson is about. Code is the fourth tab, not the first.

concept Shopping Cart beginner
Build it step by step →

Shopping Cart = A temporary collection of products the user intends to purchase, held between browsing and checkout.

Identity, ownership, lifetime
  • Does a cart have identity? Yes, weakly. Two carts with the same items are still two carts, because each belongs to someone and will become a different order. It needs an id once it leaves memory; in memory the variable is the identity.
  • Who owns it? A shopper — a logged-in user or an anonymous session. The owner is part of the state because "my cart" has to be findable again.
  • How long does it exist? From the first add until checkout or abandonment. Whether it survives a reload, a closed browser or a login is not a property of the concept; it is a persistence decision made later, and each answer changes where the cart lives.
  • Should it survive reload? Usually yes for a store, usually no for a demo. V1 in memory says no; V2 browser storage says yes on one device; V3 server storage says yes everywhere the user is logged in.
  • Should it survive login? Only if an anonymous cart and a logged-in cart are merged — a rule that does not exist in V1 and appears as a modification later.
State it must remember
  • itemscollection of CartItemkeepThe cart is its items; without them nothing else means anything.
  • items[].productIdidkeepThe reference to what is being bought. The catalog owns the product; the cart only points at it.
  • items[].quantityinteger > 0keepTwo laptops is one entry with quantity 2, not two entries — the rule "one entry per product" needs a quantity to hold.
  • owneruser id or session iddependsSo the cart can be found again by the person it belongs to.
  • items[].productNamestringderiveIt would be convenient to render the cart without a catalog lookup.
  • items[].pricemoneydependsThe total needs a price per item.
  • totalmoneydropEvery screen shows the total.
  • currencycodedependsPrices need a currency to be added.
  • createdAttimestampdropAbandoned carts might be expired or emailed about.
Operations
  • update Add item the updated cart
  • delete Remove item the updated cart
  • update Change quantity the updated cart
  • read View items the list of entries — product id and quantity — for rendering
  • domain Calculate total the sum of price × quantity over the entries
  • delete Clear cart the empty cart
Rules that must always hold
  • Every quantity is greater than zero.
  • One logical entry per product.
  • The total is never negative.
  • An unknown product cannot be added.
  • Quantity cannot exceed available stock — if inventory is enforced here.

How to do it

Most important first.

Worked on a concrete problem

The move has to produce something. This is what it produced.

  • Steps one to four for the cart: meaning — a temporary collection of products the user intends to purchase; information — items, each a productId and quantity, with owner marked "depends" (V0 has one cart) and total, createdAt and productName challenged out; what can happen — add, remove, change quantity, view, total, clear; rules — every quantity is greater than zero, one entry per product, an unknown product cannot be added, the total is never negative.
  • Steps five to eight: examples — add-first, add-again, add-second, remove, to-zero, invalid-zero; representation — the state is a list of entries; structure — array of CartItem, chosen because a cart holds a handful of items shown in insertion order and the O(n) find is invisible at that size; add-item as an operation — inputs productId and quantity (default 1), reads items and the catalog, changes items (a new entry or an existing entry's quantity), outputs the updated cart, no side effects in V0, errors for unknown product and quantity ≤ 0.
  • Steps nine to eleven: pseudocode — if not catalog.has(productId): reject; if quantity <= 0: reject; item = find entry with item.productId == productId; if item exists: item.quantity += quantity else append { productId, quantity }; return cart. Then the TypeScript, which is those lines with cart.items.find((i) => i.productId === productId) in place of the English find. Tests: "adding the same product twice increases the quantity" from add-again; "a zero quantity is rejected and the cart is unchanged" from invalid-zero.
  • Steps twelve to fourteen: edge cases — removing the last item leaves an empty cart, which is valid; change to 0 becomes a removal; total of an empty cart is 0. Integration — the product page calls addItem and reads getItems for the badge. The badge wanting a count is a new read operation, which goes back to step three rather than being bolted on.

How you know it worked

What now exists that did not before, and what question you can now ask.

  • You can name the step you are on and the artefact the previous step produced.
  • Each rule can be pointed at the example that produced it, and each test can be pointed at the example it came from.
  • The data structure has a reason that mentions the operations, not the language.
  • The first integrated operation works end to end before the second operation has been written.

The questions you can now ask

The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.

Next questions
  • ?Which step of the loop am I on, and what did the previous step hand me?
  • ?Which example would force a rule I have not written yet?
  • ?What does this operation read, change and return — and what can go wrong inside it?
  • ?Which one operation, implemented and integrated first, proves the shape is right?

What can go wrong

How the move itself fails
  • The loop is treated as a waterfall. Fourteen steps done once, in full, for all six operations, before any code — and integration then reveals that "view" needs names, which means a catalog lookup, which changes the representation discussion. Go around the loop per operation, not per concept.
  • Steps are ticked without their output. "Examples: done" with one happy-path example produces no rules; the loop only works if step five yields normal, edge and invalid cases.
  • The loop is applied at the wrong granularity. Running fourteen steps on "increase a counter" is overhead; the loop is for a concept you cannot yet write, and it shrinks as the concept becomes familiar.
  • The order is defended past its purpose. On a concept whose representation is forced — a database table that already exists — step six is a given, and the loop starts from the operations against it.
What the move costs
  • Fourteen named steps is slower than typing the class on a concept you already understand; the loop pays when the concept is new to you.
  • One operation at a time delays the moment the whole feature is visible; a stakeholder sees "add works" for a while before they see a cart.
  • The loop produces prose and tables that must be kept next to the code or they rot; a worksheet that is not revisited is a document, not a method.
Misreads
  • "So pseudocode is a step I can skip if I know the language." Pseudocode is where the branch structure is decided without syntax in the way; skipping it in a language you know well is fine, and it is exactly the step that catches the missing find in a language you know badly.
  • "Tests come at step eleven, so this is not test-first." The examples at step five *are* the tests, written before any code; step eleven is where they gain a runner.
  • "The loop is fourteen steps, so implementation takes fourteen times longer." Most steps are a sentence or a row; the loop is an hour for a cart, and the hour replaces days of debugging a cart nobody defined.

Where this applies

Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.

  • GENERALThe order — meaning before state before operations before rules before examples before representation before code — holds for any concept in any language; only the size of each step changes.
  • STAGE-SPECIFICGreenfield, the loop starts at meaning; in an existing system with a cart table, the state and representation steps are reading, not deciding, and the loop starts at operations against what exists.
  • ILLUSTRATIVELaptop, Mouse, the badge and the six operations are the shopping-cart record's own worked material; no real store is being described.

Where the depth lives

This domain asks the question and hands the answer off by name.

Further
  • The Implementation Ladder at /thinking/ladder renders these levels for the cart with the V0–V6 evolution beneath them.