opencode-metis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -0
- package/dist/cli.cjs +63 -0
- package/dist/mcp-server.cjs +51 -0
- package/dist/plugin.cjs +4 -0
- package/dist/worker.cjs +224 -0
- package/opencode/agent/the-analyst/feature-prioritization.md +66 -0
- package/opencode/agent/the-analyst/market-research.md +77 -0
- package/opencode/agent/the-analyst/project-coordination.md +81 -0
- package/opencode/agent/the-analyst/requirements-analysis.md +77 -0
- package/opencode/agent/the-architect/compatibility-review.md +138 -0
- package/opencode/agent/the-architect/complexity-review.md +137 -0
- package/opencode/agent/the-architect/quality-review.md +67 -0
- package/opencode/agent/the-architect/security-review.md +127 -0
- package/opencode/agent/the-architect/system-architecture.md +119 -0
- package/opencode/agent/the-architect/system-documentation.md +83 -0
- package/opencode/agent/the-architect/technology-research.md +85 -0
- package/opencode/agent/the-chief.md +79 -0
- package/opencode/agent/the-designer/accessibility-implementation.md +101 -0
- package/opencode/agent/the-designer/design-foundation.md +74 -0
- package/opencode/agent/the-designer/interaction-architecture.md +75 -0
- package/opencode/agent/the-designer/user-research.md +70 -0
- package/opencode/agent/the-meta-agent.md +155 -0
- package/opencode/agent/the-platform-engineer/ci-cd-pipelines.md +109 -0
- package/opencode/agent/the-platform-engineer/containerization.md +106 -0
- package/opencode/agent/the-platform-engineer/data-architecture.md +81 -0
- package/opencode/agent/the-platform-engineer/dependency-review.md +144 -0
- package/opencode/agent/the-platform-engineer/deployment-automation.md +81 -0
- package/opencode/agent/the-platform-engineer/infrastructure-as-code.md +107 -0
- package/opencode/agent/the-platform-engineer/performance-tuning.md +82 -0
- package/opencode/agent/the-platform-engineer/pipeline-engineering.md +81 -0
- package/opencode/agent/the-platform-engineer/production-monitoring.md +105 -0
- package/opencode/agent/the-qa-engineer/exploratory-testing.md +66 -0
- package/opencode/agent/the-qa-engineer/performance-testing.md +81 -0
- package/opencode/agent/the-qa-engineer/quality-assurance.md +77 -0
- package/opencode/agent/the-qa-engineer/test-execution.md +66 -0
- package/opencode/agent/the-software-engineer/api-development.md +78 -0
- package/opencode/agent/the-software-engineer/component-development.md +79 -0
- package/opencode/agent/the-software-engineer/concurrency-review.md +141 -0
- package/opencode/agent/the-software-engineer/domain-modeling.md +66 -0
- package/opencode/agent/the-software-engineer/performance-optimization.md +113 -0
- package/opencode/command/analyze.md +149 -0
- package/opencode/command/constitution.md +178 -0
- package/opencode/command/debug.md +194 -0
- package/opencode/command/document.md +178 -0
- package/opencode/command/implement.md +225 -0
- package/opencode/command/refactor.md +207 -0
- package/opencode/command/review.md +229 -0
- package/opencode/command/simplify.md +267 -0
- package/opencode/command/specify.md +191 -0
- package/opencode/command/validate.md +224 -0
- package/opencode/skill/accessibility-design/SKILL.md +566 -0
- package/opencode/skill/accessibility-design/checklists/wcag-checklist.md +435 -0
- package/opencode/skill/agent-coordination/SKILL.md +224 -0
- package/opencode/skill/api-contract-design/SKILL.md +550 -0
- package/opencode/skill/api-contract-design/templates/graphql-schema-template.md +818 -0
- package/opencode/skill/api-contract-design/templates/rest-api-template.md +417 -0
- package/opencode/skill/architecture-design/SKILL.md +160 -0
- package/opencode/skill/architecture-design/examples/architecture-examples.md +170 -0
- package/opencode/skill/architecture-design/template.md +749 -0
- package/opencode/skill/architecture-design/validation.md +99 -0
- package/opencode/skill/architecture-selection/SKILL.md +522 -0
- package/opencode/skill/architecture-selection/examples/adrs/001-example-adr.md +71 -0
- package/opencode/skill/architecture-selection/examples/architecture-patterns.md +239 -0
- package/opencode/skill/bug-diagnosis/SKILL.md +235 -0
- package/opencode/skill/code-quality-review/SKILL.md +337 -0
- package/opencode/skill/code-quality-review/examples/anti-patterns.md +629 -0
- package/opencode/skill/code-quality-review/reference.md +322 -0
- package/opencode/skill/code-review/SKILL.md +363 -0
- package/opencode/skill/code-review/reference.md +450 -0
- package/opencode/skill/codebase-analysis/SKILL.md +139 -0
- package/opencode/skill/codebase-navigation/SKILL.md +227 -0
- package/opencode/skill/codebase-navigation/examples/exploration-patterns.md +263 -0
- package/opencode/skill/coding-conventions/SKILL.md +178 -0
- package/opencode/skill/coding-conventions/checklists/accessibility-checklist.md +176 -0
- package/opencode/skill/coding-conventions/checklists/performance-checklist.md +154 -0
- package/opencode/skill/coding-conventions/checklists/security-checklist.md +127 -0
- package/opencode/skill/constitution-validation/SKILL.md +315 -0
- package/opencode/skill/constitution-validation/examples/CONSTITUTION.md +202 -0
- package/opencode/skill/constitution-validation/reference/rule-patterns.md +328 -0
- package/opencode/skill/constitution-validation/template.md +115 -0
- package/opencode/skill/context-preservation/SKILL.md +445 -0
- package/opencode/skill/data-modeling/SKILL.md +385 -0
- package/opencode/skill/data-modeling/templates/schema-design-template.md +268 -0
- package/opencode/skill/deployment-pipeline-design/SKILL.md +579 -0
- package/opencode/skill/deployment-pipeline-design/templates/pipeline-template.md +633 -0
- package/opencode/skill/documentation-extraction/SKILL.md +259 -0
- package/opencode/skill/documentation-sync/SKILL.md +431 -0
- package/opencode/skill/domain-driven-design/SKILL.md +509 -0
- package/opencode/skill/domain-driven-design/examples/ddd-patterns.md +688 -0
- package/opencode/skill/domain-driven-design/reference.md +465 -0
- package/opencode/skill/drift-detection/SKILL.md +383 -0
- package/opencode/skill/drift-detection/reference.md +340 -0
- package/opencode/skill/error-recovery/SKILL.md +162 -0
- package/opencode/skill/error-recovery/examples/error-patterns.md +484 -0
- package/opencode/skill/feature-prioritization/SKILL.md +419 -0
- package/opencode/skill/feature-prioritization/examples/rice-template.md +139 -0
- package/opencode/skill/feature-prioritization/reference.md +256 -0
- package/opencode/skill/git-workflow/SKILL.md +453 -0
- package/opencode/skill/implementation-planning/SKILL.md +215 -0
- package/opencode/skill/implementation-planning/examples/phase-examples.md +217 -0
- package/opencode/skill/implementation-planning/template.md +220 -0
- package/opencode/skill/implementation-planning/validation.md +88 -0
- package/opencode/skill/implementation-verification/SKILL.md +272 -0
- package/opencode/skill/knowledge-capture/SKILL.md +265 -0
- package/opencode/skill/knowledge-capture/reference/knowledge-capture.md +402 -0
- package/opencode/skill/knowledge-capture/reference.md +444 -0
- package/opencode/skill/knowledge-capture/templates/domain-template.md +325 -0
- package/opencode/skill/knowledge-capture/templates/interface-template.md +255 -0
- package/opencode/skill/knowledge-capture/templates/pattern-template.md +144 -0
- package/opencode/skill/observability-design/SKILL.md +291 -0
- package/opencode/skill/observability-design/references/monitoring-patterns.md +461 -0
- package/opencode/skill/pattern-detection/SKILL.md +171 -0
- package/opencode/skill/pattern-detection/examples/common-patterns.md +359 -0
- package/opencode/skill/performance-analysis/SKILL.md +266 -0
- package/opencode/skill/performance-analysis/references/profiling-tools.md +499 -0
- package/opencode/skill/requirements-analysis/SKILL.md +139 -0
- package/opencode/skill/requirements-analysis/examples/good-prd.md +66 -0
- package/opencode/skill/requirements-analysis/template.md +177 -0
- package/opencode/skill/requirements-analysis/validation.md +69 -0
- package/opencode/skill/requirements-elicitation/SKILL.md +518 -0
- package/opencode/skill/requirements-elicitation/examples/interview-questions.md +226 -0
- package/opencode/skill/requirements-elicitation/examples/user-stories.md +414 -0
- package/opencode/skill/safe-refactoring/SKILL.md +312 -0
- package/opencode/skill/safe-refactoring/reference/code-smells.md +347 -0
- package/opencode/skill/security-assessment/SKILL.md +421 -0
- package/opencode/skill/security-assessment/checklists/security-review-checklist.md +285 -0
- package/opencode/skill/specification-management/SKILL.md +143 -0
- package/opencode/skill/specification-management/readme-template.md +32 -0
- package/opencode/skill/specification-management/reference.md +115 -0
- package/opencode/skill/specification-management/spec.py +229 -0
- package/opencode/skill/specification-validation/SKILL.md +397 -0
- package/opencode/skill/specification-validation/reference/3cs-framework.md +306 -0
- package/opencode/skill/specification-validation/reference/ambiguity-detection.md +132 -0
- package/opencode/skill/specification-validation/reference/constitution-validation.md +301 -0
- package/opencode/skill/specification-validation/reference/drift-detection.md +383 -0
- package/opencode/skill/task-delegation/SKILL.md +607 -0
- package/opencode/skill/task-delegation/examples/file-coordination.md +495 -0
- package/opencode/skill/task-delegation/examples/parallel-research.md +337 -0
- package/opencode/skill/task-delegation/examples/sequential-build.md +504 -0
- package/opencode/skill/task-delegation/reference.md +825 -0
- package/opencode/skill/tech-stack-detection/SKILL.md +89 -0
- package/opencode/skill/tech-stack-detection/references/framework-signatures.md +598 -0
- package/opencode/skill/technical-writing/SKILL.md +190 -0
- package/opencode/skill/technical-writing/templates/adr-template.md +205 -0
- package/opencode/skill/technical-writing/templates/system-doc-template.md +380 -0
- package/opencode/skill/test-design/SKILL.md +464 -0
- package/opencode/skill/test-design/examples/test-pyramid.md +724 -0
- package/opencode/skill/testing/SKILL.md +213 -0
- package/opencode/skill/testing/examples/test-pyramid.md +724 -0
- package/opencode/skill/user-insight-synthesis/SKILL.md +576 -0
- package/opencode/skill/user-insight-synthesis/templates/research-plan-template.md +217 -0
- package/opencode/skill/user-research/SKILL.md +508 -0
- package/opencode/skill/user-research/examples/interview-questions.md +265 -0
- package/opencode/skill/user-research/examples/personas.md +267 -0
- package/opencode/skill/vibe-security/SKILL.md +654 -0
- package/package.json +45 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: safe-refactoring
|
|
3
|
+
description: "Systematic code refactoring methodology that preserves all external behavior through baseline verification, code smell analysis, and one-at-a-time execution"
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: opencode
|
|
6
|
+
metadata:
|
|
7
|
+
category: development
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Safe Refactoring
|
|
12
|
+
|
|
13
|
+
Roleplay as a refactoring methodology specialist that improves code quality while strictly preserving all existing behavior.
|
|
14
|
+
|
|
15
|
+
SafeRefactoring {
|
|
16
|
+
Activation {
|
|
17
|
+
When improving code structure without changing behavior
|
|
18
|
+
When removing duplication or simplifying complexity
|
|
19
|
+
When renaming for clarity
|
|
20
|
+
When extracting or reorganizing code
|
|
21
|
+
When modernizing legacy code patterns
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Constraints {
|
|
25
|
+
CorePrinciple {
|
|
26
|
+
Behavior preservation is mandatory
|
|
27
|
+
External functionality must remain identical
|
|
28
|
+
Refactoring changes structure, never functionality
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
WhatCANChange {
|
|
32
|
+
- Code structure, internal implementation
|
|
33
|
+
- Variable/function names for clarity
|
|
34
|
+
- Duplication removal
|
|
35
|
+
- Dependencies and versions
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
WhatMUSTNOTChange {
|
|
39
|
+
- External behavior or public API contracts
|
|
40
|
+
- Business logic results
|
|
41
|
+
- Side effect ordering
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
ClarityOverBrevity {
|
|
45
|
+
- `if/else` over nested ternaries
|
|
46
|
+
- Multi-line over dense one-liners
|
|
47
|
+
- Obvious implementations over clever tricks
|
|
48
|
+
- Descriptive names over abbreviations
|
|
49
|
+
- Named constants over magic numbers
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
StopConditions {
|
|
53
|
+
- Tests fail after refactoring: revert and investigate
|
|
54
|
+
- Behavior changed: revert immediately
|
|
55
|
+
- Uncovered code encountered: add tests first or skip
|
|
56
|
+
- User requests stop: halt immediately, report progress
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
AnalysisModes {
|
|
61
|
+
Evaluate the request. First match wins.
|
|
62
|
+
|
|
63
|
+
| IF request contains | THEN use | Perspectives |
|
|
64
|
+
|---------------------|----------|-------------|
|
|
65
|
+
| "simplify", "clean up", "reduce complexity" | Simplification Mode | Complexity, Clarity, Structure, Waste |
|
|
66
|
+
| anything else | Standard Mode | Code Smells, Dependencies, Test Coverage, Patterns, Risk |
|
|
67
|
+
|
|
68
|
+
StandardAnalysisPerspectives {
|
|
69
|
+
| Perspective | Intent | What to Analyze |
|
|
70
|
+
|-------------|--------|-----------------|
|
|
71
|
+
| Code Smells | Find improvement opportunities | Long methods, duplication, complexity, deep nesting, magic numbers |
|
|
72
|
+
| Dependencies | Map coupling issues | Circular dependencies, tight coupling, abstraction violations |
|
|
73
|
+
| Test Coverage | Assess safety for refactoring | Existing tests, coverage gaps, test quality, missing assertions |
|
|
74
|
+
| Patterns | Identify applicable techniques | Design patterns, refactoring recipes, architectural improvements |
|
|
75
|
+
| Risk | Evaluate change impact | Blast radius, breaking changes, complexity, rollback difficulty |
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
SimplificationAnalysisPerspectives {
|
|
79
|
+
| Perspective | Intent | What to Find |
|
|
80
|
+
|-------------|--------|--------------|
|
|
81
|
+
| Complexity | Reduce cognitive load | Long methods (>20 lines), deep nesting, complex conditionals, convoluted loops, tangled async/promise chains |
|
|
82
|
+
| Clarity | Make intent obvious | Unclear names, magic numbers, inconsistent patterns, overly defensive code, unnecessary ceremony, nested ternaries |
|
|
83
|
+
| Structure | Improve organization | Mixed concerns, tight coupling, bloated interfaces, god objects, too many parameters, hidden dependencies |
|
|
84
|
+
| Waste | Eliminate what should not exist | Duplication, dead code, unused abstractions, speculative generality, copy-paste patterns, unreachable paths |
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Workflow {
|
|
89
|
+
Phase1_EstablishBaseline {
|
|
90
|
+
Before ANY refactoring:
|
|
91
|
+
|
|
92
|
+
1. Locate target code
|
|
93
|
+
2. Run existing tests to establish baseline
|
|
94
|
+
3. Report baseline status:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Refactoring Baseline
|
|
98
|
+
|
|
99
|
+
Tests: [X] passing, [Y] failing
|
|
100
|
+
Coverage: [Z]%
|
|
101
|
+
Uncovered areas: [List critical paths]
|
|
102
|
+
|
|
103
|
+
Baseline Status: READY | TESTS FAILING | COVERAGE GAP
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
4. If tests failing: Stop and report to user
|
|
107
|
+
5. If uncovered code found: Flag for user decision before proceeding
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
Phase2_Analysis {
|
|
111
|
+
Launch parallel analysis agents per the active analysis mode perspectives
|
|
112
|
+
|
|
113
|
+
For each perspective, describe the analysis intent:
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
Analyze [PERSPECTIVE] for refactoring:
|
|
117
|
+
|
|
118
|
+
CONTEXT:
|
|
119
|
+
- Target: [Code to refactor]
|
|
120
|
+
- Scope: [Module/feature boundaries]
|
|
121
|
+
- Baseline: [Test status, coverage %]
|
|
122
|
+
|
|
123
|
+
FOCUS: [What this perspective analyzes -- from perspectives table]
|
|
124
|
+
|
|
125
|
+
OUTPUT: Return findings as:
|
|
126
|
+
- impact: HIGH | MEDIUM | LOW
|
|
127
|
+
- title: Brief title (max 40 chars)
|
|
128
|
+
- location: file:line
|
|
129
|
+
- problem: One sentence describing what's wrong
|
|
130
|
+
- refactoring: Specific technique to apply
|
|
131
|
+
- risk: Potential complications
|
|
132
|
+
|
|
133
|
+
If no findings: NO_FINDINGS
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Synthesis {
|
|
137
|
+
1. Collect all findings from analysis agents
|
|
138
|
+
2. Deduplicate overlapping issues
|
|
139
|
+
3. Rank by: Impact (High > Medium > Low), then Risk (Low risk first)
|
|
140
|
+
4. Sequence refactorings: Independent changes first, dependent changes after
|
|
141
|
+
5. Present findings:
|
|
142
|
+
|
|
143
|
+
```markdown
|
|
144
|
+
## Refactoring Analysis: [target]
|
|
145
|
+
|
|
146
|
+
### Summary
|
|
147
|
+
|
|
148
|
+
| Perspective | High | Medium | Low |
|
|
149
|
+
|-------------|------|--------|-----|
|
|
150
|
+
| [Perspective 1] | X | X | X |
|
|
151
|
+
| **Total** | X | X | X |
|
|
152
|
+
|
|
153
|
+
*High Impact Issues*
|
|
154
|
+
|
|
155
|
+
| ID | Finding | Remediation | Risk |
|
|
156
|
+
|----|---------|-------------|------|
|
|
157
|
+
| H1 | Brief title *(file:line)* | Specific technique *(problem)* | Risk level |
|
|
158
|
+
|
|
159
|
+
*Medium Impact Issues*
|
|
160
|
+
|
|
161
|
+
| ID | Finding | Remediation | Risk |
|
|
162
|
+
|----|---------|-------------|------|
|
|
163
|
+
| M1 | Brief title *(file:line)* | Specific technique *(problem)* | Risk level |
|
|
164
|
+
|
|
165
|
+
*Low Impact Issues*
|
|
166
|
+
|
|
167
|
+
| ID | Finding | Remediation | Risk |
|
|
168
|
+
|----|---------|-------------|------|
|
|
169
|
+
| L1 | Brief title *(file:line)* | Specific technique *(problem)* | Risk level |
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
6. Offer options via question:
|
|
173
|
+
- "Document and proceed" -- Save plan to `docs/refactor/[NNN]-[name].md`, then execute
|
|
174
|
+
- "Proceed without documenting" -- Execute refactorings directly
|
|
175
|
+
- "Cancel" -- Abort refactoring
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
Phase3_ExecuteChanges {
|
|
180
|
+
One refactoring at a time -- never batch changes before verification
|
|
181
|
+
|
|
182
|
+
For EACH change in the prioritized sequence:
|
|
183
|
+
|
|
184
|
+
1. Apply single change
|
|
185
|
+
2. Run tests immediately
|
|
186
|
+
3. If pass: Mark complete, continue to next
|
|
187
|
+
4. If fail: Revert change, report failure, offer options:
|
|
188
|
+
- Try alternative approach
|
|
189
|
+
- Add tests first
|
|
190
|
+
- Skip this refactoring
|
|
191
|
+
- Get user guidance
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
Phase4_FinalValidation {
|
|
195
|
+
1. Run complete test suite
|
|
196
|
+
2. Compare behavior with baseline
|
|
197
|
+
3. Present results:
|
|
198
|
+
|
|
199
|
+
```markdown
|
|
200
|
+
## Refactoring Complete: [target]
|
|
201
|
+
|
|
202
|
+
**Status**: Complete | Partial - [reason]
|
|
203
|
+
|
|
204
|
+
### Before / After
|
|
205
|
+
|
|
206
|
+
| File | Before | After | Technique |
|
|
207
|
+
|------|--------|-------|-----------|
|
|
208
|
+
| billing.ts | 75-line method | 4 functions, 20 lines each | Extract Method |
|
|
209
|
+
|
|
210
|
+
### Verification
|
|
211
|
+
|
|
212
|
+
- Tests: [X] passing (baseline: [Y])
|
|
213
|
+
- Behavior: Preserved
|
|
214
|
+
- Coverage: [Z]% (baseline: [W]%)
|
|
215
|
+
|
|
216
|
+
### Quality Improvements
|
|
217
|
+
|
|
218
|
+
- [Improvement 1]
|
|
219
|
+
|
|
220
|
+
### Skipped
|
|
221
|
+
|
|
222
|
+
- [file:line] - [reason]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
4. Offer options via question:
|
|
226
|
+
- "Commit these changes"
|
|
227
|
+
- "Run full test suite"
|
|
228
|
+
- "Address skipped items (add tests first)"
|
|
229
|
+
- "Done"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
AgentDelegationTemplate {
|
|
234
|
+
When delegating refactoring tasks:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
FOCUS: [Specific refactoring]
|
|
238
|
+
- Apply [refactoring technique] to [target]
|
|
239
|
+
- Preserve all external behavior
|
|
240
|
+
- Run tests after change
|
|
241
|
+
|
|
242
|
+
EXCLUDE: [Other code, unrelated improvements]
|
|
243
|
+
- Stay within specified scope
|
|
244
|
+
- Preserve existing feature set
|
|
245
|
+
- Maintain identical behavior
|
|
246
|
+
|
|
247
|
+
CONTEXT:
|
|
248
|
+
- Baseline tests passing
|
|
249
|
+
- Target smell: [What we're fixing]
|
|
250
|
+
- Expected improvement: [What gets better]
|
|
251
|
+
|
|
252
|
+
OUTPUT:
|
|
253
|
+
- Refactored code
|
|
254
|
+
- Test results
|
|
255
|
+
- Summary of changes
|
|
256
|
+
|
|
257
|
+
SUCCESS:
|
|
258
|
+
- Tests still pass
|
|
259
|
+
- Smell eliminated
|
|
260
|
+
- Behavior preserved
|
|
261
|
+
|
|
262
|
+
TERMINATION: Refactoring complete OR tests fail
|
|
263
|
+
```
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
CommonRefactorings {
|
|
267
|
+
| Smell | Refactoring |
|
|
268
|
+
|-------|-------------|
|
|
269
|
+
| Long Method | Extract Method |
|
|
270
|
+
| Duplicate Code | Extract Method, Pull Up Method |
|
|
271
|
+
| Long Parameter List | Introduce Parameter Object |
|
|
272
|
+
| Complex Conditional | Decompose Conditional, Guard Clauses |
|
|
273
|
+
| Large Class | Extract Class |
|
|
274
|
+
| Feature Envy | Move Method |
|
|
275
|
+
| Dead Code | Remove Dead Code |
|
|
276
|
+
| Speculative Generality | Collapse Hierarchy, Inline Class |
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
BehaviorPreservationChecklist {
|
|
280
|
+
Before EVERY refactoring:
|
|
281
|
+
|
|
282
|
+
- [ ] Tests exist and pass
|
|
283
|
+
- [ ] Baseline behavior documented
|
|
284
|
+
- [ ] Single refactoring at a time
|
|
285
|
+
- [ ] Tests run after EVERY change
|
|
286
|
+
- [ ] No functional changes mixed with refactoring
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
AntiPatterns {
|
|
290
|
+
DoNotMixRefactoringWithFeatureChanges {
|
|
291
|
+
Separate commits: one for structural changes, another for new behavior
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
DoNotRefactorWithoutTests {
|
|
295
|
+
If code is not covered by tests:
|
|
296
|
+
1. Add characterization tests first
|
|
297
|
+
2. Then refactor
|
|
298
|
+
3. Or skip and document technical debt
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
DoNotRefactorEverythingAtOnce {
|
|
302
|
+
Prioritize by:
|
|
303
|
+
1. Code you are actively working on
|
|
304
|
+
2. Code with highest change frequency
|
|
305
|
+
3. Code with most bugs
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
## References
|
|
311
|
+
|
|
312
|
+
- [reference/code-smells.md](reference/code-smells.md) -- Code smell catalog and refactoring strategies
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# Refactoring Reference
|
|
2
|
+
|
|
3
|
+
## Code Smells Catalog
|
|
4
|
+
|
|
5
|
+
### Method-Level Smells
|
|
6
|
+
|
|
7
|
+
| Smell | Symptoms | Refactorings |
|
|
8
|
+
|-------|----------|--------------|
|
|
9
|
+
| Long Method | >20 lines, multiple responsibilities | Extract Method, Decompose Conditional |
|
|
10
|
+
| Long Parameter List | >3-4 parameters | Introduce Parameter Object, Preserve Whole Object |
|
|
11
|
+
| Duplicate Code | Same/similar logic in multiple places | Extract Method, Pull Up Method, Form Template Method |
|
|
12
|
+
| Complex Conditionals | Nested if/else, switch statements | Decompose Conditional, Replace with Guard Clauses |
|
|
13
|
+
| Feature Envy | Method uses more data from other class | Move Method, Move Field |
|
|
14
|
+
| Data Clumps | Same group of variables passed together | Extract Class, Introduce Parameter Object |
|
|
15
|
+
| Speculative Generality | Unused abstractions "for the future" | Collapse Hierarchy, Inline Class, Remove Parameter |
|
|
16
|
+
| Dead Code | Unreachable or unused code | Remove Dead Code |
|
|
17
|
+
|
|
18
|
+
### Class-Level Smells
|
|
19
|
+
|
|
20
|
+
| Smell | Symptoms | Refactorings |
|
|
21
|
+
|-------|----------|--------------|
|
|
22
|
+
| Large Class | >200 lines, multiple responsibilities | Extract Class, Extract Subclass |
|
|
23
|
+
| God Class | Knows too much, does too much | Extract Class, Move Method |
|
|
24
|
+
| Data Class | Only getters/setters, no behavior | Move Method into class, Encapsulate Field |
|
|
25
|
+
| Primitive Obsession | Overuse of primitives for domain concepts | Replace Primitive with Object, Extract Class |
|
|
26
|
+
| Refused Bequest | Subclass doesn't use inherited members | Replace Inheritance with Delegation |
|
|
27
|
+
| Lazy Class | Class that doesn't do enough | Inline Class, Collapse Hierarchy |
|
|
28
|
+
| Middle Man | Class that only delegates | Remove Middle Man, Inline Method |
|
|
29
|
+
| Parallel Inheritance | Every time you subclass A, you must subclass B | Move Method, Move Field |
|
|
30
|
+
|
|
31
|
+
### Architecture-Level Smells
|
|
32
|
+
|
|
33
|
+
| Smell | Symptoms | Refactorings |
|
|
34
|
+
|-------|----------|--------------|
|
|
35
|
+
| Circular Dependencies | A->B->C->A | Dependency Inversion, Extract Interface |
|
|
36
|
+
| Inappropriate Intimacy | Classes too coupled | Move Method, Hide Delegate, Change Bidirectional to Unidirectional |
|
|
37
|
+
| Shotgun Surgery | One change requires many file edits | Move Method, Inline Class |
|
|
38
|
+
| Divergent Change | One class changed for different reasons | Extract Class |
|
|
39
|
+
| Message Chains | a.getB().getC().getD() | Hide Delegate, Extract Method |
|
|
40
|
+
| Comments (excessive) | Comments explaining bad code | Extract Method, Rename Method, Introduce Assertion |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Safe Refactoring Patterns
|
|
45
|
+
|
|
46
|
+
### Extract Method
|
|
47
|
+
|
|
48
|
+
**When**: Long method with embedded logic blocks
|
|
49
|
+
|
|
50
|
+
**Before**:
|
|
51
|
+
```javascript
|
|
52
|
+
function processOrder(order) {
|
|
53
|
+
// Validate order
|
|
54
|
+
if (!order.items || order.items.length === 0) {
|
|
55
|
+
throw new Error('Order must have items');
|
|
56
|
+
}
|
|
57
|
+
if (!order.customer) {
|
|
58
|
+
throw new Error('Order must have customer');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Calculate total
|
|
62
|
+
let total = 0;
|
|
63
|
+
for (const item of order.items) {
|
|
64
|
+
total += item.price * item.quantity;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Apply discount
|
|
68
|
+
if (order.discountCode) {
|
|
69
|
+
total = total * 0.9;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { ...order, total };
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**After**:
|
|
77
|
+
```javascript
|
|
78
|
+
function processOrder(order) {
|
|
79
|
+
validateOrder(order);
|
|
80
|
+
const total = calculateTotal(order.items, order.discountCode);
|
|
81
|
+
return { ...order, total };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validateOrder(order) {
|
|
85
|
+
if (!order.items || order.items.length === 0) {
|
|
86
|
+
throw new Error('Order must have items');
|
|
87
|
+
}
|
|
88
|
+
if (!order.customer) {
|
|
89
|
+
throw new Error('Order must have customer');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function calculateTotal(items, discountCode) {
|
|
94
|
+
let total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
|
|
95
|
+
if (discountCode) {
|
|
96
|
+
total = total * 0.9;
|
|
97
|
+
}
|
|
98
|
+
return total;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Safety**: Run tests after each extraction
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
### Rename (Variable/Method/Class)
|
|
107
|
+
|
|
108
|
+
**When**: Names don't reveal intent
|
|
109
|
+
|
|
110
|
+
**Before**:
|
|
111
|
+
```javascript
|
|
112
|
+
const d = new Date();
|
|
113
|
+
function calc(x, y) {
|
|
114
|
+
return x * y * 0.15;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**After**:
|
|
119
|
+
```javascript
|
|
120
|
+
const orderDate = new Date();
|
|
121
|
+
function calculateTax(subtotal, taxRate) {
|
|
122
|
+
return subtotal * taxRate;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Safety**: Use IDE refactoring tools for automatic updates across codebase
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### Move Method/Field
|
|
131
|
+
|
|
132
|
+
**When**: Method uses more data from another class than its own
|
|
133
|
+
|
|
134
|
+
**Before**:
|
|
135
|
+
```javascript
|
|
136
|
+
class Order {
|
|
137
|
+
calculateShipping(customer) {
|
|
138
|
+
// Uses customer data extensively
|
|
139
|
+
if (customer.isPremium) return 0;
|
|
140
|
+
if (customer.country === 'US') return 5;
|
|
141
|
+
return 15;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**After**:
|
|
147
|
+
```javascript
|
|
148
|
+
class Customer {
|
|
149
|
+
calculateShippingFor(order) {
|
|
150
|
+
if (this.isPremium) return 0;
|
|
151
|
+
if (this.country === 'US') return 5;
|
|
152
|
+
return 15;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
class Order {
|
|
157
|
+
calculateShipping(customer) {
|
|
158
|
+
return customer.calculateShippingFor(this);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Safety**: Update all callers, run tests
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### Replace Conditional with Guard Clauses
|
|
168
|
+
|
|
169
|
+
**When**: Nested conditionals obscure the main path
|
|
170
|
+
|
|
171
|
+
**Before**:
|
|
172
|
+
```javascript
|
|
173
|
+
function getPayAmount(employee) {
|
|
174
|
+
let result;
|
|
175
|
+
if (employee.isSeparated) {
|
|
176
|
+
result = { amount: 0, reason: 'separated' };
|
|
177
|
+
} else {
|
|
178
|
+
if (employee.isRetired) {
|
|
179
|
+
result = { amount: 0, reason: 'retired' };
|
|
180
|
+
} else {
|
|
181
|
+
result = { amount: employee.salary, reason: 'active' };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**After**:
|
|
189
|
+
```javascript
|
|
190
|
+
function getPayAmount(employee) {
|
|
191
|
+
if (employee.isSeparated) {
|
|
192
|
+
return { amount: 0, reason: 'separated' };
|
|
193
|
+
}
|
|
194
|
+
if (employee.isRetired) {
|
|
195
|
+
return { amount: 0, reason: 'retired' };
|
|
196
|
+
}
|
|
197
|
+
return { amount: employee.salary, reason: 'active' };
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Safety**: Ensure all paths tested before refactoring
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
### Introduce Parameter Object
|
|
206
|
+
|
|
207
|
+
**When**: Same group of parameters passed together frequently
|
|
208
|
+
|
|
209
|
+
**Before**:
|
|
210
|
+
```javascript
|
|
211
|
+
function createBooking(startDate, endDate, roomType, guestName, guestEmail) {
|
|
212
|
+
// ...
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function validateBooking(startDate, endDate, roomType) {
|
|
216
|
+
// ...
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function calculatePrice(startDate, endDate, roomType) {
|
|
220
|
+
// ...
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**After**:
|
|
225
|
+
```javascript
|
|
226
|
+
class BookingRequest {
|
|
227
|
+
constructor(startDate, endDate, roomType, guestName, guestEmail) {
|
|
228
|
+
this.startDate = startDate;
|
|
229
|
+
this.endDate = endDate;
|
|
230
|
+
this.roomType = roomType;
|
|
231
|
+
this.guestName = guestName;
|
|
232
|
+
this.guestEmail = guestEmail;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function createBooking(request) {
|
|
237
|
+
// ...
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function validateBooking(request) {
|
|
241
|
+
// ...
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function calculatePrice(request) {
|
|
245
|
+
// ...
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Safety**: Update all call sites, run tests
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### Extract Class
|
|
254
|
+
|
|
255
|
+
**When**: One class has multiple responsibilities
|
|
256
|
+
|
|
257
|
+
**Before**:
|
|
258
|
+
```javascript
|
|
259
|
+
class User {
|
|
260
|
+
name;
|
|
261
|
+
email;
|
|
262
|
+
|
|
263
|
+
// User data methods
|
|
264
|
+
getName() { return this.name; }
|
|
265
|
+
setName(name) { this.name = name; }
|
|
266
|
+
|
|
267
|
+
// Email methods (separate concern)
|
|
268
|
+
sendWelcomeEmail() { /* ... */ }
|
|
269
|
+
sendPasswordReset() { /* ... */ }
|
|
270
|
+
validateEmail() { /* ... */ }
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**After**:
|
|
275
|
+
```javascript
|
|
276
|
+
class User {
|
|
277
|
+
name;
|
|
278
|
+
email;
|
|
279
|
+
emailService;
|
|
280
|
+
|
|
281
|
+
getName() { return this.name; }
|
|
282
|
+
setName(name) { this.name = name; }
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
class EmailService {
|
|
286
|
+
sendWelcomeEmail(user) { /* ... */ }
|
|
287
|
+
sendPasswordReset(user) { /* ... */ }
|
|
288
|
+
validateEmail(email) { /* ... */ }
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Safety**: Update all dependencies, run tests
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Behavior Preservation Checklist
|
|
297
|
+
|
|
298
|
+
Before ANY refactoring:
|
|
299
|
+
|
|
300
|
+
- [ ] Tests exist and pass
|
|
301
|
+
- [ ] Baseline behavior documented
|
|
302
|
+
- [ ] Single refactoring at a time
|
|
303
|
+
- [ ] Tests run after EVERY change
|
|
304
|
+
- [ ] No functional changes mixed with refactoring
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Refactoring Decision Matrix
|
|
309
|
+
|
|
310
|
+
| Situation | Action |
|
|
311
|
+
|-----------|--------|
|
|
312
|
+
| Tests passing, clear smell | Proceed with refactoring |
|
|
313
|
+
| Tests passing, unclear benefit | Skip or discuss with team |
|
|
314
|
+
| Tests failing | Fix tests first, then refactor |
|
|
315
|
+
| No tests for area | Add tests first OR skip refactoring |
|
|
316
|
+
| Behavior change required | Not refactoring - this is a feature change |
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Anti-Patterns to Avoid
|
|
321
|
+
|
|
322
|
+
### Don't Mix Refactoring with Feature Changes
|
|
323
|
+
|
|
324
|
+
**Wrong**:
|
|
325
|
+
```
|
|
326
|
+
Commit: "Refactor user service and add email validation"
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Right**:
|
|
330
|
+
```
|
|
331
|
+
Commit 1: "Refactor: Extract email methods from UserService"
|
|
332
|
+
Commit 2: "Feature: Add email validation to registration"
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Don't Refactor Without Tests
|
|
336
|
+
|
|
337
|
+
If code isn't covered by tests:
|
|
338
|
+
1. Add characterization tests first
|
|
339
|
+
2. Then refactor
|
|
340
|
+
3. Or skip and document technical debt
|
|
341
|
+
|
|
342
|
+
### Don't Refactor Everything at Once
|
|
343
|
+
|
|
344
|
+
Prioritize by:
|
|
345
|
+
1. Code you're actively working on
|
|
346
|
+
2. Code with highest change frequency
|
|
347
|
+
3. Code with most bugs
|