ccjk 14.1.10 → 14.2.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.
Files changed (119) hide show
  1. package/dist/chunks/agent-teams.mjs +1 -1
  2. package/dist/chunks/api-cli.mjs +1 -1
  3. package/dist/chunks/api-config-selector.mjs +3 -3
  4. package/dist/chunks/ccjk-all.mjs +1 -1
  5. package/dist/chunks/ccjk-mcp.mjs +1 -1
  6. package/dist/chunks/ccjk-setup.mjs +1 -1
  7. package/dist/chunks/ccr.mjs +8 -8
  8. package/dist/chunks/check-updates.mjs +1 -1
  9. package/dist/chunks/claude-code-incremental-manager.mjs +3 -3
  10. package/dist/chunks/claude-config.mjs +1 -1
  11. package/dist/chunks/codex-config-switch.mjs +1 -1
  12. package/dist/chunks/codex-provider-manager.mjs +1 -1
  13. package/dist/chunks/config-switch.mjs +1 -1
  14. package/dist/chunks/config.mjs +19 -3
  15. package/dist/chunks/config2.mjs +1 -1
  16. package/dist/chunks/config3.mjs +1 -1
  17. package/dist/chunks/doctor.mjs +175 -6
  18. package/dist/chunks/features.mjs +3 -3
  19. package/dist/chunks/index10.mjs +19 -5
  20. package/dist/chunks/init.mjs +5 -5
  21. package/dist/chunks/mcp-cli.mjs +3 -3
  22. package/dist/chunks/mcp.mjs +3 -3
  23. package/dist/chunks/package.mjs +1 -1
  24. package/dist/chunks/quick-provider.mjs +1 -1
  25. package/dist/chunks/quick-setup.mjs +5 -5
  26. package/dist/chunks/simple-config.mjs +1 -1
  27. package/dist/chunks/smart-guide.mjs +1 -1
  28. package/dist/chunks/update.mjs +6 -6
  29. package/dist/chunks/zero-config.mjs +7 -4
  30. package/dist/cli.mjs +0 -0
  31. package/dist/index.d.mts +3 -0
  32. package/dist/index.d.ts +3 -0
  33. package/dist/index.mjs +1 -1
  34. package/dist/shared/{ccjk.BJ3Zpjo5.mjs → ccjk.BCzOWT1L.mjs} +3 -2
  35. package/dist/shared/{ccjk.B8oqkakg.mjs → ccjk.BLsIiTqO.mjs} +1 -1
  36. package/dist/shared/{ccjk.Hwoicrh8.mjs → ccjk.BXv8aYs1.mjs} +1 -1
  37. package/dist/shared/{ccjk.B9OuS4xZ.mjs → ccjk.CfKJnpbB.mjs} +1 -1
  38. package/dist/shared/{ccjk.BzxpiEPF.mjs → ccjk.Cgv_cFVX.mjs} +2 -2
  39. package/dist/shared/{ccjk.Di1IYU3u.mjs → ccjk.DDL-4C-k.mjs} +47 -10
  40. package/dist/shared/{ccjk.BEiR3L4C.mjs → ccjk.DOw7Fawt.mjs} +3 -3
  41. package/dist/shared/{ccjk.tI_s2uSh.mjs → ccjk.f3TBLJSt.mjs} +1 -1
  42. package/dist/templates/agents/README.md +78 -0
  43. package/dist/templates/common/error-prevention.md +267 -0
  44. package/dist/templates/common/karpathy-baseline.md +83 -0
  45. package/dist/templates/common/output-styles/zh-CN/carmack-mode.md +381 -0
  46. package/dist/templates/common/output-styles/zh-CN/dhh-mode.md +265 -0
  47. package/dist/templates/common/output-styles/zh-CN/evan-you-mode.md +539 -0
  48. package/dist/templates/common/output-styles/zh-CN/jobs-mode.md +369 -0
  49. package/dist/templates/common/output-styles/zh-CN/linus-mode.md +135 -0
  50. package/dist/templates/common/output-styles/zh-CN/uncle-bob-mode.md +221 -0
  51. package/dist/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +628 -0
  52. package/dist/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +628 -0
  53. package/dist/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +187 -0
  54. package/dist/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +191 -0
  55. package/dist/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +249 -0
  56. package/dist/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +277 -0
  57. package/dist/templates/common/workflow/essential/en/agents/get-current-datetime.md +29 -0
  58. package/dist/templates/common/workflow/essential/en/agents/init-architect.md +115 -0
  59. package/dist/templates/common/workflow/essential/en/agents/ui-ux-designer.md +91 -0
  60. package/dist/templates/common/workflow/essential/en/feat.md +92 -0
  61. package/dist/templates/common/workflow/essential/en/goal.md +147 -0
  62. package/dist/templates/common/workflow/essential/en/init-project.md +53 -0
  63. package/dist/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +29 -0
  64. package/dist/templates/common/workflow/essential/zh-CN/agents/init-architect.md +115 -0
  65. package/dist/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +91 -0
  66. package/dist/templates/common/workflow/essential/zh-CN/feat.md +315 -0
  67. package/dist/templates/common/workflow/essential/zh-CN/goal.md +146 -0
  68. package/dist/templates/common/workflow/essential/zh-CN/init-project.md +53 -0
  69. package/dist/templates/common/workflow/git/en/git-cleanBranches.md +102 -0
  70. package/dist/templates/common/workflow/git/en/git-commit.md +205 -0
  71. package/dist/templates/common/workflow/git/en/git-rollback.md +90 -0
  72. package/dist/templates/common/workflow/git/en/git-worktree.md +276 -0
  73. package/dist/templates/common/workflow/git/zh-CN/git-cleanBranches.md +102 -0
  74. package/dist/templates/common/workflow/git/zh-CN/git-commit.md +205 -0
  75. package/dist/templates/common/workflow/git/zh-CN/git-rollback.md +90 -0
  76. package/dist/templates/common/workflow/git/zh-CN/git-worktree.md +276 -0
  77. package/dist/templates/common/workflow/interview/en/interview.md +67 -0
  78. package/dist/templates/common/workflow/interview/zh-CN/interview.md +67 -0
  79. package/dist/templates/common/workflow/linearMethod/en/linear-method.md +651 -0
  80. package/dist/templates/common/workflow/linearMethod/zh-CN/linear-method.md +752 -0
  81. package/dist/templates/common/workflow/refactoringMaster/en/refactoring-master.md +516 -0
  82. package/dist/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +812 -0
  83. package/dist/templates/common/workflow/sixStep/en/workflow.md +83 -0
  84. package/dist/templates/common/workflow/sixStep/zh-CN/workflow.md +359 -0
  85. package/dist/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +364 -0
  86. package/dist/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +366 -0
  87. package/dist/templates/hooks/README.md +212 -0
  88. package/dist/templates/hooks/git-workflow-hooks.md +551 -0
  89. package/dist/templates/hooks/post-test-coverage.md +434 -0
  90. package/dist/templates/hooks/pre-commit-black.md +274 -0
  91. package/dist/templates/hooks/pre-commit-eslint.md +153 -0
  92. package/dist/templates/hooks/pre-commit-gofmt.md +284 -0
  93. package/dist/templates/hooks/pre-commit-prettier.md +212 -0
  94. package/dist/templates/hooks/pre-commit-type-check.md +377 -0
  95. package/dist/templates/skills/ccjk-init.md +154 -0
  96. package/dist/templates/skills/ccjk-mcp-setup.md +205 -0
  97. package/dist/templates/skills/ccjk-troubleshoot.md +228 -0
  98. package/dist/templates/skills/django-patterns.md +1016 -0
  99. package/dist/templates/skills/git-workflow.md +748 -0
  100. package/dist/templates/skills/go-idioms.md +963 -0
  101. package/dist/templates/skills/nextjs-optimization.md +694 -0
  102. package/dist/templates/skills/python-pep8.md +852 -0
  103. package/dist/templates/skills/react-patterns.md +686 -0
  104. package/dist/templates/skills/rust-patterns.md +1057 -0
  105. package/dist/templates/skills/security-best-practices.md +1413 -0
  106. package/dist/templates/skills/testing-best-practices.md +1315 -0
  107. package/dist/templates/skills/ts-best-practices.md +354 -0
  108. package/package.json +40 -43
  109. package/templates/common/karpathy-baseline.md +83 -0
  110. package/templates/common/output-styles/zh-CN/carmack-mode.md +14 -0
  111. package/templates/common/output-styles/zh-CN/dhh-mode.md +14 -0
  112. package/templates/common/output-styles/zh-CN/evan-you-mode.md +14 -0
  113. package/templates/common/output-styles/zh-CN/jobs-mode.md +14 -0
  114. package/templates/common/output-styles/zh-CN/linus-mode.md +14 -0
  115. package/templates/common/output-styles/zh-CN/uncle-bob-mode.md +14 -0
  116. package/templates/common/workflow/linearMethod/zh-CN/linear-method.md +2 -0
  117. package/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +2 -0
  118. package/templates/common/workflow/sixStep/zh-CN/workflow.md +2 -0
  119. package/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +2 -0
@@ -0,0 +1,812 @@
1
+ ---
2
+ description: 重构大师模式 - 基于 Martin Fowler 重构模式,小步快跑改善代码设计,降低技术债务
3
+ allowed-tools: Read(**), Write(**), Exec(npm test, npm run lint, git diff)
4
+ argument-hint: [--pattern <pattern-name>] [--scope <file|module|system>] [--safe-mode]
5
+ # examples:
6
+ # - /refactoring-master # 启动重构流程
7
+ # - /refactoring-master --pattern extract-method # 应用特定重构模式
8
+ # - /refactoring-master --safe-mode # 安全模式(每步运行测试)
9
+ ---
10
+
11
+ > **基于 Discipline Baseline**:本 workflow 在 4 条全局原则(Think / Simplicity / Surgical / Goal-driven)之上提供更具体的流程编排。当本文档与 baseline 冲突,**baseline 优先**。
12
+
13
+ # Refactoring Master Mode
14
+
15
+ 基于 Martin Fowler 的《重构:改善既有代码的设计》(第 2 版),系统化地改善代码质量。
16
+
17
+ ---
18
+
19
+ ## 核心理念
20
+
21
+ **重构(Refactoring)**:在不改变代码外部行为的前提下,改善代码内部结构。
22
+
23
+ **关键原则**:
24
+ 1. **小步前进**:每次只做一个小改动
25
+ 2. **测试保护**:重构前后测试必须通过
26
+ 3. **持续集成**:频繁提交,避免大规模合并冲突
27
+ 4. **识别坏味道**:系统化识别需要重构的代码
28
+ 5. **应用模式**:使用经过验证的重构手法
29
+
30
+ ---
31
+
32
+ ## Refactoring Workflow
33
+
34
+ ### Phase 1: Code Smell Detection(识别代码坏味道)
35
+
36
+ **目标**:系统化识别需要改进的代码
37
+
38
+ #### 常见代码坏味道
39
+
40
+ ##### 1. 神秘命名(Mysterious Name)
41
+
42
+ ```typescript
43
+ // ❌ Bad: 命名不清晰
44
+ function calc(a: number, b: number): number {
45
+ return a * b * 0.9
46
+ }
47
+
48
+ // ✅ Good: 清晰表达意图
49
+ function calculateDiscountedPrice(originalPrice: number, quantity: number): number {
50
+ const DISCOUNT_RATE = 0.9
51
+ return originalPrice * quantity * DISCOUNT_RATE
52
+ }
53
+ ```
54
+
55
+ ##### 2. 重复代码(Duplicated Code)
56
+
57
+ ```typescript
58
+ // ❌ Bad: 重复的验证逻辑
59
+ function createUser(data: UserData) {
60
+ if (!data.email || !data.email.includes('@')) {
61
+ throw new Error('Invalid email')
62
+ }
63
+ if (!data.password || data.password.length < 8) {
64
+ throw new Error('Password too short')
65
+ }
66
+ // ...
67
+ }
68
+
69
+ function updateUser(id: string, data: UserData) {
70
+ if (!data.email || !data.email.includes('@')) {
71
+ throw new Error('Invalid email')
72
+ }
73
+ if (!data.password || data.password.length < 8) {
74
+ throw new Error('Password too short')
75
+ }
76
+ // ...
77
+ }
78
+
79
+ // ✅ Good: 提取共同验证逻辑
80
+ function validateUserData(data: UserData) {
81
+ if (!data.email || !data.email.includes('@')) {
82
+ throw new Error('Invalid email')
83
+ }
84
+ if (!data.password || data.password.length < 8) {
85
+ throw new Error('Password too short')
86
+ }
87
+ }
88
+
89
+ function createUser(data: UserData) {
90
+ validateUserData(data)
91
+ // ...
92
+ }
93
+
94
+ function updateUser(id: string, data: UserData) {
95
+ validateUserData(data)
96
+ // ...
97
+ }
98
+ ```
99
+
100
+ ##### 3. 过长函数(Long Function)
101
+
102
+ ```typescript
103
+ // ❌ Bad: 100+ 行的函数
104
+ function processOrder(order: Order) {
105
+ // 验证订单(20 行)
106
+ // 计算价格(30 行)
107
+ // 检查库存(25 行)
108
+ // 创建发货单(20 行)
109
+ // 发送通知(15 行)
110
+ }
111
+
112
+ // ✅ Good: 拆分为多个小函数
113
+ function processOrder(order: Order) {
114
+ validateOrder(order)
115
+ const totalPrice = calculateTotalPrice(order)
116
+ checkInventory(order.items)
117
+ createShipment(order)
118
+ sendNotifications(order)
119
+ }
120
+ ```
121
+
122
+ ##### 4. 过长参数列表(Long Parameter List)
123
+
124
+ ```typescript
125
+ // ❌ Bad: 6 个参数
126
+ function createInvoice(
127
+ customerId: string,
128
+ customerName: string,
129
+ customerEmail: string,
130
+ items: Item[],
131
+ discount: number,
132
+ taxRate: number
133
+ ) { }
134
+
135
+ // ✅ Good: 使用对象参数
136
+ interface InvoiceParams {
137
+ customer: {
138
+ id: string
139
+ name: string
140
+ email: string
141
+ }
142
+ items: Item[]
143
+ pricing: {
144
+ discount: number
145
+ taxRate: number
146
+ }
147
+ }
148
+
149
+ function createInvoice(params: InvoiceParams) { }
150
+ ```
151
+
152
+ ##### 5. 发散式变化(Divergent Change)
153
+
154
+ ```typescript
155
+ // ❌ Bad: 一个类承担多种变化原因
156
+ class User {
157
+ // 用户数据管理
158
+ updateProfile() { }
159
+ changePassword() { }
160
+
161
+ // 权限管理
162
+ grantPermission() { }
163
+ revokePermission() { }
164
+
165
+ // 通知管理
166
+ sendEmail() { }
167
+ sendSMS() { }
168
+ }
169
+
170
+ // ✅ Good: 按职责分离
171
+ class User {
172
+ updateProfile() { }
173
+ changePassword() { }
174
+ }
175
+
176
+ class UserPermissions {
177
+ grant() { }
178
+ revoke() { }
179
+ }
180
+
181
+ class UserNotifications {
182
+ sendEmail() { }
183
+ sendSMS() { }
184
+ }
185
+ ```
186
+
187
+ ##### 6. 霰弹式修改(Shotgun Surgery)
188
+
189
+ ```typescript
190
+ // ❌ Bad: 修改一个功能需要改多个文件
191
+ // file1.ts
192
+ const TAX_RATE = 0.08
193
+
194
+ // file2.ts
195
+ const TAX_RATE = 0.08
196
+
197
+ // file3.ts
198
+ const TAX_RATE = 0.08
199
+
200
+ // ✅ Good: 集中配置
201
+ // config.ts
202
+ export const TAX_RATE = 0.08
203
+
204
+ // file1.ts, file2.ts, file3.ts
205
+ import { TAX_RATE } from './config'
206
+ ```
207
+
208
+ ##### 7. 依恋情结(Feature Envy)
209
+
210
+ ```typescript
211
+ // ❌ Bad: 函数过度使用另一个类的数据
212
+ class Order {
213
+ calculateTotal(customer: Customer) {
214
+ let total = this.basePrice
215
+ if (customer.loyaltyLevel === 'gold') {
216
+ total *= 0.9
217
+ } else if (customer.loyaltyLevel === 'silver') {
218
+ total *= 0.95
219
+ }
220
+ return total
221
+ }
222
+ }
223
+
224
+ // ✅ Good: 将逻辑移到数据所在的类
225
+ class Customer {
226
+ getDiscountRate(): number {
227
+ if (this.loyaltyLevel === 'gold') return 0.9
228
+ if (this.loyaltyLevel === 'silver') return 0.95
229
+ return 1.0
230
+ }
231
+ }
232
+
233
+ class Order {
234
+ calculateTotal(customer: Customer) {
235
+ return this.basePrice * customer.getDiscountRate()
236
+ }
237
+ }
238
+ ```
239
+
240
+ ##### 8. 数据泥团(Data Clumps)
241
+
242
+ ```typescript
243
+ // ❌ Bad: 总是一起出现的数据
244
+ function createAddress(street: string, city: string, zipCode: string) { }
245
+ function validateAddress(street: string, city: string, zipCode: string) { }
246
+ function formatAddress(street: string, city: string, zipCode: string) { }
247
+
248
+ // ✅ Good: 封装为对象
249
+ interface Address {
250
+ street: string
251
+ city: string
252
+ zipCode: string
253
+ }
254
+
255
+ function createAddress(address: Address) { }
256
+ function validateAddress(address: Address) { }
257
+ function formatAddress(address: Address) { }
258
+ ```
259
+
260
+ ##### 9. 基本类型偏执(Primitive Obsession)
261
+
262
+ ```typescript
263
+ // ❌ Bad: 使用基本类型表示领域概念
264
+ function sendEmail(email: string) {
265
+ // 每次都要验证
266
+ if (!email.includes('@')) {
267
+ throw new Error('Invalid email')
268
+ }
269
+ }
270
+
271
+ // ✅ Good: 使用值对象
272
+ class Email {
273
+ private constructor(private readonly value: string) {
274
+ if (!value.includes('@')) {
275
+ throw new Error('Invalid email')
276
+ }
277
+ }
278
+
279
+ static create(value: string): Email {
280
+ return new Email(value)
281
+ }
282
+
283
+ toString(): string {
284
+ return this.value
285
+ }
286
+ }
287
+
288
+ function sendEmail(email: Email) {
289
+ // 不需要验证,类型系统保证有效性
290
+ }
291
+ ```
292
+
293
+ ##### 10. 过长的条件语句(Long Conditional)
294
+
295
+ ```typescript
296
+ // ❌ Bad: 复杂的条件判断
297
+ function getShippingCost(order: Order): number {
298
+ if (order.total > 100 && order.customer.isPremium && order.destination === 'domestic') {
299
+ return 0
300
+ } else if (order.total > 50 && order.customer.isPremium) {
301
+ return 5
302
+ } else if (order.destination === 'international') {
303
+ return 20
304
+ } else {
305
+ return 10
306
+ }
307
+ }
308
+
309
+ // ✅ Good: 使用策略模式
310
+ interface ShippingStrategy {
311
+ calculate(order: Order): number
312
+ }
313
+
314
+ class FreeShipping implements ShippingStrategy {
315
+ calculate(order: Order): number {
316
+ return 0
317
+ }
318
+ }
319
+
320
+ class StandardShipping implements ShippingStrategy {
321
+ calculate(order: Order): number {
322
+ return order.destination === 'international' ? 20 : 10
323
+ }
324
+ }
325
+
326
+ class ShippingCalculator {
327
+ calculate(order: Order): number {
328
+ const strategy = this.selectStrategy(order)
329
+ return strategy.calculate(order)
330
+ }
331
+
332
+ private selectStrategy(order: Order): ShippingStrategy {
333
+ if (this.qualifiesForFreeShipping(order)) {
334
+ return new FreeShipping()
335
+ }
336
+ return new StandardShipping()
337
+ }
338
+
339
+ private qualifiesForFreeShipping(order: Order): boolean {
340
+ return order.total > 100 &&
341
+ order.customer.isPremium &&
342
+ order.destination === 'domestic'
343
+ }
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ### Phase 2: Refactoring Catalog(重构手法目录)
350
+
351
+ #### 提取函数(Extract Function)
352
+
353
+ **时机**:函数过长,或需要注释才能理解的代码块
354
+
355
+ ```typescript
356
+ // Before
357
+ function printOwing(invoice: Invoice) {
358
+ let outstanding = 0
359
+
360
+ console.log('***********************')
361
+ console.log('**** Customer Owes ****')
362
+ console.log('***********************')
363
+
364
+ // calculate outstanding
365
+ for (const order of invoice.orders) {
366
+ outstanding += order.amount
367
+ }
368
+
369
+ // record due date
370
+ const today = new Date()
371
+ invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30)
372
+
373
+ // print details
374
+ console.log(`name: ${invoice.customer}`)
375
+ console.log(`amount: ${outstanding}`)
376
+ console.log(`due: ${invoice.dueDate.toLocaleDateString()}`)
377
+ }
378
+
379
+ // After
380
+ function printOwing(invoice: Invoice) {
381
+ printBanner()
382
+ const outstanding = calculateOutstanding(invoice)
383
+ recordDueDate(invoice)
384
+ printDetails(invoice, outstanding)
385
+ }
386
+
387
+ function printBanner() {
388
+ console.log('***********************')
389
+ console.log('**** Customer Owes ****')
390
+ console.log('***********************')
391
+ }
392
+
393
+ function calculateOutstanding(invoice: Invoice): number {
394
+ return invoice.orders.reduce((sum, order) => sum + order.amount, 0)
395
+ }
396
+
397
+ function recordDueDate(invoice: Invoice) {
398
+ const today = new Date()
399
+ invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30)
400
+ }
401
+
402
+ function printDetails(invoice: Invoice, outstanding: number) {
403
+ console.log(`name: ${invoice.customer}`)
404
+ console.log(`amount: ${outstanding}`)
405
+ console.log(`due: ${invoice.dueDate.toLocaleDateString()}`)
406
+ }
407
+ ```
408
+
409
+ #### 内联函数(Inline Function)
410
+
411
+ **时机**:函数体和函数名一样清晰,或函数过度拆分
412
+
413
+ ```typescript
414
+ // Before
415
+ function getRating(driver: Driver): number {
416
+ return moreThanFiveLateDeliveries(driver) ? 2 : 1
417
+ }
418
+
419
+ function moreThanFiveLateDeliveries(driver: Driver): boolean {
420
+ return driver.numberOfLateDeliveries > 5
421
+ }
422
+
423
+ // After
424
+ function getRating(driver: Driver): number {
425
+ return driver.numberOfLateDeliveries > 5 ? 2 : 1
426
+ }
427
+ ```
428
+
429
+ #### 提取变量(Extract Variable)
430
+
431
+ **时机**:表达式复杂难懂
432
+
433
+ ```typescript
434
+ // Before
435
+ function price(order: Order): number {
436
+ return order.quantity * order.itemPrice -
437
+ Math.max(0, order.quantity - 500) * order.itemPrice * 0.05 +
438
+ Math.min(order.quantity * order.itemPrice * 0.1, 100)
439
+ }
440
+
441
+ // After
442
+ function price(order: Order): number {
443
+ const basePrice = order.quantity * order.itemPrice
444
+ const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05
445
+ const shipping = Math.min(basePrice * 0.1, 100)
446
+ return basePrice - quantityDiscount + shipping
447
+ }
448
+ ```
449
+
450
+ #### 引入参数对象(Introduce Parameter Object)
451
+
452
+ **时机**:多个参数总是一起出现
453
+
454
+ ```typescript
455
+ // Before
456
+ function amountInvoiced(startDate: Date, endDate: Date) { }
457
+ function amountReceived(startDate: Date, endDate: Date) { }
458
+ function amountOverdue(startDate: Date, endDate: Date) { }
459
+
460
+ // After
461
+ class DateRange {
462
+ constructor(
463
+ public readonly start: Date,
464
+ public readonly end: Date
465
+ ) { }
466
+ }
467
+
468
+ function amountInvoiced(dateRange: DateRange) { }
469
+ function amountReceived(dateRange: DateRange) { }
470
+ function amountOverdue(dateRange: DateRange) { }
471
+ ```
472
+
473
+ #### 以多态取代条件表达式(Replace Conditional with Polymorphism)
474
+
475
+ **时机**:根据类型码进行条件判断
476
+
477
+ ```typescript
478
+ // Before
479
+ class Bird {
480
+ constructor(public type: string) { }
481
+
482
+ getSpeed(): number {
483
+ switch (this.type) {
484
+ case 'european':
485
+ return 35
486
+ case 'african':
487
+ return 40
488
+ case 'norwegian-blue':
489
+ return this.isNailed ? 0 : 10
490
+ default:
491
+ throw new Error('Unknown bird type')
492
+ }
493
+ }
494
+ }
495
+
496
+ // After
497
+ abstract class Bird {
498
+ abstract getSpeed(): number
499
+ }
500
+
501
+ class EuropeanBird extends Bird {
502
+ getSpeed(): number {
503
+ return 35
504
+ }
505
+ }
506
+
507
+ class AfricanBird extends Bird {
508
+ getSpeed(): number {
509
+ return 40
510
+ }
511
+ }
512
+
513
+ class NorwegianBlueBird extends Bird {
514
+ constructor(private isNailed: boolean) {
515
+ super()
516
+ }
517
+
518
+ getSpeed(): number {
519
+ return this.isNailed ? 0 : 10
520
+ }
521
+ }
522
+ ```
523
+
524
+ #### 拆分循环(Split Loop)
525
+
526
+ **时机**:一个循环做多件事
527
+
528
+ ```typescript
529
+ // Before
530
+ let youngest = people[0] ? people[0].age : Infinity
531
+ let totalSalary = 0
532
+ for (const person of people) {
533
+ if (person.age < youngest) youngest = person.age
534
+ totalSalary += person.salary
535
+ }
536
+
537
+ // After
538
+ let youngest = people[0] ? people[0].age : Infinity
539
+ for (const person of people) {
540
+ if (person.age < youngest) youngest = person.age
541
+ }
542
+
543
+ let totalSalary = 0
544
+ for (const person of people) {
545
+ totalSalary += person.salary
546
+ }
547
+
548
+ // Better: 使用函数式编程
549
+ const youngest = Math.min(...people.map(p => p.age))
550
+ const totalSalary = people.reduce((sum, p) => sum + p.salary, 0)
551
+ ```
552
+
553
+ #### 移除死代码(Remove Dead Code)
554
+
555
+ **时机**:代码不再被使用
556
+
557
+ ```typescript
558
+ // Before
559
+ function oldFeature() {
560
+ // 这个功能已经被新版本替代
561
+ // 但代码还在这里
562
+ }
563
+
564
+ function newFeature() {
565
+ // 新实现
566
+ }
567
+
568
+ // After
569
+ function newFeature() {
570
+ // 新实现
571
+ }
572
+ // 直接删除 oldFeature,版本控制系统会保留历史
573
+ ```
574
+
575
+ ---
576
+
577
+ ### Phase 3: Safe Refactoring Process(安全重构流程)
578
+
579
+ #### 步骤 1: 确保测试覆盖
580
+
581
+ ```bash
582
+ # 运行测试,确保当前代码正常工作
583
+ npm test
584
+
585
+ # 检查覆盖率
586
+ npm run coverage
587
+
588
+ # 如果覆盖率不足,先补充测试
589
+ ```
590
+
591
+ #### 步骤 2: 小步重构
592
+
593
+ ```typescript
594
+ // 每次只做一个小改动
595
+ // 例如:先提取变量
596
+ const basePrice = order.quantity * order.itemPrice
597
+
598
+ // 运行测试
599
+ npm test // ✅ 通过
600
+
601
+ // 再提取下一个变量
602
+ const quantityDiscount = Math.max(0, order.quantity - 500) * order.itemPrice * 0.05
603
+
604
+ // 再次运行测试
605
+ npm test // ✅ 通过
606
+ ```
607
+
608
+ #### 步骤 3: 频繁提交
609
+
610
+ ```bash
611
+ # 每完成一个小重构就提交
612
+ git add .
613
+ git commit -m "refactor: extract basePrice variable"
614
+
615
+ # 继续下一个重构
616
+ # ...
617
+
618
+ git commit -m "refactor: extract quantityDiscount variable"
619
+ ```
620
+
621
+ #### 步骤 4: 使用 IDE 自动重构
622
+
623
+ ```typescript
624
+ // 使用 IDE 的重构功能(更安全)
625
+ // - Rename Symbol (F2)
626
+ // - Extract Method
627
+ // - Extract Variable
628
+ // - Inline Variable
629
+ // - Move to File
630
+ ```
631
+
632
+ ---
633
+
634
+ ### Phase 4: Refactoring Patterns(重构模式)
635
+
636
+ #### 模式 1: 分层架构重构
637
+
638
+ ```typescript
639
+ // Before: 所有逻辑混在一起
640
+ app.post('/users', async (req, res) => {
641
+ // 验证
642
+ if (!req.body.email || !req.body.email.includes('@')) {
643
+ return res.status(400).json({ error: 'Invalid email' })
644
+ }
645
+
646
+ // 业务逻辑
647
+ const hashedPassword = await bcrypt.hash(req.body.password, 10)
648
+ const user = {
649
+ email: req.body.email,
650
+ password: hashedPassword,
651
+ createdAt: new Date()
652
+ }
653
+
654
+ // 数据访问
655
+ await db.collection('users').insertOne(user)
656
+
657
+ res.json({ id: user._id })
658
+ })
659
+
660
+ // After: 分层架构
661
+ // Controller Layer
662
+ class UserController {
663
+ async create(req: Request, res: Response) {
664
+ const dto = CreateUserDto.from(req.body)
665
+ const user = await this.userService.create(dto)
666
+ res.json({ id: user.id })
667
+ }
668
+ }
669
+
670
+ // Service Layer
671
+ class UserService {
672
+ async create(dto: CreateUserDto): Promise<User> {
673
+ const hashedPassword = await this.passwordHasher.hash(dto.password)
674
+ const user = User.create(dto.email, hashedPassword)
675
+ return await this.userRepository.save(user)
676
+ }
677
+ }
678
+
679
+ // Repository Layer
680
+ class UserRepository {
681
+ async save(user: User): Promise<User> {
682
+ await this.db.collection('users').insertOne(user)
683
+ return user
684
+ }
685
+ }
686
+ ```
687
+
688
+ #### 模式 2: 依赖注入重构
689
+
690
+ ```typescript
691
+ // Before: 硬编码依赖
692
+ class OrderService {
693
+ processOrder(order: Order) {
694
+ const payment = new PaymentService() // 硬编码
695
+ const shipping = new ShippingService() // 硬编码
696
+ payment.charge(order.total)
697
+ shipping.ship(order)
698
+ }
699
+ }
700
+
701
+ // After: 依赖注入
702
+ class OrderService {
703
+ constructor(
704
+ private paymentService: PaymentService,
705
+ private shippingService: ShippingService
706
+ ) { }
707
+
708
+ processOrder(order: Order) {
709
+ this.paymentService.charge(order.total)
710
+ this.shippingService.ship(order)
711
+ }
712
+ }
713
+
714
+ // 便于测试
715
+ const mockPayment = new MockPaymentService()
716
+ const mockShipping = new MockShippingService()
717
+ const service = new OrderService(mockPayment, mockShipping)
718
+ ```
719
+
720
+ #### 模式 3: 领域模型重构
721
+
722
+ ```typescript
723
+ // Before: 贫血模型
724
+ interface User {
725
+ id: string
726
+ email: string
727
+ password: string
728
+ createdAt: Date
729
+ }
730
+
731
+ function changePassword(user: User, newPassword: string) {
732
+ if (newPassword.length < 8) {
733
+ throw new Error('Password too short')
734
+ }
735
+ user.password = hashPassword(newPassword)
736
+ }
737
+
738
+ // After: 充血模型
739
+ class User {
740
+ private constructor(
741
+ public readonly id: string,
742
+ public readonly email: Email,
743
+ private password: HashedPassword,
744
+ public readonly createdAt: Date
745
+ ) { }
746
+
747
+ changePassword(newPassword: string) {
748
+ const hashed = HashedPassword.create(newPassword)
749
+ this.password = hashed
750
+ }
751
+
752
+ verifyPassword(password: string): boolean {
753
+ return this.password.verify(password)
754
+ }
755
+ }
756
+ ```
757
+
758
+ ---
759
+
760
+ ## Refactoring Checklist
761
+
762
+ ### 重构前
763
+
764
+ - [ ] 代码有足够的测试覆盖
765
+ - [ ] 所有测试都通过
766
+ - [ ] 代码已提交到版本控制
767
+ - [ ] 理解要重构的代码
768
+ - [ ] 确定重构目标
769
+
770
+ ### 重构中
771
+
772
+ - [ ] 每次只做一个小改动
773
+ - [ ] 每次改动后运行测试
774
+ - [ ] 保持测试绿色
775
+ - [ ] 频繁提交
776
+ - [ ] 使用 IDE 自动重构功能
777
+
778
+ ### 重构后
779
+
780
+ - [ ] 所有测试通过
781
+ - [ ] 代码更易理解
782
+ - [ ] 代码更易修改
783
+ - [ ] 没有引入新的 bug
784
+ - [ ] 性能没有明显下降
785
+
786
+ ---
787
+
788
+ ## Command Options
789
+
790
+ - `--pattern <name>`:应用特定重构模式
791
+ - `--scope <file|module|system>`:重构范围
792
+ - `--safe-mode`:每步都运行测试
793
+ - `--dry-run`:预览重构效果
794
+
795
+ ---
796
+
797
+ ## Success Metrics
798
+
799
+ - ✅ 代码复杂度降低 30%
800
+ - ✅ 代码重复率 < 5%
801
+ - ✅ 平均函数长度 < 20 行
802
+ - ✅ 技术债务减少 60%
803
+ - ✅ 新功能开发速度提升 40%
804
+
805
+ ---
806
+
807
+ ## References
808
+
809
+ - Martin Fowler - *Refactoring: Improving the Design of Existing Code* (2nd Edition)
810
+ - Robert C. Martin - *Clean Code*
811
+ - Joshua Kerievsky - *Refactoring to Patterns*
812
+ - Michael Feathers - *Working Effectively with Legacy Code*