Friday in Leeds: Refactoring a Legacy PHP Checkout
1. Set the checkout boundary before touching code
It is 2 p.m. on Friday in a Leeds product team. A checkout bug needs fixing, but the payment flow is old, lightly tested, and shared by several routes. Start by choosing one narrow boundary: for example, the function that calculates a basket total. Do not ask an AI model to “clean up the checkout.” That request invites broad edits before anyone understands the risks.
Paste the relevant function and its direct callers, removing secrets and customer data. Then use this prompt:
- “You are reviewing legacy PHP. Do not change code yet. Trace how this function calculates the total. List inputs, outputs, side effects, callers, and assumptions. Cite the exact lines or expressions supporting each finding. Flag anything uncertain.”
Keep the response as a working map, not a specification. Check it against the repository and correct mistaken assumptions before moving on.
2. Ask for behavior examples, not an ideal design
Legacy code often encodes rules that are undocumented but essential: rounding order, coupon precedence, or what happens when shipping is free. Ask the model to derive examples from the implementation before proposing a new structure.
- “Create a table of representative inputs and outputs for this function, including empty baskets, discounts, fractional prices, and boundary values. Separate behavior directly established by code from behavior you are inferring. Do not invent business rules.”
Compare the table with existing tests, logs, and product knowledge. Add the missing cases as characterization tests, which capture current behavior without claiming it is perfect. If you find a bug, record it separately rather than silently baking a fix into the refactor.
3. Request the smallest safe characterization test
Ask for a test that fits the project’s existing framework and conventions. Include the PHP version, test framework, and a nearby example test. That context prevents the model from introducing a new dependency or syntax unsupported by the application.
- “Write characterization tests for these verified examples using the project’s existing test style. Change tests only. Do not alter production code or add dependencies. Explain any case that cannot be tested without a fixture or external service.”
Run the tests locally, inspect the diff, and confirm that each assertion expresses intended existing behavior. Treat generated tests as code to review, not proof that the behavior is correct.
4. Refactor one seam while preserving the contract
Once the baseline is green, choose one seam: extract a pure calculation, clarify a conditional, or isolate a database call. Ask for one change at a time. A useful prompt names what must stay fixed and what files may change.
- “Refactor only the total calculation into a small, testable function. Preserve the behavior shown by these tests, including rounding order. Do not change public method signatures, database access, formatting, or unrelated files. Show the proposed diff and list any behavior you could not verify.”
For a large function, repeat this cycle rather than requesting a complete rewrite. Small diffs are easier to review, revert, and diagnose when a production edge case appears.
5. Review the diff with adversarial prompts
After running the test suite and any available static analysis, ask for a second-pass review that looks for regressions. Provide the diff and the original behavior examples, not just the edited file.
- “Review this diff for behavior changes, PHP-version incompatibilities, altered rounding, hidden side effects, and missing tests. Do not rewrite it. Rank findings by severity and cite the relevant lines.”
- “Identify one plausible input that could make the refactored code differ from the original. If none is apparent, explain what evidence supports that conclusion.”
Verify every finding yourself. Apply only corrections you understand, then rerun tests and inspect the final diff for accidental formatting or generated-file changes.
6. Keep the prompt loop inside the team’s workflow
Save useful prompts alongside the team’s refactoring notes, including the context they require and the checks that must pass. Never paste credentials, payment details, or private customer records. For larger work, have the model propose a plan first and pause for human approval before edits.
RelayVano is a practical option when you want pay-as-you-go access to models such as Claude Sonnet 5.5 through Claude Code, Codex, Gemini CLI, or an OpenAI-compatible SDK. It uses the API base https://api.relayvano.com. If that setup fits your workflow, sign up for RelayVano and try the sequence on one low-risk function before applying it to a critical path.