In Refactor Anytime, I wrote that AI refactoring tends toward responsibility separation, increasing file count. If you want DRY consolidation, you need scope management.
But what does "scope management" actually look like in practice?
After several failed attempts, I arrived at a simple protocol that makes AI consolidate code without micromanagement.
The Problem
When you say "refactor this," AI defaults to responsibility separation.
"Refactor this namespace"
↓
AI splits by responsibility
↓
More files, clearer boundaries
↓
Context size increases
↓
Worse than before
I hit this directly.
A namespace was growing too large, so I asked AI to refactor it.
The result was more files, more indirection, and an even larger context window.
To force DRY consolidation, I had to micromanage:
- specify exact files
- point to specific lines
- explain which patterns were “the same”
That doesn’t scale.
First Attempt: Policy Declaration
My first idea was to declare a refactoring policy upfront:
Refactoring Policy:
- Priority: DRY (consolidate duplicates)
- Prefer integration into existing files
- Minimize responsibility separation
- Do not increase file count
AI understood the policy.
Then it asked:
“Which files and which duplicates do you want to consolidate?”
Back to micromanagement.
The policy told AI how to refactor—but not what to look for.
The Missing Piece: Phases
The breakthrough was realizing this:
AI needs explicit permission—and a workflow—to discover refactoring targets on its own.
Policies define direction.
Phases define agency.
Without phases, AI waits for human-specified targets.
With phases, AI can take initiative safely.
The DRY-First Refactoring Protocol
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
DRY-First Refactoring Protocol
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【Phase 1】Discovery
List the following:
- Files with similar processing
- Duplicate code patterns
- Consolidation candidates
【Phase 2】Proposal
For each discovered duplicate:
- Where to consolidate
- How to integrate
(Do not implement yet)
【Phase 3】Implementation
After "approved", implement.
【Priority】
1. DRY (consolidate duplicates)
2. Integration into existing files
3. Responsibility separation (minimum necessary)
The Result
With this protocol, AI responded like this:
Phase 1: Discovery
- Similar processing:
SelectBuilder.cs,ProjectionBuilder.cs,HavingBuilder.cs- Common: SQL operator mapping, constant stringification
- Similar processing:
JoinBuilder.cs,GroupByBuilder.cs,HavingBuilder.cs- Common: Lambda / MemberExpression extraction
- Consolidation candidates:
GetSqlOperatorandVisitConstant→ unify- Lambda extraction → consolidate in
BuilderUtil
Phase 2: Proposal
Consolidate operator and constant processing
- Target:
BuilderUtil.cs- Add
GetSqlOperator(ExpressionType)- Add
FormatConstant(ConstantExpression)- Replace implementations in Select/Projection/Having builders
Consolidate Lambda/Member extraction
- Target:
BuilderUtil.cs- Add
ExtractLambda(Expression)- Add
UnwrapLambdaBody(Expression)- Replace custom implementations across builders
Reply “approved” to proceed to Phase 3.
I replied: approved.
AI implemented the consolidation.
No micromanagement.
Measured Impact
| Metric | Before | After | Change |
|---|---|---|---|
| Files | 7 | 7 | 0 |
| Lines | 1559 | 1479 | -5.1% |
The goal wasn’t dramatic reduction.
The goal was consolidation without expansion.
That goal was met.
Why This Works
| Element | Effect |
|---|---|
| Explicit phases | Prevents premature implementation |
| Discovery first | AI finds targets autonomously |
| Proposal gate | Human reviews intent, not code |
| “Approved” trigger | Clear responsibility handoff |
The key insight:
AI can discover duplication patterns—if you explicitly ask it to.
Without discovery, AI waits.
With it, AI acts.
Before and After
Before (no protocol):
"Refactor this"
→ AI separates by responsibility
→ File count increases
→ Human intervenes with specific instructions
→ Micromanagement
After (with protocol):
"Refactor this" + protocol
→ AI lists duplicates
→ AI proposes consolidation
→ Human approves
→ AI implements
→ No micromanagement
When to Use This Protocol
Use it when:
- A namespace or module is growing too large
- You sense duplication but don’t want to enumerate it
- Previous refactoring increased complexity
- Context size is becoming a bottleneck
Don’t use it when:
- Responsibility separation is the actual goal
- The codebase is small enough for direct instruction
- You already know exactly what to consolidate
The Deeper Lesson
AI’s default behavior isn’t wrong.
Responsibility separation is a valid refactoring strategy.
The problem is implicit defaults.
When you don’t specify direction, AI chooses one.
This protocol makes intent explicit:
- What to look for (duplication)
- When to stop (proposal before implementation)
- How to prioritize (DRY over separation)
This isn’t about controlling AI.
It’s about aligning AI’s initiative with your goals.
Summary
| Problem | Structural Fix |
|---|---|
| AI defaults to separation | Declare DRY priority |
| Policy alone causes questions | Add discovery phase |
| Risk of unwanted changes | Add proposal gate |
| Micromanagement burden | Let AI discover first |
Three phases. One approval. No micromanagement.
This article is part of the “Beyond Prompt Engineering” series, exploring structural—not ad-hoc—approaches to AI-assisted development.
Top comments (0)