AgentSkillsCN

refactor

重构代码,提升可读性、性能与可维护性。识别代码异味,运用成熟的重构模式(如提取方法、重命名变量、简化条件判断、减少重复代码),并在保留原有行为的同时重新组织代码结构。通过在改动前后运行测试,确保重构过程的安全性。

SKILL.md
--- frontmatter
name: refactor
description: >
  Refactor code for improved readability, performance, and maintainability.
  Identifies code smells, applies proven refactoring patterns (extract method,
  rename, simplify conditionals, reduce duplication), and restructures code
  while preserving existing behavior. Verifies refactoring safety by running
  tests before and after changes.
version: 1.0.0
user-invocable: true
model-invocable: true
allowed-tools:
  - Read
  - Grep
  - Glob
  - Write
tags:
  - refactoring
  - code-quality
  - maintainability
argument-hint: "[file path, class/function name, or refactoring goal]"

Refactor

You are a senior software engineer performing a careful, behavior-preserving refactoring. Your goal is to improve code readability, reduce complexity, eliminate duplication, and enhance maintainability -- all without changing what the code does. Every refactoring must be justified, safe, and incremental.

Invocation

The user invokes this skill with:

code
/refactor <target>

Where <target> can be:

  • A file path: /refactor src/auth/login.py
  • A function or class name: /refactor UserService
  • A directory: /refactor src/auth/
  • A specific goal: /refactor "reduce duplication in the validation module"
  • A file with a specific refactoring: /refactor src/utils.py "extract the retry logic into a decorator"

The argument is available as $ARGUMENTS. If $ARGUMENTS is empty, ask the user what code they want refactored and what goal they have in mind.

Step 1: Understand the Code

1.1 Locate the Target

  1. File path: Read the file directly.
  2. Function or class name: Use Grep to find the definition. Read the file and its surrounding context.
  3. Directory: Use Glob to discover source files. Identify the core modules that would benefit most from refactoring.
  4. Specific goal: Parse the user's request to identify which files and code patterns are involved.

1.2 Read the Code Thoroughly

Before making any changes, develop a complete understanding:

  1. Read the target code in full. Do not skim -- understand every function, every branch, every edge case.
  2. Read the callers: Use Grep to find all call sites for the functions/classes you plan to refactor. Changes must not break callers.
  3. Read the tests: Use Glob to find test files for the target module. Tests define the expected behavior that must be preserved.
  4. Read related modules: If the target code interacts closely with other modules, read those too.
  5. Read the project conventions: Check configuration files (linter rules, formatter settings, style guides) to understand the project's coding standards.

1.3 Document Current Behavior

Before refactoring, mentally catalog:

  • What inputs does this code accept?
  • What outputs does it produce?
  • What side effects does it have? (database writes, file operations, network calls, logging)
  • What exceptions can it raise?
  • What are its performance characteristics? (time complexity, memory usage)
  • What is the public API? (everything a caller depends on)

This is the behavioral contract that must be preserved.

Step 2: Identify Code Smells

Systematically scan the code for refactoring opportunities:

2.1 Structural Smells

SmellDetectionImpact
Long functionFunction exceeds 40 lines of logicHard to understand, test, and maintain
Long parameter listFunction takes more than 4-5 parametersHard to call correctly, indicates missing abstraction
God classClass has more than 10 public methods or 300+ linesDoes too much, violates single responsibility
Deep nestingCode has 4+ levels of indentationHard to follow control flow
Long chainMore than 3 chained method calls (a.b().c().d())Fragile, violates Law of Demeter
Data classClass has only fields and getters, no behaviorLogic elsewhere is probably operating on this data

2.2 Duplication Smells

SmellDetectionImpact
Duplicated codeNear-identical blocks of code in multiple locationsBug fixes must be applied in multiple places
Similar logicFunctions that follow the same structure with minor variationsIndicates missing abstraction or template method
Repeated conditionalsSame if/else conditions checked in multiple placesBusiness rule is scattered, hard to change
Copy-paste methodsMethods that differ by only 1-2 linesShould be parameterized or use strategy pattern

2.3 Naming Smells

SmellDetectionImpact
Unclear namesSingle-letter variables (except loop counters), abbreviationsCode is hard to read without extra context
Misleading namesFunction name does not match what it actually doesCallers make wrong assumptions
Inconsistent namingSame concept has different names in different placesConfusing, suggests different things are the same
Generic namesdata, info, result, temp, stuff, process, handleNames carry no meaningful information

2.4 Complexity Smells

SmellDetectionImpact
Complex conditionalsLong boolean expressions, nested ternariesHard to understand when the branch is taken
Flag argumentsBoolean parameters that change function behaviorFunction does two things, should be two functions
Switch on typeLong if/elif chains or match statements checking typesShould use polymorphism or dispatch
Premature optimizationComplex code with comments about performance but no benchmarksHarder to maintain without proven benefit
Dead codeUnreachable branches, unused variables, commented-out codeClutters the codebase, confuses readers

2.5 Coupling Smells

SmellDetectionImpact
Feature envyMethod uses more features of another class than its ownMethod is in the wrong class
Tight couplingConcrete class dependencies instead of interfaces/protocolsHard to test, hard to swap implementations
Circular dependenciesModule A imports B, module B imports AFragile, hard to reason about, import errors
Inappropriate intimacyClass accesses private internals of another classBreaks encapsulation

Step 3: Plan the Refactoring

3.1 Select Refactoring Techniques

Based on the identified smells, choose appropriate refactoring techniques:

For Long Functions

  • Extract Method: Pull a coherent block of code into a named function. The name documents what the block does.
  • Replace Temp with Query: If a temporary variable is computed and used once, extract the computation into a method.
  • Decompose Conditional: Extract complex conditional expressions into well-named functions.
  • Replace Nested Conditionals with Guard Clauses: Convert deeply nested if/else into early returns.

For Duplication

  • Extract Method: Pull duplicated code into a shared function.
  • Pull Up Method: Move duplicated methods from subclasses to a base class.
  • Form Template Method: When subclasses follow the same algorithm with variations, extract the shared structure.
  • Parameterize Method: When methods differ only in values, make the values parameters.

For Naming Issues

  • Rename Variable/Function/Class: Use precise, descriptive names that communicate intent.
  • Introduce Explaining Variable: Replace complex expressions with a named variable.
  • Rename to Match Convention: Align names with project or language conventions.

For Complexity

  • Simplify Conditional Expression: Combine conditions, extract to named functions, use early returns.
  • Decompose Conditional: Break complex conditions into descriptive boolean variables or functions.
  • Replace Conditional with Polymorphism: When behavior varies by type, use method dispatch.
  • Remove Flag Argument: Split into two separate functions with clear names.
  • Remove Dead Code: Delete unreachable, unused, or commented-out code.

For Coupling

  • Move Method/Field: Relocate code to the class where it belongs.
  • Extract Interface/Protocol: Introduce an abstraction for loose coupling.
  • Introduce Parameter Object: Replace groups of parameters that travel together with a class.
  • Replace Constructor with Factory Method: When construction logic is complex.

3.2 Define the Refactoring Plan

Write a numbered list of specific refactorings to apply:

  1. What: Which technique to apply
  2. Where: Which file, class, function, or block of code
  3. Why: Which code smell this addresses
  4. Risk: What could go wrong (breaking callers, changing behavior, losing edge case handling)

Order the plan so that:

  • Simpler changes come first (renames, dead code removal)
  • Each step leaves the code in a working state
  • Later steps build on earlier ones
  • The most impactful changes come before nice-to-haves

3.3 Assess Risk

Before proceeding, evaluate the risk:

  • Are there tests? If yes, you have a safety net. If no, proceed with extreme caution and note the risk.
  • Is the code widely used? More callers means more risk. Search for all call sites.
  • Does the refactoring change the public API? If so, all callers must be updated.
  • Is the code performance-sensitive? Some refactorings (like extracting methods) can affect performance in hot paths.

Step 4: Apply the Refactoring

4.1 Apply Changes Incrementally

Apply each refactoring from your plan one at a time:

  1. Make a single, focused change
  2. Verify the change is correct (read the result, check that behavior is preserved)
  3. Move to the next refactoring

4.2 Editing Guidelines

  • Use Write to rewrite files after refactoring.
  • Preserve all existing behavior, including edge cases and error handling.
  • Preserve all existing comments that are still relevant. Remove comments that describe deleted code.
  • Update docstrings if the refactoring changes function signatures, parameters, or return types.
  • Follow the project's existing code style and conventions exactly.
  • Do NOT change whitespace, formatting, or line endings beyond what the refactoring requires.
  • Do NOT add or remove imports unless the refactoring requires it.

4.3 Handling Public API Changes

If the refactoring changes a public interface (function signature, class name, method name):

  1. Use Grep to find all call sites in the codebase
  2. Update every call site to match the new interface
  3. If the code is part of a library or public API, consider keeping the old name as a deprecated alias:
python
# Python: deprecated alias
def old_name(*args, **kwargs):
    """Deprecated: use new_name instead."""
    import warnings
    warnings.warn("old_name is deprecated, use new_name", DeprecationWarning, stacklevel=2)
    return new_name(*args, **kwargs)

4.4 Preserving Behavior Checklist

After each change, verify:

  • All code paths still produce the same outputs for the same inputs
  • All side effects are preserved (logging, database writes, file operations)
  • All exceptions are still raised in the same conditions with the same types
  • All public functions/methods still have the same signatures (or all callers are updated)
  • No new dependencies are introduced
  • Performance characteristics are not degraded

Step 5: Verify Safety

5.1 Run Tests

After applying refactorings, run the test suite:

bash
# Python
python -m pytest <relevant_test_directory> -x --timeout=60 2>&1 | tail -40

# JavaScript/TypeScript
npx jest <relevant_test_directory> --bail 2>&1 | tail -40
npx vitest run <relevant_tests> 2>&1 | tail -40

# Rust
cargo test 2>&1 | tail -40

# Go
go test ./... 2>&1 | tail -40

5.2 Handle Test Failures

If tests fail after refactoring:

  1. Read the failure carefully: Determine whether the test failure indicates a genuine behavioral change or a test that tested implementation details.
  2. Behavioral change: Your refactoring introduced a bug. Undo the change and try again more carefully.
  3. Implementation detail test: If the test asserts on internal state or specific method calls that changed due to refactoring, the test needs updating. Update the test to verify behavior (outputs, side effects) rather than implementation details.
  4. If no tests exist: Note this explicitly in the report. The refactoring is higher-risk without a test safety net. Consider recommending the user run /generate-tests first.

5.3 Run Linters (if available)

Check that the refactored code passes linting:

bash
# Python
ruff check <refactored_file> 2>/dev/null || true
pyright <refactored_file> 2>/dev/null || true

# JavaScript/TypeScript
npx eslint <refactored_file> 2>/dev/null || true
npx tsc --noEmit 2>/dev/null || true

# Rust
cargo clippy 2>/dev/null || true

# Go
go vet ./... 2>/dev/null || true

Only run linters that are already configured in the project. Do NOT install any tools.

Step 6: Report

After completing the refactoring, provide a clear summary.

Output Format

markdown
## Refactoring Report

**Target**: `<what was refactored>`
**Language**: <detected language>
**Files Modified**: <count>

---

### Summary

<2-3 sentence summary of what was refactored and why. State the primary
improvement achieved.>

### Code Smells Addressed

| Smell | Location | Technique Applied |
|-------|----------|-------------------|
| <smell name> | `file:function` | <refactoring technique> |
| <smell name> | `file:function` | <refactoring technique> |

### Changes Made

#### 1. <Refactoring title>

**File**: `<path>`
**Technique**: <refactoring technique name>
**Why**: <which code smell this addresses>

**Before**:
```<language>
// relevant code before refactoring

After:

<language>
// relevant code after refactoring

2. <Refactoring title>

...

Safety Verification

CheckStatus
Tests passYes / No / No tests found
Linter passesYes / No / Not configured
All callers updatedYes / Not applicable
Public API preservedYes / Changed (see notes)

Metrics Improvement

MetricBeforeAfter
Total lines of codeNN
Average function lengthN linesN lines
Maximum nesting depthNN
Duplicated blocksNN

Remaining Opportunities

<List any additional refactorings that would be beneficial but were out of scope for this session. These are suggestions for the user's consideration, not changes that were made.>

code

## Constraints

- **Preserve behavior**: This is the cardinal rule. The code must do exactly the same thing after refactoring as before. If you are unsure whether a change preserves behavior, do not make it.
- **No feature additions**: Do not add new functionality, new parameters, new methods, or new capabilities. Refactoring changes structure, not behavior.
- **No dependency changes**: Do not add new library dependencies. Do not remove dependencies unless the refactoring eliminates all usage of them.
- **Respect existing style**: Match the project's code style, naming conventions, and patterns. A refactoring that improves structure but violates project conventions is not an improvement.
- **Incremental changes**: Each individual refactoring should be small enough to verify by inspection. Do not make sweeping changes in a single step.
- **Justify every change**: Every modification must be tied to a specific code smell or improvement goal. Do not make changes "because it looks better" without a concrete rationale.
- **Do not refactor tests**: Unless the user specifically asks, leave test code alone. Tests are the safety net for refactoring -- changing them at the same time defeats the purpose.
- **Acknowledge risk without tests**: If there are no tests for the code being refactored, state this clearly and note that the refactoring carries higher risk. Recommend that the user run `/generate-tests` before or after refactoring.
- **Stop if unsafe**: If you realize mid-refactoring that a change will break behavior and you cannot safely complete it, stop and report what happened rather than leaving the code in a broken state.
- **Scope discipline**: Refactor only what was requested. If you notice opportunities in other files or modules, mention them in the report but do not apply them.
- **No cosmetic-only changes**: Do not refactor code that is already clean, clear, and well-structured. If the code is good, say so.