AgentSkillsCN

refactoring

技术债务治理与代码重构工作流。适用于优化代码结构、降低复杂度、提炼抽象概念,或逐步偿还累积的技术债务时使用。

SKILL.md
--- frontmatter
name: refactoring
description: |
  Technical debt remediation and code restructuring workflow. Use when improving
  code structure, reducing complexity, extracting abstractions, or paying down
  accumulated technical debt.
license: MIT
metadata:
  author: samuel
  version: "1.0"
  category: workflow

Refactoring Skill

Structured approach to technical debt remediation. Improve code structure while maintaining behavior through incremental, safe changes.


When to Use

TriggerDescription
Guardrail ViolationsFunctions >50 lines, files >300 lines
Complexity ThresholdCyclomatic complexity >10
Code DuplicationSame logic in 3+ places
Quarterly ReviewRegular technical debt assessment
Pre-FeatureBefore adding features to messy code
Post-IncidentAfter bugs caused by confusing code

Refactoring Principles

Golden Rules

  1. Behavior Preservation: Output unchanged after refactoring
  2. Small Steps: One change at a time
  3. Test First: Ensure tests exist before changing
  4. Incremental: Commit after each successful change
  5. Reversible: Easy to roll back if issues arise

When NOT to Refactor

  • During active incident response
  • Without test coverage
  • When deadline is imminent
  • If no clear improvement goal

Prerequisites

Before starting:

  • Code compiles and all tests pass
  • Test coverage exists for target code (>60%)
  • Clear refactoring goal defined
  • Time allocated (refactoring always takes longer)
  • Git working directory is clean

Refactoring Process

code
Phase 1: Identify Candidates
    ↓
Phase 2: Impact Analysis
    ↓
Phase 3: Plan Refactoring
    ↓
Phase 4: Add Safety Net
    ↓
Phase 5: Execute Incrementally
    ↓
Phase 6: Validate & Document

Phase 1: Identify Candidates

1.1 Automated Detection

Long Functions (>50 lines):

bash
# Find functions over 50 lines (varies by language)
# Example: use linter rules or IDE features

Long Files (>300 lines):

bash
# Find files over 300 lines
find src -name "*.ts" -exec wc -l {} \; | awk '$1 > 300'
find src -name "*.py" -exec wc -l {} \; | awk '$1 > 300'

High Complexity:

bash
# Use complexity analyzers
npx escomplex src/**/*.ts
python -m mccabe src/**/*.py

1.2 Code Smells

SmellSignsPriority
Long Method>50 lines, multiple responsibilitiesHigh
Large Class>300 lines, low cohesionHigh
Feature EnvyMethod uses other class more than ownMedium
Data ClumpsSame group of variables togetherMedium
Primitive ObsessionOveruse of primitives vs objectsMedium
Switch StatementsLarge switch blocksLow
Speculative GeneralityUnused abstractionsLow

1.3 Candidate List

Document identified candidates:

markdown
## Refactoring Candidates

### High Priority
| File | Issue | Lines | Impact |
|------|-------|-------|--------|
| src/services/order.ts | Long method: processOrder | 120 → 50 | High |
| src/api/users.ts | Large file | 450 → 200 | High |
| src/utils/validation.ts | Duplication | N/A | Medium |

### Medium Priority
| File | Issue | Lines | Impact |
|------|-------|-------|--------|
| src/models/product.ts | Feature envy | N/A | Medium |
| src/services/email.ts | Complex conditionals | N/A | Medium |

Phase 2: Impact Analysis

2.1 Dependency Mapping

For each candidate, identify:

code
Target: src/services/order.ts

Dependencies (imports from):
- src/models/order.ts
- src/services/inventory.ts
- src/services/payment.ts

Dependents (imported by):
- src/api/orders.ts
- src/workers/orderProcessor.ts
- tests/services/order.test.ts

Impact radius: 5 files
Risk level: Medium

2.2 Risk Assessment

FactorLowMediumHigh
Test coverage>80%60-80%<60%
Dependents<33-10>10
Business criticalityNon-criticalImportantCritical path
ComplexitySimple renameExtract methodArchitecture change

2.3 Risk Matrix

code
              Low Effort    High Effort
            ┌────────────┬────────────┐
High Value  │  DO FIRST  │  PLAN      │
            │            │  CAREFULLY │
            ├────────────┼────────────┤
Low Value   │  QUICK WIN │  AVOID     │
            │            │            │
            └────────────┴────────────┘

Phase 3: Plan Refactoring

3.1 Choose Refactoring Technique

SmellTechniqueDescription
Long methodExtract MethodPull out logical chunks
Large classExtract ClassSplit by responsibility
Feature envyMove MethodMove to appropriate class
Data clumpsExtract Parameter ObjectGroup related params
Duplicated codeExtract to shared functionDRY principle
Complex conditionalReplace with polymorphismStrategy pattern
Long parameter listIntroduce Parameter ObjectCreate wrapper class

3.2 Step-by-Step Plan

Example: Extract Method from Long Function

markdown
## Refactoring Plan: processOrder()

### Goal
Reduce processOrder() from 120 lines to <50 lines

### Steps
1. [ ] Add characterization tests for current behavior
2. [ ] Extract validateOrder() (lines 15-35)
3. [ ] Verify tests pass
4. [ ] Commit: "refactor: extract validateOrder"
5. [ ] Extract calculateTotals() (lines 40-65)
6. [ ] Verify tests pass
7. [ ] Commit: "refactor: extract calculateTotals"
8. [ ] Extract processPayment() (lines 70-95)
9. [ ] Verify tests pass
10. [ ] Commit: "refactor: extract processPayment"
11. [ ] Extract sendConfirmation() (lines 100-115)
12. [ ] Verify tests pass
13. [ ] Commit: "refactor: extract sendConfirmation"
14. [ ] Final cleanup and documentation
15. [ ] Commit: "refactor: cleanup processOrder"

### Expected Result
- processOrder(): 120 → 25 lines
- New methods: 4
- Total lines: +10 (net increase for clarity)

Phase 4: Add Safety Net

4.1 Characterization Tests

Before refactoring, add tests that capture current behavior:

typescript
describe('processOrder - characterization tests', () => {
  it('should match current behavior for valid order', () => {
    const order = createValidOrder();
    const result = processOrder(order);

    // Capture current output exactly
    expect(result).toMatchSnapshot();
  });

  it('should match current behavior for edge cases', () => {
    const edgeCases = [
      createEmptyOrder(),
      createMaxItemOrder(),
      createDiscountedOrder(),
    ];

    edgeCases.forEach(order => {
      expect(processOrder(order)).toMatchSnapshot();
    });
  });
});

4.2 Coverage Check

Ensure adequate coverage before proceeding:

bash
# Check coverage for target file
npm test -- --coverage --collectCoverageFrom="src/services/order.ts"

Minimum Coverage: 60% before refactoring (prefer >80%)

4.3 Checkpoint Commit

Create a checkpoint before starting:

bash
git add .
git commit -m "chore: checkpoint before refactoring processOrder"

Phase 5: Execute Incrementally

5.1 One Change at a Time

Bad: Multiple changes in one commit

bash
# Too much at once - hard to debug if tests fail
git commit -m "refactor: refactor entire order module"

Good: Atomic changes

bash
git commit -m "refactor(order): extract validateOrder method"
git commit -m "refactor(order): extract calculateTotals method"
git commit -m "refactor(order): extract processPayment method"

5.2 Red-Green-Refactor

For each change:

code
1. Run tests → PASS (green)
2. Make one refactoring change
3. Run tests → Should still PASS (green)
4. If FAIL (red) → Revert and try smaller change
5. If PASS → Commit
6. Repeat

5.3 Common Refactoring Patterns

See references/process.md for detailed code examples including:

  • Extract Method pattern
  • Extract Class pattern
  • Replace Conditional with Polymorphism pattern

Phase 6: Validate & Document

6.1 Final Validation

  • All tests pass
  • Coverage maintained or improved
  • No new linter warnings
  • Performance unchanged (or improved)
  • Behavior identical (check snapshots)

6.2 Document Changes

Update patterns.md (if new pattern emerged):

markdown
## Order Processing Pattern

Orders are processed through composable steps:
1. validateOrder() - Input validation
2. calculateTotals() - Price calculations
3. processPayment() - Payment handling
4. sendConfirmation() - Notifications

Create memory entry (if significant):

markdown
# Refactoring: Order Processing

**Date**: 2025-01-15
**Files**: src/services/order.ts

## Before
- Single 120-line function
- Difficult to test
- Hard to modify

## After
- 5 focused functions (<30 lines each)
- Easier to test
- Clear responsibilities

## Lessons
- Extract Method is low-risk, high-reward
- Characterization tests prevented regressions

6.3 Final Commit

bash
git add .
git commit -m "refactor(order): complete processOrder decomposition

- Extract validateOrder (20 lines)
- Extract calculateTotals (25 lines)
- Extract processPayment (30 lines)
- Extract sendConfirmation (20 lines)
- Main function now 25 lines (was 120)

No behavior changes. All tests passing."

Refactoring Catalog

Quick Reference

RefactoringWhenEffortRisk
RenameUnclear namingLowLow
Extract MethodLong functionLowLow
Extract VariableComplex expressionLowLow
InlineOver-abstractionLowLow
Extract ClassLarge classMediumMedium
Move MethodFeature envyMediumMedium
Extract Parameter ObjectLong param listMediumLow
Replace Conditional with PolymorphismComplex switchHighMedium
Replace Inheritance with CompositionRigid hierarchyHighHigh

IDE Support

Most refactorings have IDE shortcuts:

ActionVS CodeJetBrains
RenameF2Shift+F6
Extract MethodCtrl+Shift+RCtrl+Alt+M
Extract VariableCtrl+Shift+RCtrl+Alt+V
MoveDrag or F2F6
InlineN/ACtrl+Alt+N

Checklist

Before Refactoring

  • Clear goal defined
  • Tests exist (>60% coverage)
  • Impact analysis complete
  • Step-by-step plan created
  • Checkpoint committed

During Refactoring

  • One change at a time
  • Tests run after each change
  • Commit after each successful change
  • No behavior changes introduced

After Refactoring

  • All tests pass
  • Coverage maintained
  • Code cleaner (measurable)
  • Documentation updated
  • Patterns documented (if applicable)

Related Resources

  • Workflows: code-review.md, testing-strategy.md, troubleshooting.md
  • Detailed Examples: See references/process.md for code patterns
  • Refactoring Book: Martin Fowler's "Refactoring: Improving the Design of Existing Code"