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