top of page

Tutorial 5: Use AI for Refactoring

  • Contributor
  • 4 days ago
  • 2 min read

AI excels at mechanical transformations. Mass renames, pattern changes, language ports. Mechanical bug-fixes too.

Step 1: Identify Mechanical Refactors (10 min)

Good AI refactors:

  • Rename a function across many files

  • Update pattern (callbacks → promises → async)

  • Add types to JS

  • Change library (requests → httpx)

  • Restructure tests

  • Format / lint en masse

Bad AI refactors:

  • "Make the code better"

  • Restructure architecture

  • Break complex feature into modules

  • High-risk security-sensitive changes

Mechanical = AI strong. Subjective = AI weak.

Step 2: One-File Refactor (10 min)

Open the file. Prompt:

"Refactor this to use async/await instead of callbacks. Keep
behavior identical. Add JSDoc types."

AI generates. You diff. Apply if good.

Verify with tests.

Step 3: Multi-File Refactor (15 min)

For changes across many files:

  • Cursor's "Composer" / "Edit" modes

  • Claude Code's agent

  • Aider with --auto-commits

"Across this codebase, replace usage of the deprecated `oldFunc`
with `newFunc`. Behavior is identical but the signature changed:
oldFunc(a, b) → newFunc({a, b})"

Tool finds usages; rewrites. You review each change.

For 50+ files: faster than sed. Smarter than sed.

Step 4: Verify by Tests (10 min)

After refactor:

npm test

Tests catch regressions.

If tests are sparse: write more tests before refactoring. Tests are your safety net.

Step 5: Codemod Style (10 min)

For specific syntax transforms: AST-aware tools beat AI:

  • jscodeshift (JS)

  • ast-grep (multi-language)

  • libCST (Python)

These are deterministic. AI is probabilistic.

For high-risk mechanical refactors: AST tools. For one-offs: AI.

Step 6: Reset Your Branch (10 min)

Before mass refactor:

git checkout -b refactor-promises-to-async

After AI refactor:

git status   # see all changes
git diff     # review

If wrong:

git checkout -- .   # reset

Branch + diff is your safety. Mass changes need easy revert.

Step 7: Commit Logically (10 min)

Don't commit a 500-file refactor as one commit.

Split:

git add src/auth/*
git commit -m "refactor(auth): callbacks to async/await"

git add src/users/*
git commit -m "refactor(users): same transform"

Easier to review. Easier to bisect later.

Step 8: Watch for Subtle Differences (15 min)

AI refactors sometimes:

  • Swap argument order

  • Change error handling slightly

  • Lose comments

  • Reformat unrelated lines

Diff carefully. Especially: behavior changes hidden in syntactic noise.

For high-stakes refactor: pair-review the diff with a teammate.

Step 9: Add Tests First (10 min)

Before mechanical refactor:

# Pin behavior with tests
npm test -- --coverage

If coverage is low: write tests for the area you'll refactor.

Tests are the contract. Refactor preserves the contract.

Step 10: Don't Refactor Just Because AI Could (5 min)

AI makes refactor cheap. Tempting: refactor everything.

But:

  • Each refactor = risk

  • Each refactor = team disruption

  • Each refactor = git history complexity

Refactor for a reason:

  • Removing tech debt

  • Enabling new features

  • Performance fix

  • Maintainability

Not "because we can."

What You Just Did

AI refactoring: identify mechanical, one-file, multi-file, verify, codemods, branch+diff, logical commits, watch differences, tests first, refactor for a reason. Productive use.

Common Failure Modes

Refactor without tests. Hidden behavior change ships.

Mass commit; impossible to review. Bugs slip.

Accept AI changes blindly. Subtle bugs.

Refactor every codebase weekly. Disruption > value.

Use AI where AST tools are deterministic. Probabilistic mistakes.

bottom of page