Iterating Without Breaking Things
A project that never changes is a project no one uses. Real applications are iterated constantly: new features added, existing features revised, performance improved, bugs fixed. Each change carries risk — something that worked before may stop working because of what you just changed. In AI-assisted development, this risk is elevated: the AI generates confident-looking code that may solve the new problem while silently breaking an existing one. Learning to iterate safely is not optional; it is the discipline that separates projects that grow from projects that collapse under their own weight.
The Concept of Regression
A regression is a failure in functionality that previously worked, caused by a change made to fix something else or add a new feature. The term comes from the Latin regressus — a going back — and it describes exactly that: the application goes backward in quality in some area even as it moves forward in another. Regressions are especially common in AI-assisted projects for a specific reason: when you ask the AI to modify a file, it rewrites the relevant section — and sometimes adjacent sections — based on its understanding of what you asked for. If your description was incomplete, the AI may change something you did not intend to change. A developer who does not review the full diff (the complete set of changes between the old version and the new version) may not notice until a user reports that a feature that worked last week is now broken. Diff (definition): a structured comparison of two versions of a file or set of files, showing exactly which lines were added, removed, or modified. Reading the diff is the primary method for verifying that a change does what was intended and nothing more. The review phase of every build loop should always include reading the diff. This is the mechanical act of verifying scope: does the set of changes match the set of changes you asked for? If the AI changed three lines you did not ask it to change, those three lines need scrutiny.
The diff is the ground truth of what changed. Reading the description of what you asked for and the output the AI produced is not sufficient — the description may match the new feature while hiding an unintended change. Reading the diff line by line is the only way to be certain the change is exactly what was intended. Make this a non-negotiable habit on every iteration.
Four practices make iteration safer: 1. Small, focused changes: make one change at a time. A change that adds a new feature AND refactors an existing module AND updates the database schema is three changes — each of which can introduce regressions independently. Breaking it into three separate loops means three separate diffs, each narrow enough to review completely. 2. Test before you change: before modifying a working feature, understand its current behavior precisely. Write down (or record) the inputs you give it and the outputs you expect. After the change, repeat the same inputs and verify the same outputs. This is manual regression testing — not automated, but far better than no testing at all. 3. Keep a running list of things to verify: as you make changes, record which existing features might be affected. If you add a new field to the database schema, the list includes: does the Create route still work? Does the Read route still return the new field? Does the existing data (which lacks the new field) cause any errors? 4. Prompt for minimal changes: when asking the AI to make a change, add 'modify only what is necessary for this change; do not refactor, rename, or reformat anything else' to your prompt. This does not guarantee the AI will comply, but it reduces the probability of unintended changes — and makes the diff easier to review when you check.
Match each iteration practice to the problem it prevents.
Terms
Definitions
Drag terms onto their definitions, or click a term then click a definition to match.
Handling Unexpected Breakage
Despite careful iteration, things break. The question is not whether you will encounter unexpected breakage but how you will handle it when you do. The first step is isolation: determine which change caused the breakage. If you have been making small, focused changes, this is straightforward — the most recent change is the most likely cause. If you have been making large, multi-part changes, isolation is much harder. The second step is characterization: describe the breakage precisely. What input causes it? What output do you get? What output did you expect? A precise bug description is the most effective input you can give an AI for debugging: 'Before this change, GET /expenses?month=2026-04 returned a JSON array. After adding the user_id column, it returns an empty array. The database has five expense records for this user.' This description gives the AI all the context it needs to diagnose the problem correctly. The third step is the fix loop: apply the same describe-generate-review-refine discipline to the fix that you applied to the original feature. Do not accept the first suggested fix without reviewing it — a fix that introduces a new regression is worse than the original problem.
'It does not work' is not a bug description. 'When I submit the expense form with a valid amount and category, the page reloads but the expense does not appear in the list, and the browser console shows: TypeError: Cannot read properties of undefined (reading map)' is a bug description. The second version gives the AI (and you) actionable diagnostic information. Investing thirty seconds in writing a precise description saves minutes of diagnostic loops.
A developer asks the AI to add a new filter to a search feature. The AI returns modified code. Without reading the diff, the developer deploys the change. Two days later, a user reports that deleting a record no longer works. What practice would most likely have caught this?
Why does making one change at a time reduce the difficulty of debugging regressions?
Regression Hunt
- Below is a description of a change made to the expense tracker and a list of existing features. Your task is to perform a 'regression audit' — identify every existing feature that could potentially be broken by the change, and for each one, write the specific input you would test and the output you would expect.
- The change: A new field, 'recurring' (a boolean, default false), was added to the expenses table. The Create route was updated to accept and store this field. The Read route was updated to include this field in its response.
- Existing features to audit:
- A. The expense list page, which displays all expenses for the current month.
- B. The category summary, which totals amounts by category.
- C. The delete feature, which removes an expense by id.
- D. Old expense records in the database that were created before the 'recurring' field existed.
- For each feature, write: 'This feature could break because ___, so I would test by ___ and expect ___.'
- If you believe a feature cannot be affected, explain why.