Files
monisuo/.agents/skills/clean-code/SKILL.md
2026-03-23 00:08:19 +08:00

517 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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<string, User>;
}
// ✅ 好 - 使用适配器模式
interface UserMap {
get(key: string): User;
set(key: string, user: User): void;
}
class ThirdPartyUserMap implements UserMap {
private map: Map<string, User>;
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. **代码坏味道识别**:参考常见问题
告诉我需要审查的代码,我会帮你识别问题并提供改进建议!