StartGENERALSIMPLIFIEDCONTESTEDILLUSTRATIVE

The Problem-Solving Loop

Problem → Understand → Requirements → Constraints → Unknowns → Decomposition → Smallest Useful Step → Model → Experiment / Implement → Observe → Debug → Learn → Iterate. Not a template — a map that says where you are and what comes next.

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 are somewhere in the middle of a problem and cannot tell whether you are making progress or just moving. What is the loop, where are you in it, and what does it say to do next?

The situation

Three days into the store you have a running server, a half-finished cart, a note that says "look into Stripe", and an uneasy feeling. You have been busy the whole time and you cannot say what you know now that you did not know on the first morning.

The reflex

Keep going. Momentum is real: the code is compiling, the cart is nearly done, and stopping to "step back" feels like the thing people do when they are avoiding work. If the next task is visible, do the next task.

Why it stalls

The next task is always visible because tasks are infinite — there is always a component to tidy, a library to try, a page to style. Visible tasks say nothing about whether the problem is closer to solved.

What the reflex produces — and fails to produce
  • The next task is always visible because tasks are infinite — there is always a component to tidy, a library to try, a page to style. Visible tasks say nothing about whether the problem is closer to solved.
  • Without a map, every step is judged by whether it produced something, and every step produces something. The cart has been rewritten twice, and neither rewrite answered a question anyone had.
  • Unknowns are met in the order the code reaches them, not the order of risk. "Look into Stripe" has been on the note for three days because the cart got there first; the riskiest part of the store has had the least attention.
  • When something breaks there is no evidence trail. The last three changes were all "improvements", none was an experiment, and 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.

  • Carry the loop as a map of thirteen positions: Problem, Understand, Requirements, Constraints, Unknowns, Decomposition, Smallest Useful Step, Model, Experiment / Implement, Observe, Debug, Learn, Iterate. At any moment you are at one of them, and the position — not your mood — says what the next move is.
  • Locate yourself by asking what you would need to produce next. If you cannot say what the thing is, you are before Understand. If you cannot say what it must do, you are at Requirements. If there is a word you cannot research, you are at Unknowns. If you cannot say what to build first, you are at Decomposition or Smallest Useful Step. If you have built something and cannot say what it showed, you skipped Observe.
  • Distinguish motion from progress by the output of each position. Each stage has a characteristic product — a statement, a list, a question, a tree, a slice, a model, an observation, a hypothesis, a lesson — and a stage without its product has not been done, however many hours went in.
  • Treat the loop as a loop, not a march. Iterate returns to Problem with more evidence; Debug sends you back to Model with a hypothesis; a discovered unknown drops you from Implement back to Unknowns. Going backwards is the method working, not failing.

The loop as positions, each with a product

The pipeline below lists every position with what it produces and the characteristic way it is skipped. The middle column is the useful one: a position whose product does not exist has not been visited, whatever the calendar says. The third column is how motion impersonates that position.

The problem-solving loop
  1. 1
    Problem

    A statement of what is being asked, in the requester's words.

    fails by Starting from the request as a task list.

  2. 2
    Understand

    One paragraph: what the thing is, who uses it, what it is for.

    fails by Reading for days and producing no paragraph.

  3. 3
    Requirements

    What it must do, and what it must never do.

    fails by The happy path only; failures "later".

  4. 4
    Constraints

    Time, users, data, known technology, budget, legal — the walls.

    fails by Assuming the constraints of the tutorial.

  5. 5
    Unknowns

    Every vague word turned into a question with an experiment.

    fails by A list of worries with no verbs.

  6. 6
    Decomposition

    A tree whose leaves are testable.

    fails by Frontend / backend / database.

  7. 7
    Smallest Useful Step

    The slice that touches every layer and answers the most.

    fails by A week on one layer.

  8. 8
    Model

    What you expect to happen, and why — pseudocode, a sketch, a prediction.

    fails by Typing before predicting.

  9. 9
    Experiment / Implement

    The smallest thing that can be observed.

    fails by A change too big to attribute.

  10. 10
    Observe

    What actually happened, written down.

    fails by "It works" without looking.

  11. 11
    Debug

    Hypothesis, evidence, narrowing — when Observe disagrees with Model.

    fails by Editing the last thing touched.

  12. 12
    Learn

    What you know now, and which requirement or assumption it changed.

    fails by Moving on.

  13. 13
    Iterate

    Back to Problem with more evidence and a smaller unknown list.

    fails by Adding the next feature instead.

The loop is entered at whichever position the problem demands and left when the next question is clear. Most real cycles visit five or six positions, not thirteen.

One pass, on the store's inventory

Here is the loop run once, on one requirement, ordered as it actually happened. The order device carries an alternative because it must: on a store where the team had already built inventory elsewhere, Model would be skipped and Implement would start from the known answer.

Never sell more than exists
  1. 1
    State the requirement and the invariant: stock never goes below zero

    because Everything downstream tests against this sentence; without it the experiment has no pass condition (What Must Never Break).

  2. 2
    Sharpen the unknown: does a plain read-then-write oversell under two concurrent checkouts?

    because This is the only part nobody on the team could answer from experience, so it carries the risk.

  3. 3
    Model: predict that an unconditional update oversells and a conditional one rejects the loser

    because A prediction written before the experiment is what makes the result evidence instead of an anecdote (Prediction Before Execution).

  4. 4
    Experiment: one row, two concurrent decrements, both ways

    because It is the smallest thing that can be observed and it needs no store around it.

  5. 5
    Observe and learn: the invariant belongs in the database

    because The result changes the decomposition — the check is not an application-level step any more (Invariants in an Online Store).

  6. 6
    Iterate: the requirement gains "checkout tells the losing customer why"

    because The experiment surfaced a user-facing case the original sentence did not contain.

a different valid order Implement-first: build the checkout with a naive decrement, then write the concurrency test and watch it fail. A team confident in its test harness would choose this because the failing test becomes the specification; it costs a little rework and buys a regression test for free.

Where the loop gets skipped, and what it looks like

Each row below is a way of leaving the loop while appearing to be in it. The symptom column is what a colleague would notice; the response column is the position to return to.

Motion that impersonates a position
TriggerSymptomCauseResponse
Understand skippedEveryone on the team describes the store differently; the cart is "obviously" per-user to one person and per-session to another.No one-paragraph statement exists to disagree with.Write the paragraph; make the disagreement explicit; ask the founder (Problem Framing).
Unknowns skippedThe same word — "payments", "realtime" — appears on every status update, unchanged.The unknown never became a question, so it cannot be researched or finished.Sharpen it into a question with an experiment (Unknown to Specific Question).
Smallest step skippedThe database schema is complete and nothing has rendered a page.Work is organised by layer, so nothing is testable end to end.Cut a slice through every layer for one feature (Vertical Slices).
Observe skipped"It works" — and the first real user finds it does not.The result was assumed from the absence of errors.Write what was observed, against what was predicted.
Learn skippedThe same surprise happens twice.The finding never changed a requirement or an assumption.Record what changed and why in the notebook (The Decision Journal).

How to do it

Most important first.

  • Write the thirteen positions somewhere you will see them, and at the end of each session mark which one you are at. If the mark has not moved in a day, ask what product the current position is waiting for.
  • Before starting any piece of work, name the position it serves. "Building the cart" serves Implement; "does Stripe confirm payment synchronously?" serves Unknowns. Work that serves no position is motion.
  • Make every Experiment / Implement step small enough that Observe is possible the same day. A step whose result cannot be seen for a week is several steps (Short Feedback Loops).
  • When something breaks, say which position you are returning to and with what hypothesis, rather than editing the last thing you touched (Debugging Is Problem Solving).
  • Once a cycle, do Learn explicitly: write what you know now that you did not, and which requirement or assumption it changed (Iterative Development).

Worked on a concrete problem

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

  • Locating the store on the map. "I cannot say what the store must do about a failed payment" → that is a Requirements gap, not an Implement problem, and the cart rewrite is not addressing it. "I do not know what Stripe sends back" → an Unknown, with a small experiment attached. Two positions were being skipped by the visible work.
  • One pass through the loop, on inventory. Problem: two customers might buy the last unit. Understand: stock is a count that decrements at checkout. Requirement: never sell more than exists. Constraint: one database, one region. Unknown: does a plain update under concurrency oversell? Decomposition: the decrement, the check, the response to the loser. Smallest step: one row, two concurrent decrements. Model: "a conditional update where stock is greater than zero will fail for one of them". Experiment: run it. Observe: one row went negative without the condition; with it, one request was rejected. Debug: nothing to debug — the model held. Learn: the invariant lives in the database, not in the application. Iterate: the requirement now says "checkout rejects, with a clear message, when stock is gone".
  • The chat app, going backwards on purpose. Implement was under way on message delivery when a question surfaced: what does "read" mean with two devices? That is an Unknown discovered late. The loop says: stop Implement, sharpen the question, run the smallest experiment — two sessions, one message, mark it read in one — and return to Requirements with the answer, before more delivery code assumes one device.

How you know it worked

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

  • You can say which of the thirteen positions you are at, and the answer is not "somewhere in the middle".
  • Each recent piece of work has a position it served and a product it produced — a question sharpened, a slice that runs, an observation written down.
  • Going backwards is something you do deliberately and can explain, rather than something that happens when you get stuck.
  • The riskiest unknown is being answered in proportion to its risk, not to how soon the code reaches it.

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 of the thirteen positions am I at right now, and what is its product?
  • ?What did the last thing I built show me — and did I actually look?
  • ?Which unknown am I avoiding because the code has not reached it yet?
  • ?Which position should I go back to, with what hypothesis?

What can go wrong

How the move itself fails
  • The loop becomes a checklist marched through once, top to bottom, with a document at every stage. A requirements phase, then a decomposition phase, then a build phase — that is the waterfall the loop exists to replace. The positions are places you return to, not gates you pass.
  • Locating yourself becomes the work. Some people would rather classify their state than change it; if you have named the position and its product, the next move is to produce the product.
  • The loop is applied at one grain only. It works at the scale of a project and at the scale of a single function, and using it at only the large scale means the small decisions are still made by reflex.
  • Observe is skipped because the result "obviously worked". The step that turns implementation into evidence is the one most often dropped, and it is the one Debug and Learn depend on.
What the move costs
  • Naming the position costs attention every session, and on a small, familiar problem that attention is wasted; an experienced engineer runs the loop without narrating it.
  • A loop that insists on Observe after every step slows the steps down. The alternative is faster and blind, and the choice depends on how expensive being wrong is here.
  • Going backwards deliberately means discarding work, and discarded work is visible to whoever is counting output.
Misreads
  • "The thirteen steps are the method; do them in order." They are a map, not a route. A problem you understand well starts at Decomposition; a bug starts at Observe; a new requirement starts at Requirements. The order is the order of dependency, not the order of visits.
  • "Understand means read everything first." Understand produces a one-paragraph statement of what the thing is. Reading everything is one way to fail to produce it.
  • "If I follow the loop, I will not get stuck." You will get stuck; the loop tells you where you are stuck, which is what makes the stuckness a question instead of a feeling.

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 positions apply to any engineering problem at any grain, from a product to a function; what changes is how many of them a given problem visits and how long each takes.
  • SIMPLIFIEDThirteen named positions is a teaching model. Real work blurs Model into Implement, runs Observe continuously, and revisits Requirements while debugging; the names are there to make skipped steps visible, not to describe how work is really segmented.
  • CONTESTEDSome experienced practitioners hold that naming stages at all is harmful: that good engineers work by taste and tight feedback, that any explicit loop turns into ceremony under management pressure, and that the honest description of expert practice is "build the smallest thing, look, adjust" with no intermediate vocabulary. That view is strongest for small teams of experts on familiar problems, where the loop is internalised and naming it adds nothing but overhead.
  • ILLUSTRATIVEThe three days, the store, the note about Stripe and the inventory experiment are invented to show the shape of the loop; no real project is described.

Where the depth lives

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

Observability & Performancemeasure-before-optimizing
Further
  • The capstone at /thinking/capstone runs this loop ten times on the store with feedback only; the loop is the scaffolding of every stage.