PromptDev

Plan a refactor

Turns a file and a goal into refactor steps that each ship on their own, with the check that would catch every regression.

Last updated

Fill in the blanks

Assembled in your browser — nothing you type is stored or sent anywhere.

Your prompt

Plan a refactor of the code below. Goal: split this 800-line controller into testable pieces before adding the new payment flow. Break the refactor into an ordered sequence of steps, where each step is small enough to ship on its own (a mergeable PR) and leaves the code in a working state — no step that only makes sense once a later step lands. For each step, state: what changes, why it's safe to deploy alone, and the specific check (test, invariant, or manual verification) that would catch a behaviour regression introduced by that step. Keep logic changes and structural changes in separate steps — one concern per step. If part of the current behaviour is ambiguous or looks intentional-but-undocumented, flag it and ask rather than assuming which parts are safe to change. Code: [paste the file or module here]

Model-agnostic — works in Claude, ChatGPT, Gemini or any AI chat.

Why this prompt works

  • →Requiring every step to be independently shippable rules out the default failure mode: a "plan" that's really one giant untested rewrite wearing a numbered list.
  • →Naming the specific verification per step, rather than just "add tests," forces a concrete falsifiable check that would actually catch the regression that step could introduce.
  • →Separating logic changes from structural changes keeps each diff reviewable — a reviewer can tell whether a bug came from moving code or from changing what it does.

Part by part

small enough to ship on its own (a mergeable PR)
The constraint that makes the plan usable. Without a definition of small, a model produces three enormous steps that are really one rewrite in a numbered list.
leaves the code in a working state
Rules out steps that only compile once a later step lands. It is what turns a decomposition into a sequence you can stop halfway through.
the specific check (test, invariant, or manual verification)
Naming the check per step forces something falsifiable. Asking for "add tests" produces the phrase "add tests" and nothing you can act on.
Keep logic changes and structural changes in separate steps
The rule that makes each diff reviewable — a reviewer can tell whether a bug came from moving code or from changing what it does.
flag it and ask rather than assuming
An explicit escape hatch. Without one, ambiguity is resolved silently and confidently, which is worse than a question.

Common mistakes

  • Refactor this code to make it cleaner.

    Clean is undefined, so the model picks a meaning — usually renaming and extracting functions — and returns a single large diff. Nothing about it can be shipped incrementally or verified.

  • Break this refactor into steps.

    Produces a numbered list whose steps are not independently shippable. Without the working-state constraint, step three routinely depends on step five, which is the failure this prompt exists to prevent.

  • Refactor this and add tests.

    Combines two jobs, so the tests are written against the new structure and prove nothing about whether behaviour changed. The check has to be named per step and has to exist before the step lands.

Questions

Why insist every step ships on its own?

Because it is the only property that makes a refactor abandonable. A plan whose middle steps leave the code broken commits you to finishing, which is exactly the position a large refactor should never put a team in.

Does this work without pasting the code?

Poorly. The steps become generic advice about extracting functions, because there is nothing concrete to decompose. If the file is too large or sensitive to paste, describe its structure and the actual coupling rather than asking in the abstract.

Should I trust the ordering?

Treat it as a draft to argue with. The model cannot see your deployment process, your test coverage or which parts of the file are genuinely load-bearing, so the value is in having a decomposition to critique.

Why separate logic from structure?

Because a diff that moves code and changes behaviour at once is nearly impossible to review. Keeping them apart means a structural step can be verified by tests passing unchanged, which is a much stronger signal.

Related in Prompts