Ravindra BagaleCourses & study guides Track your progress
AI CODING ASSISTANTS · CHAPTER 5 · WORKFLOWS

How to Refactor Code with AI

Refactor means improve the shape of the code without changing what it does. With AI, you ask for clarity and tests — not a surprise rewrite of the whole app.

In short: lock behaviour with tests first, ask for a small named improvement, compare the diff, re-run tests. Ban “while you’re at it” feature changes.

Why refactor with AI

WHY

Messy helpers slow every future change. AI is fast at renaming, extracting functions and simplifying nested loops. It is also eager to change behaviour. Tests are the seatbelt.

What a safe refactor request includes

WHAT
  • Goal: “extract slugify”, “rename for clarity”, “remove duplication” — one goal.
  • Freeze behaviour: “do not change outputs; keep public names unless I say so.”
  • Scope: one file or one function first.
  • Proof: existing tests, or ask the AI to add characterisation tests before editing.

How a safe refactor flows

1 · Tests green or add characterisation tests 2 · One refactor goal name it clearly 3 · Review the diff reject behaviour changes 4 · Re-run tests must stay green 5 · Commit small easy to revert

Example: messy process() → slugify_many()

REFACTOR PROMPT (COPY)

Refactor the function below. Goal: clearer name, typed Python 3.12, use regex for slugify, skip None/blank. Do NOT change the idea of the outputs for normal strings. Add a short docstring. Return code only.

before.py
def process(d):
    o = []
    for x in d:
        if x is not None and str(x).strip() != "":
            s = str(x).strip().lower().replace(" ", "-")
            while "--" in s:
                s = s.replace("--", "-")
            o.append(s)
    return o
after.py (tested here)
import re

_SLUG = re.compile(r"[^a-z0-9]+")


def slugify_many(values: list[object]) -> list[str]:
    """Turn each non-empty value into a simple URL slug."""
    out: list[str] = []
    for raw in values:
        if raw is None:
            continue
        text = str(raw).strip().lower()
        if not text:
            continue
        slug = _SLUG.sub("-", text).strip("-")
        if slug:
            out.append(slug)
    return out
test_after.py
from after import slugify_many

def test_basic():
    assert slugify_many(["Pune City", "  ", None, "Nashik--Road"]) == [
        "pune-city",
        "nashik-road",
    ]
cd code/refactor
python3 -m pytest -q
# -> 1 passed

How to refactor step by step

HOW
  1. Get a green baseline (or write tests that pin today’s behaviour).
  2. Ask for one improvement: rename, extract, simplify — not all three plus features.
  3. Read every changed line. Reject new dependencies you did not request.
  4. Re-run tests. If behaviour shifted, either fix the prompt or discard the diff.
  5. Commit the refactor alone so reviews stay easy.
Safe askRisky ask
“Extract a helper; keep outputs the same”“Clean this up and also add caching and a CLI”
“Rename locals for clarity”“Modernise the whole package”
“Remove duplication in these two functions”“Rewrite in another language”
Rule: Agent mode can touch many files. Use Plan mode first, or limit the agent to listed paths. Keep shell approval on.

Settings tip

  1. Project rules: “Refactors must not change public behaviour without a new test.”
  2. In Cursor / Copilot Agent: point at files with @ and say “only these files”.
  3. Prefer a strong model for big design refactors; use inline/fast for rename-only work.

Quick quiz

1. What must stay the same in a refactor?

Observable behaviour (outputs and public contracts), unless you explicitly change them.

2. What do you do before editing?

Have tests green, or add characterisation tests.

3. Why commit refactors alone?

So you can revert cleanly and reviewers see one intent.

4. What is a risky prompt?

Mixing cleanup with new features in one request.

Save tokens and money

SMART AI USE

Small scope = fewer tokens and safer diffs. Do not ask five models to rewrite the same module. One good pass + tests is enough.

Save these cards

INTERVIEW CARDAI Coding

How do you refactor with AI safely?

Tests first, one goal, review the diff.
Re-run tests; no surprise features.
Ravindra Bagale · ravindrabagale.com/ai-coding
COMPARISON CARDAI Coding

Refactor vs rewrite

Refactor: same behaviour, clearer shape.
Rewrite: new design — needs new tests and a plan.
Ravindra Bagale · ravindrabagale.com/ai-coding
REVISION CARDAI Coding

Refactor in 3

Green tests.
One named goal.
Diff + re-test.
Ravindra Bagale · ravindrabagale.com/ai-coding