aiknowsys 0.0.1
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/AGENTS.template.md +207 -0
- package/CODEBASE_CHANGELOG.template.md +145 -0
- package/CODEBASE_ESSENTIALS.template.md +382 -0
- package/LICENSE +21 -0
- package/README.md +714 -0
- package/bin/cli.js +81 -0
- package/lib/commands/init.js +227 -0
- package/lib/commands/install-agents.js +100 -0
- package/lib/commands/install-skills.js +92 -0
- package/lib/commands/migrate.js +161 -0
- package/lib/commands/scan.js +418 -0
- package/lib/utils.js +93 -0
- package/package.json +53 -0
- package/scripts/migrate-existing.sh +222 -0
- package/scripts/scan-codebase.sh +379 -0
- package/scripts/setup.sh +273 -0
- package/templates/agents/README.md +270 -0
- package/templates/agents/architect.agent.template.md +58 -0
- package/templates/agents/developer.agent.template.md +27 -0
- package/templates/agents/setup-agents.sh +65 -0
- package/templates/skills/code-refactoring/SKILL.md +662 -0
- package/templates/skills/dependency-updates/SKILL.md +561 -0
- package/templates/skills/documentation-management/SKILL.md +744 -0
- package/templates/skills/skill-creator/SKILL.md +252 -0
- package/templates/skills/skill-creator/template.md +89 -0
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-refactoring
|
|
3
|
+
description: Safe code refactoring guide for gnwebsite project. Use when refactoring components, removing duplication, improving code structure, or simplifying complex functions. Covers test-driven refactoring, incremental changes, extract function/composable patterns, and rollback procedures. Ensures refactoring preserves behavior while improving code quality.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Refactoring Guide
|
|
7
|
+
|
|
8
|
+
Step-by-step guide for safely refactoring code without breaking functionality in the gnwebsite fullstack project.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Use when:
|
|
13
|
+
- User asks "How do I refactor this code?" or "Can I simplify this?"
|
|
14
|
+
- Reducing code duplication (DRY violations)
|
|
15
|
+
- Simplifying complex functions (>50 lines)
|
|
16
|
+
- Extracting reusable logic to composables
|
|
17
|
+
- Improving code structure or naming
|
|
18
|
+
- Addressing technical debt
|
|
19
|
+
- User mentions: "refactor", "clean up", "simplify", "reduce duplication"
|
|
20
|
+
|
|
21
|
+
**Do NOT use for:**
|
|
22
|
+
- Style preferences without measurable benefit
|
|
23
|
+
- Just before deadlines
|
|
24
|
+
- Code without existing tests
|
|
25
|
+
- Changes that alter behavior (that's feature work, not refactoring)
|
|
26
|
+
|
|
27
|
+
## Decision Tree: Proposal or Direct Refactoring?
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Need to refactor?
|
|
31
|
+
│
|
|
32
|
+
├─ Breaking changes? (API contracts, schemas, core patterns)
|
|
33
|
+
│ └─ YES → Create OpenSpec proposal
|
|
34
|
+
│
|
|
35
|
+
├─ Just reorganizing code? (internal structure, no external impact)
|
|
36
|
+
│ └─ YES → Follow safe refactoring steps
|
|
37
|
+
│
|
|
38
|
+
└─ Unsure?
|
|
39
|
+
└─ Create proposal (better safe than sorry!)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Prerequisites (CRITICAL)
|
|
43
|
+
|
|
44
|
+
**NEVER refactor without tests!**
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Check test coverage
|
|
48
|
+
cd frontend && npm run test:run -- --coverage
|
|
49
|
+
cd backend && docker exec backend pytest --cov
|
|
50
|
+
|
|
51
|
+
# If coverage < 80% for code being refactored:
|
|
52
|
+
# 1. STOP
|
|
53
|
+
# 2. Write tests FIRST
|
|
54
|
+
# 3. THEN refactor
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Minimum requirements:**
|
|
58
|
+
- [ ] Unit tests exist for all functions being changed
|
|
59
|
+
- [ ] Integration tests exist for workflows being changed
|
|
60
|
+
- [ ] All tests currently passing ✅
|
|
61
|
+
|
|
62
|
+
## Phase 1: Preparation
|
|
63
|
+
|
|
64
|
+
### Step 1: Document Current Behavior
|
|
65
|
+
|
|
66
|
+
Create temporary documentation:
|
|
67
|
+
```markdown
|
|
68
|
+
# Refactoring: [Component Name]
|
|
69
|
+
|
|
70
|
+
## Current Behavior
|
|
71
|
+
- Input: X
|
|
72
|
+
- Output: Y
|
|
73
|
+
- Side effects: Z
|
|
74
|
+
- Edge cases: A, B, C
|
|
75
|
+
|
|
76
|
+
## Existing Tests
|
|
77
|
+
- test_case_1: normal flow
|
|
78
|
+
- test_case_2: error handling
|
|
79
|
+
- test_case_3: edge case
|
|
80
|
+
|
|
81
|
+
## Success Criteria
|
|
82
|
+
After refactor: all tests pass, same behavior
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Step 2: Create Safety Backup
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Create backup branch
|
|
89
|
+
git checkout -b backup-before-refactor
|
|
90
|
+
git checkout -b refactor-my-feature
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Step 3: Create Refactoring Checklist
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
## Refactoring Checklist
|
|
97
|
+
|
|
98
|
+
### Before
|
|
99
|
+
- [ ] All existing tests pass
|
|
100
|
+
- [ ] Coverage documented
|
|
101
|
+
- [ ] Behavior documented
|
|
102
|
+
- [ ] Backup branch created
|
|
103
|
+
|
|
104
|
+
### During
|
|
105
|
+
- [ ] ONE change at a time
|
|
106
|
+
- [ ] Run tests after EACH change
|
|
107
|
+
- [ ] Commit after EACH success
|
|
108
|
+
|
|
109
|
+
### After
|
|
110
|
+
- [ ] All tests still pass
|
|
111
|
+
- [ ] No console errors
|
|
112
|
+
- [ ] Manual testing complete
|
|
113
|
+
- [ ] Performance unchanged/better
|
|
114
|
+
- [ ] Documentation updated
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Phase 2: Refactoring Patterns
|
|
118
|
+
|
|
119
|
+
### Pattern A: Extract Function (Reduce Complexity)
|
|
120
|
+
|
|
121
|
+
**When**: Function >50 lines or multiple responsibilities
|
|
122
|
+
|
|
123
|
+
**Before**:
|
|
124
|
+
```typescript
|
|
125
|
+
async function processArticle(article: Article) {
|
|
126
|
+
// Validation (10 lines)
|
|
127
|
+
if (!article.title) throw new Error('Title required')
|
|
128
|
+
if (!article.content) throw new Error('Content required')
|
|
129
|
+
|
|
130
|
+
// Image processing (15 lines)
|
|
131
|
+
const images = []
|
|
132
|
+
for (const img of article.images || []) {
|
|
133
|
+
const url = img.image?.fileUrl || img.image?.file_url
|
|
134
|
+
if (url) images.push({ url, caption: img.caption })
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Save (20 lines)
|
|
138
|
+
const response = await api.create({ title, content, images })
|
|
139
|
+
return response
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**After**:
|
|
144
|
+
```typescript
|
|
145
|
+
async function processArticle(article: Article) {
|
|
146
|
+
validateArticle(article)
|
|
147
|
+
const images = processImages(article.images)
|
|
148
|
+
return await saveArticle(article, images)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function validateArticle(article: Article) {
|
|
152
|
+
if (!article.title) throw new Error('Title required')
|
|
153
|
+
if (!article.content) throw new Error('Content required')
|
|
154
|
+
if (article.title.length > 200) throw new Error('Title too long')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function processImages(images?: ArticleImage[]) {
|
|
158
|
+
return (images || [])
|
|
159
|
+
.map(img => ({ url: getImageUrl(img.image), caption: img.caption }))
|
|
160
|
+
.filter(img => img.url && img.url !== '/placeholder-image.png')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function saveArticle(article: Article, images: ProcessedImage[]) {
|
|
164
|
+
return await api.create({
|
|
165
|
+
title: article.title,
|
|
166
|
+
content: article.content,
|
|
167
|
+
images
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Steps**:
|
|
173
|
+
1. Extract ONE function at a time
|
|
174
|
+
2. Run tests after each extraction
|
|
175
|
+
3. Commit each success
|
|
176
|
+
4. Add tests for new functions:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
describe('validateArticle', () => {
|
|
180
|
+
it('should throw on missing title', () => {
|
|
181
|
+
expect(() => validateArticle({ content: 'test' }))
|
|
182
|
+
.toThrow('Title required')
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
describe('processImages', () => {
|
|
187
|
+
it('should extract URLs', () => {
|
|
188
|
+
const imgs = [{ image: { fileUrl: 'test.jpg' }, caption: 'Test' }]
|
|
189
|
+
expect(processImages(imgs)).toEqual([{ url: 'test.jpg', caption: 'Test' }])
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('should filter placeholders', () => {
|
|
193
|
+
expect(processImages([{ image: null }])).toEqual([])
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Pattern B: Extract Composable (Reuse Logic)
|
|
199
|
+
|
|
200
|
+
**When**: Same logic duplicated across 3+ components
|
|
201
|
+
|
|
202
|
+
**Before** (duplicated in BlogView, ArticleView, CategoryView):
|
|
203
|
+
```vue
|
|
204
|
+
<script setup>
|
|
205
|
+
const items = ref([])
|
|
206
|
+
const loading = ref(false)
|
|
207
|
+
const error = ref('')
|
|
208
|
+
|
|
209
|
+
const loadItems = async () => {
|
|
210
|
+
loading.value = true
|
|
211
|
+
try {
|
|
212
|
+
const response = await blogService.getAll()
|
|
213
|
+
items.value = response.results
|
|
214
|
+
} catch (err) {
|
|
215
|
+
error.value = 'Failed to load'
|
|
216
|
+
} finally {
|
|
217
|
+
loading.value = false
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
onMounted(loadItems)
|
|
222
|
+
</script>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**After**:
|
|
226
|
+
```typescript
|
|
227
|
+
// composables/useDataLoader.ts
|
|
228
|
+
export function useDataLoader<T>(
|
|
229
|
+
loadFn: () => Promise<{ results: T[] }>
|
|
230
|
+
) {
|
|
231
|
+
const items = ref<T[]>([])
|
|
232
|
+
const loading = ref(false)
|
|
233
|
+
const error = ref('')
|
|
234
|
+
|
|
235
|
+
const load = async () => {
|
|
236
|
+
loading.value = true
|
|
237
|
+
error.value = ''
|
|
238
|
+
try {
|
|
239
|
+
const response = await loadFn()
|
|
240
|
+
items.value = response.results || []
|
|
241
|
+
} catch (err) {
|
|
242
|
+
error.value = 'Failed to load items'
|
|
243
|
+
console.error(err)
|
|
244
|
+
} finally {
|
|
245
|
+
loading.value = false
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
onMounted(load)
|
|
250
|
+
return { items, loading, error, reload: load }
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```vue
|
|
255
|
+
<!-- All components now -->
|
|
256
|
+
<script setup>
|
|
257
|
+
import { useDataLoader } from '@/composables/useDataLoader'
|
|
258
|
+
|
|
259
|
+
const { items, loading, error, reload } = useDataLoader(() =>
|
|
260
|
+
blogService.getAll()
|
|
261
|
+
)
|
|
262
|
+
</script>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Steps**:
|
|
266
|
+
1. Create composable
|
|
267
|
+
2. Write composable tests
|
|
268
|
+
3. Migrate ONE component
|
|
269
|
+
4. Test that component
|
|
270
|
+
5. Commit
|
|
271
|
+
6. Repeat for remaining components
|
|
272
|
+
|
|
273
|
+
### Pattern C: Consolidate Styles
|
|
274
|
+
|
|
275
|
+
**When**: Same CSS in 3+ components
|
|
276
|
+
|
|
277
|
+
**Before** (duplicated in 6 form components):
|
|
278
|
+
```vue
|
|
279
|
+
<style scoped>
|
|
280
|
+
.form-group { margin-bottom: 1.5rem; }
|
|
281
|
+
.form-control { width: 100%; padding: 0.75rem; }
|
|
282
|
+
.btn-primary { background: #007bff; color: white; }
|
|
283
|
+
</style>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**After**:
|
|
287
|
+
```css
|
|
288
|
+
/* styles/admin-forms.css */
|
|
289
|
+
.form-group { margin-bottom: 1.5rem; }
|
|
290
|
+
.form-control { width: 100%; padding: 0.75rem; }
|
|
291
|
+
.btn-primary { background: #007bff; color: white; }
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
```vue
|
|
295
|
+
<!-- Components keep only unique styles -->
|
|
296
|
+
<style scoped>
|
|
297
|
+
.special-field { /* component-specific */ }
|
|
298
|
+
</style>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Steps**:
|
|
302
|
+
1. Extract to shared CSS file
|
|
303
|
+
2. Import in main.ts/App.vue
|
|
304
|
+
3. Remove from ONE component
|
|
305
|
+
4. Visual test
|
|
306
|
+
5. Commit
|
|
307
|
+
6. Repeat for remaining
|
|
308
|
+
|
|
309
|
+
### Pattern D: Replace with Utility
|
|
310
|
+
|
|
311
|
+
**When**: Same calculation in 5+ places
|
|
312
|
+
|
|
313
|
+
**Before** (in 5 files):
|
|
314
|
+
```typescript
|
|
315
|
+
const imageUrl = img.image?.fileUrl || img.image?.file_url || '/placeholder-image.png'
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**After**:
|
|
319
|
+
```typescript
|
|
320
|
+
// utils/imageData.ts
|
|
321
|
+
export function extractImageUrl(
|
|
322
|
+
imageData: any,
|
|
323
|
+
fallback = '/placeholder-image.png'
|
|
324
|
+
): string {
|
|
325
|
+
if (!imageData) return fallback
|
|
326
|
+
return imageData.fileUrl || imageData.file_url || fallback
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// All files:
|
|
330
|
+
const imageUrl = extractImageUrl(img.image)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Steps**:
|
|
334
|
+
1. Create utility
|
|
335
|
+
2. Write comprehensive tests
|
|
336
|
+
3. Replace in ONE location
|
|
337
|
+
4. Test
|
|
338
|
+
5. Commit
|
|
339
|
+
6. Repeat for each location
|
|
340
|
+
|
|
341
|
+
## Phase 3: Incremental Execution
|
|
342
|
+
|
|
343
|
+
**CRITICAL WORKFLOW**: One change → Test → Commit
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
# 1. Create working branch
|
|
347
|
+
git checkout -b refactor-my-feature
|
|
348
|
+
|
|
349
|
+
# 2. Make ONE small change
|
|
350
|
+
# ... edit code ...
|
|
351
|
+
|
|
352
|
+
# 3. Run tests
|
|
353
|
+
npm run test:run
|
|
354
|
+
|
|
355
|
+
# 4. If pass, commit
|
|
356
|
+
git add .
|
|
357
|
+
git commit -m "refactor: extract validateArticle function
|
|
358
|
+
|
|
359
|
+
- Moved validation from processArticle
|
|
360
|
+
- All tests passing
|
|
361
|
+
- No behavior changes"
|
|
362
|
+
|
|
363
|
+
# 5. Repeat for next change
|
|
364
|
+
# ... edit code ...
|
|
365
|
+
npm run test:run
|
|
366
|
+
git commit -m "refactor: extract processImages"
|
|
367
|
+
|
|
368
|
+
# Continue until complete
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Testing After EVERY Change
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
# After each change:
|
|
375
|
+
|
|
376
|
+
# 1. Unit tests
|
|
377
|
+
npm run test:run
|
|
378
|
+
|
|
379
|
+
# 2. Type check
|
|
380
|
+
npm run type-check
|
|
381
|
+
|
|
382
|
+
# 3. Pattern check
|
|
383
|
+
npm run test:patterns
|
|
384
|
+
|
|
385
|
+
# 4. Manual spot check
|
|
386
|
+
npm run dev
|
|
387
|
+
# Test the specific feature
|
|
388
|
+
|
|
389
|
+
# If ANY fail:
|
|
390
|
+
git reset --hard HEAD # Undo
|
|
391
|
+
# OR fix before committing
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Phase 4: Validation
|
|
395
|
+
|
|
396
|
+
### Comprehensive Testing Checklist
|
|
397
|
+
|
|
398
|
+
**Automated:**
|
|
399
|
+
- [ ] All unit tests pass
|
|
400
|
+
- [ ] All integration tests pass
|
|
401
|
+
- [ ] Type check passes
|
|
402
|
+
- [ ] Pattern enforcement passes
|
|
403
|
+
- [ ] No new linting errors
|
|
404
|
+
|
|
405
|
+
**Manual:**
|
|
406
|
+
- [ ] Feature works exactly as before
|
|
407
|
+
- [ ] No console errors
|
|
408
|
+
- [ ] No visual regressions
|
|
409
|
+
- [ ] Performance unchanged/better
|
|
410
|
+
- [ ] Works in all browsers
|
|
411
|
+
|
|
412
|
+
**Code Quality:**
|
|
413
|
+
- [ ] More readable
|
|
414
|
+
- [ ] More testable
|
|
415
|
+
- [ ] Less duplication
|
|
416
|
+
- [ ] Lower complexity
|
|
417
|
+
- [ ] Reasonable file sizes
|
|
418
|
+
|
|
419
|
+
### Performance Verification
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
# Before refactor
|
|
423
|
+
npm run build
|
|
424
|
+
# Note: size, time
|
|
425
|
+
|
|
426
|
+
# After refactor
|
|
427
|
+
npm run build
|
|
428
|
+
# Compare: should be similar or better
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Phase 5: Documentation
|
|
432
|
+
|
|
433
|
+
### Update Project Docs
|
|
434
|
+
|
|
435
|
+
If new patterns introduced:
|
|
436
|
+
|
|
437
|
+
**CODEBASE_ESSENTIALS.md**:
|
|
438
|
+
```markdown
|
|
439
|
+
- **Image URL extraction:** Always use `extractImageUrl()` from `@/utils/imageData`. Prevents silent failures.
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**CODEBASE_CHANGELOG.md**:
|
|
443
|
+
```markdown
|
|
444
|
+
### Session: Refactor Image URL Handling (Jan 13, 2026)
|
|
445
|
+
|
|
446
|
+
**Goal**: Eliminate duplicated image URL logic
|
|
447
|
+
|
|
448
|
+
**Changes**:
|
|
449
|
+
- Created `extractImageUrl()` utility
|
|
450
|
+
- Replaced 12 instances
|
|
451
|
+
- Added tests (8 unit, 6 integration)
|
|
452
|
+
|
|
453
|
+
**Impact**:
|
|
454
|
+
- Reduced duplication by ~80 lines
|
|
455
|
+
- Improved testability
|
|
456
|
+
|
|
457
|
+
**Validation**:
|
|
458
|
+
- ✅ All 227 tests pass
|
|
459
|
+
- ✅ No behavior changes
|
|
460
|
+
- ✅ Build size unchanged
|
|
461
|
+
|
|
462
|
+
**Commit**: abc123
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
## Anti-Patterns (DON'T DO THIS)
|
|
466
|
+
|
|
467
|
+
### ❌ Big Bang Refactor
|
|
468
|
+
|
|
469
|
+
```bash
|
|
470
|
+
# WRONG: Change 50 files at once
|
|
471
|
+
git commit -m "refactor: everything"
|
|
472
|
+
|
|
473
|
+
# CORRECT: Incremental commits
|
|
474
|
+
git commit -m "refactor: extract validation"
|
|
475
|
+
# test
|
|
476
|
+
git commit -m "refactor: extract image processing"
|
|
477
|
+
# test
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### ❌ Refactor Without Tests
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
// WRONG: No tests exist
|
|
484
|
+
function refactoredFunction() {
|
|
485
|
+
// Hope this works! 🤞
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// CORRECT: Write tests first
|
|
489
|
+
test('refactoredFunction works', () => { ... })
|
|
490
|
+
function refactoredFunction() { ... }
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### ❌ Change Behavior
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
// WRONG: Added new validation during refactor
|
|
497
|
+
function validateArticle(article: Article) {
|
|
498
|
+
if (!article.title) throw new Error('Title required')
|
|
499
|
+
if (!article.excerpt) throw new Error('Excerpt required') // NEW!
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// CORRECT: Preserve exact behavior
|
|
503
|
+
function validateArticle(article: Article) {
|
|
504
|
+
if (!article.title) throw new Error('Title required')
|
|
505
|
+
// Same validation as before, just extracted
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### ❌ Premature Optimization
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
// WRONG: No measured problem, making code complex
|
|
513
|
+
// Replacing simple readable code with "faster" code
|
|
514
|
+
|
|
515
|
+
// CORRECT: Measure first, optimize if needed
|
|
516
|
+
// Keep code simple unless profiling shows issue
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### ❌ Refactor Under Pressure
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
// WRONG: "Production deploy tomorrow, let me refactor today!"
|
|
523
|
+
// CORRECT: Refactor when you have time to test properly
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## Common Scenarios
|
|
527
|
+
|
|
528
|
+
### Scenario 1: Component Too Large (>300 lines)
|
|
529
|
+
|
|
530
|
+
**Fix**:
|
|
531
|
+
1. Extract child components
|
|
532
|
+
2. Extract composables for logic
|
|
533
|
+
3. Extract utilities for helpers
|
|
534
|
+
4. ONE responsibility per file
|
|
535
|
+
|
|
536
|
+
### Scenario 2: Duplicated Code (3+ places)
|
|
537
|
+
|
|
538
|
+
**Fix**:
|
|
539
|
+
1. Identify common pattern
|
|
540
|
+
2. Extract to utility/composable
|
|
541
|
+
3. Write tests
|
|
542
|
+
4. Replace one by one
|
|
543
|
+
5. Delete duplicates
|
|
544
|
+
|
|
545
|
+
### Scenario 3: Hard to Test
|
|
546
|
+
|
|
547
|
+
**Fix**:
|
|
548
|
+
1. Identify dependencies
|
|
549
|
+
2. Extract to parameters
|
|
550
|
+
3. Make functions pure
|
|
551
|
+
4. Write tests with mocks
|
|
552
|
+
|
|
553
|
+
### Scenario 4: Unclear Naming
|
|
554
|
+
|
|
555
|
+
**Fix**:
|
|
556
|
+
1. Rename ONE identifier
|
|
557
|
+
2. Use IDE refactor (F2 in VS Code)
|
|
558
|
+
3. Run tests
|
|
559
|
+
4. Commit
|
|
560
|
+
5. Repeat
|
|
561
|
+
|
|
562
|
+
## Emergency Rollback
|
|
563
|
+
|
|
564
|
+
If refactoring breaks something:
|
|
565
|
+
|
|
566
|
+
```bash
|
|
567
|
+
# Option 1: Revert last commit
|
|
568
|
+
git revert HEAD
|
|
569
|
+
|
|
570
|
+
# Option 2: Restore from backup
|
|
571
|
+
git checkout backup-before-refactor
|
|
572
|
+
git checkout -b refactor-my-feature-v2
|
|
573
|
+
|
|
574
|
+
# Option 3: Stash and investigate
|
|
575
|
+
git stash
|
|
576
|
+
npm run test:run # Pass now?
|
|
577
|
+
git stash pop # Re-apply and fix
|
|
578
|
+
|
|
579
|
+
# Option 4: Nuclear
|
|
580
|
+
git reset --hard origin/development
|
|
581
|
+
# Start over with smaller changes
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## Success Metrics
|
|
585
|
+
|
|
586
|
+
Refactoring succeeds when:
|
|
587
|
+
|
|
588
|
+
✅ All tests pass (no behavior changes)
|
|
589
|
+
✅ Code more readable (clear improvement)
|
|
590
|
+
✅ Complexity reduced (fewer lines, simpler logic)
|
|
591
|
+
✅ Duplication removed (DRY)
|
|
592
|
+
✅ Test coverage maintained/improved
|
|
593
|
+
✅ Performance unchanged/better
|
|
594
|
+
✅ No regressions (manual testing confirms)
|
|
595
|
+
|
|
596
|
+
## Key Commands
|
|
597
|
+
|
|
598
|
+
```bash
|
|
599
|
+
# Before refactoring
|
|
600
|
+
npm run test:run -- --coverage # Check coverage
|
|
601
|
+
docker exec backend pytest --cov # Backend coverage
|
|
602
|
+
git checkout -b backup-before-refactor # Safety backup
|
|
603
|
+
|
|
604
|
+
# During refactoring (after EACH change)
|
|
605
|
+
npm run test:run # Frontend tests
|
|
606
|
+
npm run type-check # TypeScript
|
|
607
|
+
npm run test:patterns # Pattern enforcement
|
|
608
|
+
docker exec backend pytest -v # Backend tests
|
|
609
|
+
git commit -m "refactor: [change]" # Commit success
|
|
610
|
+
|
|
611
|
+
# After refactoring
|
|
612
|
+
npm run build # Verify build
|
|
613
|
+
npm run dev # Manual test
|
|
614
|
+
git push origin refactor-my-feature # Push when complete
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
## Examples
|
|
618
|
+
|
|
619
|
+
### Example 1: Extract Function
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
# 1. Initial state: 80-line function
|
|
623
|
+
# 2. Extract validation (commit)
|
|
624
|
+
git commit -m "refactor: extract validateArticle"
|
|
625
|
+
# 3. Extract image processing (commit)
|
|
626
|
+
git commit -m "refactor: extract processImages"
|
|
627
|
+
# 4. Simplify main function (commit)
|
|
628
|
+
git commit -m "refactor: simplify processArticle"
|
|
629
|
+
# Result: 3 small focused functions
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Example 2: Extract Composable
|
|
633
|
+
|
|
634
|
+
```bash
|
|
635
|
+
# 1. Create useDataLoader composable
|
|
636
|
+
# 2. Write tests for composable
|
|
637
|
+
git commit -m "refactor: add useDataLoader composable"
|
|
638
|
+
# 3. Migrate BlogView (test, commit)
|
|
639
|
+
git commit -m "refactor: BlogView uses useDataLoader"
|
|
640
|
+
# 4. Migrate ArticleView (test, commit)
|
|
641
|
+
git commit -m "refactor: ArticleView uses useDataLoader"
|
|
642
|
+
# 5. Migrate CategoryView (test, commit)
|
|
643
|
+
git commit -m "refactor: CategoryView uses useDataLoader"
|
|
644
|
+
# Result: Eliminated 60 lines of duplication
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
## When to Stop
|
|
648
|
+
|
|
649
|
+
Stop refactoring when:
|
|
650
|
+
- Tests start failing frequently (too aggressive)
|
|
651
|
+
- Code is "good enough" (perfect is enemy of done)
|
|
652
|
+
- Deadline approaching (commit what you have)
|
|
653
|
+
- No measurable benefit (diminishing returns)
|
|
654
|
+
- You're just tweaking style (not improving structure)
|
|
655
|
+
|
|
656
|
+
## Related Resources
|
|
657
|
+
|
|
658
|
+
- [developer-checklist](../developer-checklist/SKILL.md) - Pre-commit validation
|
|
659
|
+
- [feature-implementation](../feature-implementation/SKILL.md) - Adding features
|
|
660
|
+
- [CODEBASE_ESSENTIALS.md](../../../CODEBASE_ESSENTIALS.md) - Current patterns
|
|
661
|
+
- [CODEBASE_CHANGELOG.md](../../../CODEBASE_CHANGELOG.md) - Historical changes
|
|
662
|
+
- [.archive/guides/DRY_REFACTORING_GUIDE.md](../../../.archive/guides/DRY_REFACTORING_GUIDE.md) - Past refactor example
|