Claude
Skills
Sign in
Back

refactoring

Included with Lifetime
$97 forever

Linter-driven refactoring patterns to reduce complexity and improve code quality. Use when linter fails with complexity issues (cyclomatic, cognitive, maintainability) or when code feels hard to read/maintain. Applies storifying, type extraction, and function extraction patterns.

General

What this skill does


<objective>
Linter-driven refactoring patterns to reduce complexity and improve code quality.
Operates autonomously - no user confirmation needed during execution.

**Reference**: See `reference.md` for complete decision tree, patterns, and code examples.
**Examples**: See `examples.md` for real-world refactoring case studies.
</objective>

<skill_invocation>
**CRITICAL**: When this skill says "Invoke @skill-name" or routes to "@skill-name", you MUST use the **Skill tool** explicitly.

| Notation | Skill Tool Call |
|----------|-----------------|
| @code-designing | `Skill(go-linter-driven-development:code-designing)` |
| @testing | `Skill(go-linter-driven-development:testing)` |
| @pre-commit-review | `Skill(go-linter-driven-development:pre-commit-review)` |

**DO NOT** just reference the skill - actually invoke it using the Skill tool.
</skill_invocation>

<quick_start>
1. **Receive linter failures** from @linter-driven-development
2. **Analyze root cause** - Does it read like a story? Can it be broken down?
3. **Apply patterns** in priority order (storify → early returns → extract function → extract type)
4. **Verify** - Re-run linter automatically
5. **Iterate** until linter passes

**IMPORTANT**: This skill operates autonomously - no user confirmation needed.
</quick_start>

<when_to_use>
- **Automatically invoked** by @linter-driven-development when linter fails
- **Automatically invoked** by @pre-commit-review when design issues detected
- **Complexity failures**: cyclomatic, cognitive, maintainability index
- **Architectural failures**: noglobals, gochecknoinits, gochecknoglobals
- **Design smell failures**: dupl, goconst, ineffassign
- **Package size violations**: ≥13 non-test `.go` files at one directory level (red zone, must decompose) or 8–12 (yellow zone, design review before next file)
- Functions > 50 LOC or nesting > 2 levels
- Mixed abstraction levels in functions
- Manual invocation when code feels hard to read/maintain
</when_to_use>

<learning_resources>
- **Quick Start**: Use patterns below for common cases
- **Complete Reference**: See [reference.md](./reference.md) for full decision tree and all patterns
- **Real-World Examples**: See [examples.md](./examples.md) for case studies:
  - **Example 1**: Storifying mixed abstractions + extracting leaf types (fat function → lean orchestration)
  - **Example 2**: Primitive obsession with multiple types + switch elimination (includes over-abstraction trap!)
  - **Example 3**: Dependency rejection pattern (globals → clean testable islands, bottom-up approach)
</learning_resources>

<refactoring_signals>

<linter_routing>
| Linter Error | Pattern |
|--------------|---------|
| `nestif` (deep nesting) | Storify → Early returns → Extract function |
| `cyclop`/`gocognit` | Storify → Extract type |
| `funlen` (too long) | Storify → Extract function |
| `noglobals` | Dependency rejection |
| `dupl` | Extract common logic/types |
| `goconst` | Extract constants or types |
| `wrapcheck` | Direct fix: `fmt.Errorf("context: %w", err)` |
| `early-return` (revive) | Invert condition, return early |
| `file-length-limit` | Route to @code-designing for file splitting |

**Pattern Documentation**:
- Storifying, Early Returns, Extract Function, Extract Type → `reference.md`
- Dependency Rejection → `examples.md` (Example 3)
- Over-abstraction warnings → `reference.md` section 2.5
</linter_routing>

<file_level_concerns>
**When `file-length-limit` triggers (>450 lines):**

| File Pattern | Route To | Action |
|--------------|----------|--------|
| Multiple juicy types | @code-designing | Juicy type per file |
| Single god type (>15 methods) | @refactoring → @code-designing | Storify, then decompose |
| Long functions, few types | @refactoring | Storify → Extract functions |

**"Juicy" types** (deserve own file): ≥2 methods, complex validation, transformations/parsing
**Anemic types** (can stay grouped): Simple enums, DTOs without methods, type aliases
</file_level_concerns>

<package_level_concerns>
**Detection is automatic.** This plugin ships a PostToolUse hook (`hooks/check-package-sizes.sh`) that counts non-test `.go` files per package after every Write / Edit / MultiEdit and surfaces violations directly to Claude.

| Count | Zone   | Action                                                                          |
|-------|--------|---------------------------------------------------------------------------------|
| ≤ 7   | Green  | Fine.                                                                           |
| 8–12  | Yellow | Advisory from hook (non-blocking). Design review **before the next file lands** — route to `<package_decomposition>`. |
| ≥ 13  | Red    | Blocking feedback from hook (exit 2). **Must decompose** — route to `<package_decomposition>`. |

**Critical**: A package-size violation is a *design* review (domain modeling + type extraction), not a mechanical file split. File count is a symptom; the disease is usually missing domain types or multiple vertical slices sharing a package.
</package_level_concerns>
</refactoring_signals>

<pattern_summary>
**Pattern Priority Order** (for complexity failures):

1. **Storifying** - Make code read like a story, reveals hidden structure
2. **Early Returns** - Reduce nesting by inverting conditions
3. **Extract Function** - Break up long functions by responsibility
4. **Extract Type** - Create domain types (only if "juicy")
5. **Switch Extraction** - Extract case handlers to separate functions
6. **Dependency Rejection** - Push globals up call chain incrementally
7. **Package Decomposition** - Split oversized packages (≥13 files) via 3-step design review (see `<package_decomposition>`)

See `reference.md` for detailed patterns with code examples.

<juiciness_test>
Before extracting a type, verify it's "juicy" (worth creating):

**BEHAVIORAL**: Complex validation, ≥2 meaningful methods, state transitions
**STRUCTURAL**: Parsing unstructured data, grouping related data
**USAGE**: Used in multiple places, simplifies calling code

Need "yes" in at least ONE category. See `reference.md` section 2.5 for over-abstraction warnings.

**Self-Validation Rule:** Extracted types must own their validation. The original function stops validating what the new type now owns. Composed self-validating types are trusted, not re-validated.
</juiciness_test>

<type_cohesion>
When extracting a type to its own file, co-locate ALL related declarations:
- Type definition + constants + constructor + all methods

Verify by searching for *declarations* tied to the type, not every usage of its name
(usages in tests, comments, and other packages are false positives). Check for:
- Receiver methods: `grep -RnE '^func \([^)]+\*?TypeName\)' --include="*.go" .`
- Constructors: `grep -RnE '^func (New|Parse|Make)TypeName\b' --include="*.go" .`
- Related `const`/`var` declarations that belong with the type.

If declarations that should be co-located are found elsewhere → move them to the type's file.
</type_cohesion>

<god_object_decomposition>
**Trigger**: Type has >15 methods OR >500 LOC

**Strategy** (in order):

1. **Extract generic logic first** (creates reusable leaf types):
   - String manipulation → `StringParser`, `Formatter` types
   - URL/path handling → `URL`, `FilePath` types with validation
   - Retry/timeout logic → `Retrier`, `TimeoutHandler` types
   - Date/time formatting → `DateFormatter` type
   - Validation patterns → Self-validating domain types

   These become **testable islands** and may be useful elsewhere.

2. **Then group remaining methods by noun** (domain services):
   - User methods → `UserService`
   - Order methods → `OrderService`
   - Cache methods → `CacheService`

3. **Extract each group into focused service type**
4. **Compose services in orchestrator** (delegates, doesn't implement)

**Key insight**: Generic logic extraction often reveals the god object was mixing infrastructure concerns with domain logic.

See `reference.md` for detailed 

Related in General