Maintenance & Refactoring with AI

How to use AI agents to understand, refactor, and evolve legacy and brownfield codebases safely.

โ† Back to AI-SDLC main site

๐Ÿ” Understanding Existing Code

/explain โ€” Your First Move

Before modifying unfamiliar code, always explain first:

Command Use Case
/explain on selection Understand what selected code does
/explain #file Get overview of an entire file's responsibilities
@workspace + question Explore architecture across the project
/explain on error Understand a stack trace or build error

Example prompt:

Explain what this stored procedure does, what calls it, and what would break if I changed the return type.

The Steel Thread Pattern

When refactoring brownfield code, pick the narrowest vertical slice through your system:

  1. Identify โ€” Find the narrowest user flow touching every layer (e.g., "add to cart" from UI โ†’ Controller โ†’ Service โ†’ DB)
  2. Research โ€” Use @workspace and LSP (find-references, type-hierarchy) to map every caller and dependency
  3. Plan โ€” In a fresh context, feed research.md to produce an ordered extraction plan with verification commands
  4. Implement โ€” Follow the plan with harnesses running: compiler + unit tests + E2E after every change
  5. Verify โ€” The "physics beat law" moment: if the compiler or tests force a deviation from the plan, that's correct behaviour
Key insight:

Each phase gets a fresh AI context with only the artefacts from the previous phase. This prevents the agent from hallucinating based on stale conversation context.

๐Ÿ”ง Refactoring & Evolution

Agent Mode Refactoring

Multi-file refactoring with test preservation. Three example prompts:

Service extraction:

Refactor: extract the email notification logic from OrderController into a NotificationService. Update all callers. Don't change behaviour.

Pattern migration:

Migrate all direct DbContext calls in the Controllers folder to use the repository pattern. Follow the same structure as ProductRepository. Update tests.

Code modernisation:

Update this class to use C# 12 features: file-scoped namespaces, primary constructors where appropriate, and collection expressions. Keep all existing tests passing.

Dependency Updates

How Dependabot + Copilot work together:

  1. Enable Dependabot in repo Settings โ†’ Code Security
  2. Dependabot opens PRs for outdated dependencies automatically
  3. Add Copilot as reviewer โ€” it checks for breaking API changes
  4. Copilot suggests migration steps if the update requires code changes

Tip: Combine Dependabot PRs with agent mode. If a dependency update breaks something, ask agent mode: "Fix the build failures caused by the upgrade to [library] v[X]. Check the migration guide at [URL]."

The Safety Net

Before any refactoring, ensure your harness:

Layer What It Catches How to Set Up
Compiler / type checker Type errors, missing references Already there โ€” just build
Unit tests Logic errors, calculation drift /tests to generate baseline coverage
E2E tests (Playwright) Behavioural changes, broken flows Agent mode: "Write Playwright tests for the [X] flow"
Linter / analyser Style drift, code smells Configure in CI pipeline

Self-Paced Resources

๐Ÿ”—
Modernize Legacy Code with Copilot
Interactive course on modernizing existing code
๐Ÿ”—
Build Apps with Agent Mode
Learn how to use coding agents for multi-file changes
๐Ÿ”—
Code Maintenance with Copilot Agent
Microsoft Learn module on using agents for maintenance
๐Ÿ”—
Code Review with Copilot
Master code review practices with AI assistance