Opus 4.6 scores 80.8% on SWE-bench Verified — the highest of any model. SWE-bench tests whether a model can autonomously resolve real GitHub issues from real open source projects. This is not a synthetic benchmark. It measures exactly what you need: can the model understand a large codebase, locate the problem, and apply a correct multi-file fix?
This lesson teaches you to use that capability for systematic refactoring — the kind of work that takes a senior engineer days and a team weeks.
Why Opus 4.6 Changes Refactoring
Traditional AI-assisted refactoring works file by file. You open a file, ask for changes, then manually propagate those changes across dependent files. With Opus 4.6:
graph LR
subgraph "Previous Models (200K context)"
A1[File A] --> B1[Refactor A]
B1 --> C1[Manually find dependents]
C1 --> D1[Fix File B]
D1 --> E1[Fix File C]
E1 --> F1[Hope nothing was missed]
end
subgraph "Opus 4.6 (1M context)"
A2[Entire Codebase] --> B2[Analyze all dependencies]
B2 --> C2[Refactor all files atomically]
C2 --> D2[Verify consistency]
end
The 1M token window means Opus 4.6 can hold your entire codebase in context while performing the refactor. It sees every import, every type reference, every test assertion — simultaneously.
Rename Refactoring at Scale
Renaming seems simple until you realize it touches types, interfaces, database column mappings, API contracts, test fixtures, documentation, and configuration files.
Example: Renaming a Core Domain Concept
Your team decides that Customer should become Account across the entire codebase. This affects:
- TypeScript interfaces and types
- Database models and migrations
- API endpoint paths and request/response schemas
- Test fixtures and assertions
- Documentation and comments
claude "Rename the domain concept 'Customer' to 'Account' across
the entire codebase. This includes:
1. All TypeScript types, interfaces, and classes
2. All variable names and function parameters
3. Database model definitions (but NOT migration files — create new migrations)
4. API route paths: /customers → /accounts
5. Test files and fixtures
6. Documentation and comments
Do NOT modify:
- Migration files in db/migrations/ (create new ones instead)
- Third-party type definitions in node_modules/
- Git history or commit messages
After making changes, run 'npm run typecheck' and 'npm run test'
to verify nothing is broken."
What Opus 4.6 Does Internally
When given this instruction with full codebase context, Opus 4.6:
- Builds a dependency graph — traces every reference to
Customeracross all files - Plans the change order — types first, then implementations, then tests
- Handles edge cases —
CustomerService→AccountService,customer_id→account_id,getCustomerById→getAccountById - Preserves semantics — does not rename
customerIdin a Stripe integration where it refers to Stripe’s concept - Generates migrations — creates a new database migration for column renames
- Runs verification — executes typecheck and tests to confirm the refactor
Interface Extraction
Extracting interfaces from concrete implementations is a refactoring pattern that improves testability and decoupling. It requires understanding every usage site to determine what the interface should contain.
claude "Extract an interface from the UserService class.
Requirements:
1. Analyze every file that imports or uses UserService
2. Determine the minimal interface needed based on actual usage
3. Create IUserService in packages/shared/src/interfaces/
4. Update all consumers to depend on IUserService instead of UserService
5. Update dependency injection container in packages/api/src/container.ts
6. Update all test files to mock IUserService instead of UserService
The interface should only include methods that are actually used
by consumers — not every public method on UserService."
The Extracted Interface
Opus 4.6 analyzes usage across the codebase and produces a minimal interface:
// packages/shared/src/interfaces/IUserService.ts
export interface IUserService {
getById(id: string): Promise<Result<User, NotFoundError>>;
getByEmail(email: string): Promise<Result<User, NotFoundError>>;
update(id: string, data: UpdateUserDTO): Promise<Result<User, ValidationError>>;
deactivate(id: string): Promise<Result<void, NotFoundError>>;
}
Note what is not in the interface: internal methods like hashPassword(), validateEmailDomain(), or syncToExternalCRM() — because no consumer calls them directly.
Dependency Inversion Across Modules
Dependency inversion — making high-level modules depend on abstractions rather than concrete implementations — is one of the hardest refactoring patterns to apply retroactively. It requires understanding the full dependency tree.
claude "Apply dependency inversion to the notification subsystem.
Current state:
- OrderService directly imports and instantiates EmailNotifier
- PaymentService directly imports and instantiates SlackNotifier
- UserService directly imports and instantiates EmailNotifier
Target state:
- Create a NotificationPort interface
- Create EmailAdapter and SlackAdapter implementing NotificationPort
- All services receive NotificationPort via constructor injection
- Wire everything in the DI container
- Update all tests to inject mock NotificationPort
Show me the dependency graph before and after."
Before and After Dependency Graph
Opus 4.6 generates the refactoring and provides the analysis:
graph TD
subgraph "Before: Direct Dependencies"
OS1[OrderService] --> EN1[EmailNotifier]
PS1[PaymentService] --> SN1[SlackNotifier]
US1[UserService] --> EN2[EmailNotifier]
end
graph TD
subgraph "After: Dependency Inversion"
OS2[OrderService] --> NP[NotificationPort]
PS2[PaymentService] --> NP
US2[UserService] --> NP
NP --> EA[EmailAdapter]
NP --> SA[SlackAdapter]
DI[DI Container] -.->|wires| EA
DI -.->|wires| SA
end
Practical Refactoring Workflow
A battle-tested workflow for large refactoring operations:
Step 1: Analysis Phase
# Always start with analysis, not changes
claude "Analyze the impact of extracting the payment processing logic
from OrderService into a dedicated PaymentService.
List:
1. Every file that would need to change
2. Every test that would need to update
3. Risk areas where the refactor could introduce bugs
4. A suggested order of operations
Do NOT make any changes yet."
Step 2: Create a Safety Net
# Create a refactoring branch
git checkout -b refactor/extract-payment-service
# Ensure all tests pass before refactoring
npm run test
Step 3: Execute in Phases
# Phase 1: Create new structures
claude "Create the PaymentService class and its interface based on
the analysis from our previous conversation. Do not modify
existing files yet."
# Phase 2: Wire the new service
claude "Update the DI container to register PaymentService.
Update OrderService to use PaymentService via injection.
Run typecheck after changes."
# Phase 3: Migrate tests
claude "Update all tests affected by the PaymentService extraction.
Run the full test suite and fix any failures."
Step 4: Verify
# Run full verification
npm run typecheck && npm run lint && npm run test
# Review the diff
git diff --stat
Handling Refactoring Failures
Opus 4.6 is the best available model for refactoring, but it is not infallible. Common failure modes and mitigations:
| Failure Mode | Detection | Mitigation |
|---|---|---|
| Missed type reference | TypeScript compiler error | Run tsc --noEmit after each phase |
| Broken circular dependency | Runtime import error | Ask Opus to analyze the import graph before changing |
| Test assertion drift | Test failures with wrong expected values | Review test changes manually — do not auto-approve |
| API contract change | Integration test failures | Lock API schemas with snapshot tests |
| Over-abstraction | Code is harder to read | Constrain: “Only extract if 3+ consumers exist” |
Cost Awareness
Large refactoring operations consume significant tokens:
Typical rename refactor (medium project):
Input: ~300,000 tokens (codebase context)
Output: ~15,000 tokens (changes + explanations)
Cost: ~$1.88 per run
Dependency inversion (large project):
Input: ~600,000 tokens
Output: ~30,000 tokens
Cost: ~$3.75 per run
Compare this to the engineering time saved: a multi-day refactoring task completed in minutes, with fewer missed references than a manual approach. The ROI is clear for any professional team.
When Not to Use Autonomous Refactoring
Opus 4.6 refactoring works best for mechanical, well-defined transformations. Avoid it for:
- Architectural redesigns — changing from monolith to microservices requires human judgment about service boundaries
- Performance optimization — requires profiling data that the model cannot generate
- Legacy code without tests — no safety net means no way to verify correctness
- Cross-repository changes — Claude Code operates within a single project context
For these cases, use Opus 4.6 as an advisor — ask for analysis and recommendations — but apply changes manually.
In the next lesson, you will learn to use Opus 4.6 for automated security auditing — the capability that discovered over 500 zero-day vulnerabilities.