**The brief.** [Exercise 4](@/AgenticEngineering/Introduction/Source/Exercise4)'s order calculator **works** — and it is ugly: the same logic copied twice, unexplained numbers hard-coded in the middle of it, names that tell you nothing. Nobody touches it until it is **pinned** — until what it really does is written down as checks that run. First *characterize* it: capture six of its behaviours by *running* the code and recording each result as a check (that record is your spec — the outcome you want, written so it runs). Then *refactor* — tidy the code without changing what it does — and let the equivalence table prove the output never moved.

This is Module 1's discipline at working size — one step past Predict the Behaviour: there you pinned someone else's function; here you pin and then change, and the pins — your running record of what the code does — are what make the change safe. It is the exact move Module 4 — Refactoring turns into a profession.

The legacy code

The module's own Exercise 4, distilled to the function that matters:

// ugly but works — in prod, no tests
static decimal LegacyTotal((string N, decimal P, int Q)[] basket)
{
    decimal x = 0;
    foreach (var i in basket) x += i.P * i.Q;
    if (x > 1000) x = x - x * 0.05m;
    if (x > 2000) x = x - x * 0.02m;
    return x;
}

Two ifs, three unexplained hard-coded numbers, one variable called x — and at least three behaviours in there that most readers get wrong on the first guess.

The rules

  1. Characterize first. The Pinned column in the workbench is pre-filled with plausible guesses — three are wrong. Run, read the Legacy column (that is the truth), and correct the pins until the legacy agrees with every pin. Do not touch the baskets; only the pins move.
  2. Then refactor. Rewrite the logic in Total — named constants, one clear method, honest names. The Refactored column must agree with the pins too: ✓ identical, all six rows.
  3. The behaviours worth your attention: is the first threshold > or >=? Does the second if read the gross total — or the already-discounted one? Is a 3,000 basket a flat 7% off — or something subtler?

Your workbench

When every row says ✓ you have done a true refactor: the shape changed, and the behaviour — including the quirky sequential discount — provably did not.


Pinned and tamed — or stuck on a wrong pin? Reveal the solution — the full battery with each surprise explained, and a clean refactor that stays byte-identical.

← Introduction exercises · Module 1 — Introduction

Reconnecting…
The connection to the server was interrupted. Trying to restore it…
Trying again…
The connection could not be restored. Reloading the page…
The server was updated. Reloading the page to pick up the latest version.