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.
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?
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.
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.
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.
- 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.
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.
- 1Problem
A statement of what is being asked, in the requester's words.
fails by Starting from the request as a task list.
- 2Understand
One paragraph: what the thing is, who uses it, what it is for.
fails by Reading for days and producing no paragraph.
- 3Requirements
What it must do, and what it must never do.
fails by The happy path only; failures "later".
- 4Constraints
Time, users, data, known technology, budget, legal — the walls.
fails by Assuming the constraints of the tutorial.
- 5Unknowns
Every vague word turned into a question with an experiment.
fails by A list of worries with no verbs.
- 6Decomposition
A tree whose leaves are testable.
fails by Frontend / backend / database.
- 7Smallest Useful Step
The slice that touches every layer and answers the most.
fails by A week on one layer.
- 8Model
What you expect to happen, and why — pseudocode, a sketch, a prediction.
fails by Typing before predicting.
- 9Experiment / Implement
The smallest thing that can be observed.
fails by A change too big to attribute.
- 10Observe
What actually happened, written down.
fails by "It works" without looking.
- 11Debug
Hypothesis, evidence, narrowing — when Observe disagrees with Model.
fails by Editing the last thing touched.
- 12Learn
What you know now, and which requirement or assumption it changed.
fails by Moving on.
- 13Iterate
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.
- 1State 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).
- 2Sharpen 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.
- 3Model: 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).
- 4Experiment: one row, two concurrent decrements, both ways
because It is the smallest thing that can be observed and it needs no store around it.
- 5Observe 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).
- 6Iterate: the requirement gains "checkout tells the losing customer why"
because The experiment surfaced a user-facing case the original sentence did not contain.
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.
| Trigger | Symptom | Cause | Response |
|---|---|---|---|
| Understand skipped | Everyone 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 skipped | The 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 skipped | The 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 skipped | The 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.
- ?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
- 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.
- 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.
- "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.
- — The capstone at /thinking/capstone runs this loop ten times on the store with feedback only; the loop is the scaffolding of every stage.