--- name: clean-code description: Clean Code 代码质量审查和重构指南。用于代码审查、重构、提升代码质量、减少技术债务。触发词:代码审查、clean code、重构、代码质量、技术债务、代码规范。 --- # Clean Code 技能 帮助编写高质量、可维护、可读性强的代码。 ## 核心原则 ### 1. 有意义的命名 ```typescript // ❌ 坏 const d = new Date(); const ymd = date.split('-'); // ✅ 好 const currentDate = new Date(); const [year, month, day] = date.split('-'); ``` **规则:** - 使用描述性名称,避免缩写 - 名称应该表达意图 - 避免误导性名称 - 做有意义的区分(不是 a1, a2) - 使用可搜索的名称 - 类名用名词,方法名用动词 ### 2. 函数 ```typescript // ❌ 坏 - 做太多事 function processUser(user: User) { // 验证 if (!user.email) throw new Error('Email required'); if (!user.name) throw new Error('Name required'); // 保存 database.save(user); // 发送邮件 emailService.send(user.email, 'Welcome!'); // 记录日志 logger.log(`User ${user.name} created`); } // ✅ 好 - 单一职责 function validateUser(user: User): void { if (!user.email) throw new Error('Email required'); if (!user.name) throw new Error('Name required'); } function saveUser(user: User): void { database.save(user); } function sendWelcomeEmail(user: User): void { emailService.send(user.email, 'Welcome!'); } function logUserCreation(user: User): void { logger.log(`User ${user.name} created`); } function processUser(user: User) { validateUser(user); saveUser(user); sendWelcomeEmail(user); logUserCreation(user); } ``` **规则:** - 函数应该小(<20行) - 只做一件事 - 每个函数一个抽象层级 - 使用描述性名称 - 函数参数越少越好(理想0-3个) - 避免副作用 - 分隔指令与询问 ### 3. 注释 ```typescript // ❌ 坏 - 多余的注释 // 检查用户是否已激活 if (user.isActive) { ... } // ✅ 好 - 代码自解释 if (user.isActive) { ... } // ✅ 好 - 解释为什么 // 使用 setTimeout 而不是 setInterval 避免重叠执行 setTimeout(processQueue, 1000); ``` **规则:** - 好的代码是自解释的 - 注释不能弥补糟糕的代码 - 用代码表达意图 - 好的注释:法律信息、解释意图、警示、TODO - 坏的注释:喃喃自语、多余的、误导的、注释掉的代码 ### 4. 格式 ```typescript // ❌ 坏 export class User{constructor(private name:string,private age:number){} getName(){return this.name;}} // ✅ 好 export class User { constructor( private name: string, private age: number ) {} getName(): string { return this.name; } } ``` **规则:** - 垂直格式:概念之间用空行分隔 - 水平格式:行宽<120字符 - 缩进:统一使用2或4空格 - 团队规则:遵循项目既定风格 ### 5. 对象和数据结构 ```typescript // ❌ 坏 - 暴露内部结构 class User { public name: string; public age: number; } // ✅ 好 - 隐藏实现 class User { private _name: string; private _age: number; get name(): string { return this._name; } set age(value: number) { if (value < 0) throw new Error('Invalid age'); this._age = value; } } ``` **规则:** - 数据抽象:隐藏实现 - 数据、对象的反对称性 - 得墨忒耳定律:模块不应知道它操作对象的内部细节 ### 6. 错误处理 ```typescript // ❌ 坏 - 返回 null function getUser(id: string): User | null { return database.find(id); } // ✅ 好 - 抛出异常 function getUser(id: string): User { const user = database.find(id); if (!user) throw new UserNotFoundError(id); return user; } // ✅ 好 - 使用 Special Case 模式 class NullUser implements User { name = 'Guest'; age = 0; } ``` **规则:** - 使用异常而非返回码 - 先写 Try-Catch-Finally - 给出异常的上下文 - 别返回 null 值 - 别传递 null 值 ### 7. 边界 ```typescript // ❌ 坏 - 直接依赖第三方类 import { Map } from 'third-party-lib'; class UserCollection { private users: Map; } // ✅ 好 - 使用适配器模式 interface UserMap { get(key: string): User; set(key: string, user: User): void; } class ThirdPartyUserMap implements UserMap { private map: Map; get(key: string): User { return this.map.get(key); } set(key: string, user: User): void { this.map.set(key, user); } } ``` **规则:** - 隐藏第三方代码 - 使用适配器模式 - 边界处的代码需要清晰的分割和测试 ### 8. 单元测试 ```typescript // ❌ 坏 - 不清晰的测试 test('user', () => { const u = new User('John', 25); expect(u.getName()).toBe('John'); expect(u.getAge()).toBe(25); }); // ✅ 好 - BUILD-OPERATE-CHECK 模式 test('shouldReturnUserName', () => { // BUILD const user = new User('John', 25); // OPERATE const name = user.getName(); // CHECK expect(name).toBe('John'); }); // ✅ 好 - Given-When-Then 模式 test('shouldReturnUserName', () => { // Given const user = new User('John', 25); // When const name = user.getName(); // Then expect(name).toBe('John'); }); ``` **规则:** - F.I.R.S.T 原则: - Fast(快速) - Independent(独立) - Repeatable(可重复) - Self-Validating(自验证) - Timely(及时) - 每个测试一个断言 - 单一概念 - 测试代码和生产代码一样重要 ### 9. 类 ```typescript // ❌ 坏 - 大类 class UserManager { createUser() {} deleteUser() {} updateUser() {} sendEmail() {} validateEmail() {} generateReport() {} } // ✅ 好 - 单一职责 class UserService { create(user: User) {} delete(id: string) {} update(user: User) {} } class EmailService { send(email: string, content: string) {} validate(email: string): boolean {} } class ReportService { generate(userId: string): Report {} } ``` **规则:** - 类应该小 - 单一职责原则(SRP) - 内聚性:方法和数据互相依赖 - 保持内聚性就会得到许多短小的类 ### 10. 系统 ```typescript // ❌ 坏 - 硬编码依赖 class UserService { private db = new Database(); // 硬编码 } // ✅ 好 - 依赖注入 class UserService { constructor(private db: Database) {} } // ✅ 好 - 工厂模式 class ServiceFactory { static createUserService(): UserService { return new UserService(new Database()); } } ``` **规则:** - 分离构造和使用 - 依赖注入 - 扩充:AOP(面向切面编程) - 测试驱动系统架构 ## 代码审查清单 ### 命名 - [ ] 变量名是否描述了其用途? - [ ] 函数名是否描述了其行为? - [ ] 类名是否描述了其职责? - [ ] 名称是否一致? ### 函数 - [ ] 函数是否小于20行? - [ ] 函数是否只做一件事? - [ ] 函数参数是否<=3个? - [ ] 函数是否有副作用? - [ ] 函数名是否描述性? ### 结构 - [ ] 代码是否有清晰的层次结构? - [ ] 类是否遵循单一职责原则? - [ ] 是否有重复代码? - [ ] 依赖是否清晰? ### 测试 - [ ] 是否有足够的测试覆盖? - [ ] 测试是否快速? - [ ] 测试是否独立? - [ ] 测试是否清晰? ### 错误处理 - [ ] 是否处理了所有可能的错误? - [ ] 错误信息是否清晰? - [ ] 是否避免了返回 null? ## 重构技巧 ### 提取方法 ```typescript // Before function printOwing(invoice: Invoice) { let outstanding = 0; // 打印横幅 console.log('***********************'); console.log('*** Customer Owes ***'); console.log('***********************'); // 计算未付款 for (const order of invoice.orders) { outstanding += order.amount; } // 打印详情 console.log(`name: ${invoice.customer}`); console.log(`amount: ${outstanding}`); } // After function printOwing(invoice: Invoice) { printBanner(); const outstanding = calculateOutstanding(invoice); printDetails(invoice, outstanding); } function printBanner() { console.log('***********************'); console.log('*** Customer Owes ***'); console.log('***********************'); } function calculateOutstanding(invoice: Invoice): number { return invoice.orders.reduce((sum, order) => sum + order.amount, 0); } function printDetails(invoice: Invoice, outstanding: number) { console.log(`name: ${invoice.customer}`); console.log(`amount: ${outstanding}`); } ``` ### 内联方法 ```typescript // Before function getRating(driver: Driver): number { return moreThanFiveLateDeliveries(driver) ? 2 : 1; } function moreThanFiveLateDeliveries(driver: Driver): boolean { return driver.numberOfLateDeliveries > 5; } // After function getRating(driver: Driver): number { return driver.numberOfLateDeliveries > 5 ? 2 : 1; } ``` ### 提取变量 ```typescript // Before if (platform.toUpperCase().indexOf('MAC') > -1 && browser.toUpperCase().indexOf('IE') > -1 && wasInitialized() && resize > 0) { // do something } // After const isMacOs = platform.toUpperCase().indexOf('MAC') > -1; const isIE = browser.toUpperCase().indexOf('IE') > -1; const wasResized = resize > 0; if (isMacOs && isIE && wasInitialized() && wasResized) { // do something } ``` ### 分解条件 ```typescript // Before if (date.before(SUMMER_START) || date.after(SUMMER_END)) { charge = quantity * winterRate + winterServiceCharge; } else { charge = quantity * summerRate; } // After if (isSummer(date)) { charge = summerCharge(quantity); } else { charge = winterCharge(quantity); } function isSummer(date: Date): boolean { return !date.before(SUMMER_START) && !date.after(SUMMER_END); } function summerCharge(quantity: number): number { return quantity * summerRate; } function winterCharge(quantity: number): number { return quantity * winterRate + winterServiceCharge; } ``` ### 以多态取代条件 ```typescript // Before function calculatePay(employee: Employee): number { switch (employee.type) { case 'ENGINEER': return employee.monthlySalary; case 'SALESMAN': return employee.monthlySalary + employee.commission; case 'MANAGER': return employee.monthlySalary + employee.bonus; default: throw new Error('Invalid employee type'); } } // After abstract class Employee { abstract calculatePay(): number; } class Engineer extends Employee { calculatePay(): number { return this.monthlySalary; } } class Salesman extends Employee { calculatePay(): number { return this.monthlySalary + this.commission; } } class Manager extends Employee { calculatePay(): number { return this.monthlySalary + this.bonus; } } ``` ## 使用方法 1. **代码审查时**:参考清单逐项检查 2. **重构时**:应用重构技巧 3. **新功能开发时**:遵循核心原则 4. **代码坏味道识别**:参考常见问题 告诉我需要审查的代码,我会帮你识别问题并提供改进建议!