ExamplesGENERALTEAM-SPECIFICILLUSTRATIVE

Examples Before Algorithms

Cart = [] → add Laptop → [Laptop × 1] → add Laptop → [Laptop × 2] → add Mouse → [Laptop × 2, Mouse × 1]. Four states and three operations, and the algorithm for addItem is already visible in them. If you cannot explain what should happen with a concrete example, you are probably not ready to implement it.

The moveWorked exampleNext questions

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 know the cart's operations and rules and still cannot see the algorithm. What do you write down so that the algorithm becomes visible?

The situation

You have "add item" as a name and "one entry per product" as a rule, and the function body is blank. You try to think about adding in general and your mind slides off it. You can feel that there is a find and a branch somewhere, but not in what order, or what the branch is on.

The reflex

Ask an AI to write addItem, or find one in a tutorial, and read the result to see how it thinks about the problem. Reading working code seems like the fastest way to see the algorithm.

Why it stalls

The code arrives and it does have a find and a branch — and you cannot say whether the branch is right, because you never wrote down what right looks like. The code is now the definition of the behaviour, and it was written by someone who never saw your rules.

What the reflex produces — and fails to produce
  • The code arrives and it does have a find and a branch — and you cannot say whether the branch is right, because you never wrote down what right looks like. The code is now the definition of the behaviour, and it was written by someone who never saw your rules.
  • The tutorial's addItem appends. Its cart shows Laptop twice, and nothing in your head objects, because "same product twice" was never a case you examined; the code has decided a rule you had not yet noticed you needed.
  • Asked to explain the function line by line, you can describe what each line does and not why it is there. That is the shape of code that was received rather than derived, and it will not survive the first change.
ProblemUnderstandRequirementsConstraintsUnknownsDecompositionSmallest StepModelExperimentObserveDebugLearnIterate

The move

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

  • Refuse to think about the operation in general. Pick a concrete cart, apply the operation once, and write what the cart looks like afterwards. Then apply it again with a different input. Then again with the same input as before. The sequence of states is the specification, and it was written without any code.
  • Read the algorithm off the examples. Between [Laptop × 1] and [Laptop × 2] the number of entries did not change and a quantity did; between [Laptop × 2] and [Laptop × 2, Mouse × 1] an entry appeared. Two different things happened, so there is a branch; what decided it was whether the product was already there, so there is a find before the branch. The algorithm — find, branch, increase or append — was in the examples, not in your head.
  • Use the moment of hesitation. If you cannot write the after for some before and operation, you are not ready to implement — not because you lack skill, but because a decision has not been made. Make it as a rule, write the after, and continue. Every hesitation you resolve here is a bug you do not write later.
  • Keep the examples. They are the tests, once the code exists; they are the explanation when someone asks why the function has a find in it; and they are the thing you check the received code against, if you do decide to read someone else's.

The sequence that contains the algorithm

Three operations on one cart, from the concept record. The device names what changed each time, because the change is the point: the first and third calls added an entry and the second changed a quantity. The same operation did two different things, and what differed between the calls was whether the product was already present. That sentence is the algorithm.

add-first, then add-again
before
Cart = []  →  after add Laptop:  [ Laptop × 1 ]
add Laptop (the same product, a second time) →
after
Cart = [ Laptop × 2 ]
what changed First call: an entry appeared · Second call: Laptop's quantity 1 → 2; the number of entries did not change · The difference between the calls: whether Laptop was already in the cart

The third example, and the branch it reveals

Add a different product to the same cart and an entry appears again, while Laptop is untouched. Now there are two examples of the same operation with different kinds of change, which means a branch, and one thing the code must look at to choose: is there already an entry with this product id? The find comes before the branch because the branch needs its answer. Nothing here was invented; it was read off the states.

add-second
before
Cart = [ Laptop × 2 ]
add Mouse →
after
Cart = [ Laptop × 2, Mouse × 1 ]
what changed An entry appeared: Mouse × 1 · Laptop: untouched · Compared with add-again: a different kind of change from the same operation — so addItem has a branch, and the find decides it
The algorithm, read off the three examples
1function addItem(cart, productId, quantity = 1):
2 item = find entry in cart.items with item.productId == productId -- what differed between the calls
3 if item exists:
4 item.quantity = item.quantity + quantity -- add-again
5 else:
6 append { productId, quantity } to cart.items -- add-first, add-second
7 return cart

The two rule checks — product exists, quantity positive — are not in this version yet; they arrive from the invalid examples, and go before the find because rejection must leave the state untouched.

From "how do I implement a cart?" to a question with an answer

The reflex asks the general question and gets general code. The examples ask a question that has a checkable answer, and the decomposition below shows the cart broken down by examples rather than by layers — every leaf is a before / after someone could run, which is what makes it testable.

The cart, decomposed by examples
Implement addItem
  • A product not yet in the cartthe normal casetestable [] + add Laptop → [Laptop × 1]; [Laptop × 2] + add Mouse → [Laptop × 2, Mouse × 1].
  • A product already in the cartthe case that reveals the findtestable [Laptop × 1] + add Laptop → [Laptop × 2], and the cart still has one entry.
  • An input the rules refusethe case that fixes where the checks go
    • Quantity 0testable [] + add Laptop × 0 → rejected with "quantity must be positive"; cart still [].
    • Unknown producttestable [] + add Toaster → rejected with "unknown product"; cart still [].

Every leaf is an example; the examples are the tests; the tree is the plan for the function, and none of it names a language.

Question quality
vagueHow do I implement a shopping cart?
betterWhat should addItem do when the product is already in the cart?
bestCart = [Laptop × 1]; add Laptop. What is the cart afterwards, and what changed?

why The best form has one answer that can be right or wrong — [Laptop × 2], quantity changed, entries unchanged — and that answer contains the branch; the vague form can only be answered with someone else's code.

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.

  • Write before → operation → after for the empty cart first, then for a cart that already contains the product, then for a cart containing something else (Example-Driven Thinking).
  • Name what changed between before and after, explicitly: "Laptop's quantity: 1 → 2; entries: unchanged". The changed list is where the branch shows itself.
  • When two examples of the same operation change different things, there is a branch; ask what the code must look at to choose, and that is the lookup.
  • Write the example you cannot complete as a question, decide it as a rule, and come back (Rules Come From Examples).
  • Only when the sequence of states is written and each transition is explained in words, write the pseudocode — from the examples, not from memory (Plain-English Logic Is the Algorithm).

Worked on a concrete problem

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

  • Cart = []. add Laptop → [Laptop × 1]. Changed: an entry appeared. add Laptop → [Laptop × 2]. Changed: a quantity, not the number of entries. add Mouse → [Laptop × 2, Mouse × 1]. Changed: an entry appeared, Laptop untouched. Two kinds of change from one operation means one branch, and the thing that differed between the second and third call was whether the product was already in the cart.
  • From that: find the entry with this product id; if found, increase its quantity; otherwise append a new entry. The numbered plain English in the concept record is exactly this reading, with the two rule checks — product exists, quantity positive — placed before the find because the invalid examples say the state must be untouched on rejection.
  • The version that appends without a find would have produced [Laptop × 1, Laptop × 1] on the second add. The example is what makes that visibly wrong; without it, the duplicate looks like a design choice.

How you know it worked

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

  • A written sequence of cart states exists for every operation, with the change between each pair named, and no code has been written yet.
  • You can point to the example that produces each branch of the algorithm.
  • Received code — from a tutorial, a colleague or an AI — can be checked: run the examples against it and see which after it gets wrong.

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
  • ?For this operation, what does the state look like before, and what exactly does it look like after?
  • ?Between which two examples did something different happen — and what did the code have to look at to choose?
  • ?Which example can I not complete without deciding something?
  • ?If I ran these examples against the code I was about to copy, which one would fail?

What can go wrong

How the move itself fails
  • Examples are written only for the empty cart, so every add looks like an append and the find never appears. The second example must reuse a product.
  • Examples are written after the code, from the code, and confirm it. They then test the implementation rather than the behaviour, and a bug in the code becomes a bug in the examples.
  • The examples get so numerous that the sequence of states becomes a table nobody reads. Three or four per operation — normal, edge, invalid — is what the algorithm needs; the rest are tests, and belong in the test file.
What the move costs
  • Writing four examples before a three-line function is slower than writing the function, and on an operation you have written many times before it is theatre.
  • Examples fix decisions early; "same product twice → increment" is now a commitment that a later "wishlist allows duplicates" requirement has to undo.
  • A concrete example can hide a general case: [Laptop × 2] says nothing about a cart with a thousand entries, and the algorithm read off small examples may be the wrong one at scale.
Misreads
  • "So examples replace understanding the algorithm." They are how the algorithm is found; the reading — two kinds of change, therefore a branch, therefore a lookup — is the understanding. Examples without the reading are a table.
  • "This is test-driven development." It is upstream of it. TDD writes the test first in code; this writes the state change first in words, and only some of them become tests.
  • "Never read someone else's cart." Read it after your examples exist, and check it against them; that is reading code as a reviewer, which teaches, instead of as a recipient, which does not (Before You Copy Code).

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.

  • GENERALBefore / operation / after is how any stateful concept becomes visible — a rate limiter's window, a queue's jobs, a login's session — and reading the branch off two differing examples is the same move everywhere.
  • TEAM-SPECIFICA learner needs the examples written down; an engineer who has implemented the cart before runs them in their head and the visible step is the one or two edge cases they still write out, so the move shrinks with familiarity rather than disappearing.
  • ILLUSTRATIVELaptop, Mouse and the quantities are the concept record's invented example; any real cart's products and numbers would do, and the reading would be the same.

Where the depth lives

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