# 步骤3：代码质量检查

## ⚠️ 执行前必读规范

**🔥 重要：在执行本步骤之前，AI必须先完整阅读同级目录下的 `README.md` 文件！**

该README文件包含：
- 🎯 执行前准备和用户信息收集要求
- 🔄 强制执行原则和分步执行流程  
- 🔥 修改后立即重新执行当前步骤的强制规则
- 📝 文件修改记录规范和版本号递增规则
- 🧪 测试文件调试规范和测试指令使用规范
- 🚨 全局约束和游戏服务器特殊要求

**不阅读README直接执行步骤将导致执行不规范，违反项目要求！**

---

## 🎯 检查目标
清理和优化代码质量，消除未使用代码、规范常量定义、处理TODO项。

## 🧹 未使用代码清理

### 清理未使用的导入
```typescript
// ❌ 错误：导入未使用的模块
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { User, Admin } from './user.entity';
import * as crypto from 'crypto'; // 未使用
import { RedisService } from '../redis/redis.service'; // 未使用

// ✅ 正确：只导入使用的模块
import { Injectable, NotFoundException } from '@nestjs/common';
import { User } from './user.entity';
```

### 清理未使用的变量
```typescript
// ❌ 错误：定义但未使用的变量
const unusedVariable = 'test';
let tempData = [];

// ✅ 正确：删除未使用的变量
// 只保留实际使用的变量
```

### 清理未使用的方法
```typescript
// ❌ 错误：定义但未调用的私有方法
private generateVerificationCode(): string {
  // 如果这个方法没有被调用，应该删除
}

// ✅ 正确：删除未使用的私有方法
// 或者确保方法被正确调用
```

## 📊 常量定义规范

### 使用SCREAMING_SNAKE_CASE
```typescript
// ✅ 正确：使用全大写+下划线
const SALT_ROUNDS = 10;
const MAX_LOGIN_ATTEMPTS = 5;
const DEFAULT_PAGE_SIZE = 20;
const WEBSOCKET_TIMEOUT = 30000;
const MAX_ROOM_CAPACITY = 100;

// ❌ 错误：使用小驼峰
const saltRounds = 10;
const maxLoginAttempts = 5;
const defaultPageSize = 20;
```

### 提取魔法数字为常量
```typescript
// ❌ 错误：使用魔法数字
if (attempts > 5) {
  throw new Error('Too many attempts');
}
setTimeout(callback, 30000);

// ✅ 正确：提取为常量
const MAX_LOGIN_ATTEMPTS = 5;
const WEBSOCKET_TIMEOUT = 30000;

if (attempts > MAX_LOGIN_ATTEMPTS) {
  throw new Error('Too many attempts');
}
setTimeout(callback, WEBSOCKET_TIMEOUT);
```

## 📏 方法长度检查

### 长度限制
- **建议**：方法不超过50行
- **原则**：一个方法只做一件事
- **拆分**：复杂方法拆分为多个小方法

### 方法拆分示例
```typescript
// ❌ 错误：方法过长（超过50行）
async processUserRegistration(userData: CreateUserDto): Promise<User> {
  // 验证用户数据
  // 检查邮箱是否存在
  // 生成密码哈希
  // 创建用户记录
  // 发送欢迎邮件
  // 记录操作日志
  // 返回用户信息
  // ... 超过50行的复杂逻辑
}

// ✅ 正确：拆分为多个小方法
async processUserRegistration(userData: CreateUserDto): Promise<User> {
  await this.validateUserData(userData);
  await this.checkEmailExists(userData.email);
  const hashedPassword = await this.generatePasswordHash(userData.password);
  const user = await this.createUserRecord({ ...userData, password: hashedPassword });
  await this.sendWelcomeEmail(user.email);
  await this.logUserRegistration(user.id);
  return user;
}

private async validateUserData(userData: CreateUserDto): Promise<void> {
  // 验证逻辑
}

private async checkEmailExists(email: string): Promise<void> {
  // 邮箱检查逻辑
}
```

## 🔄 代码重复消除

### 识别重复代码
```typescript
// ❌ 错误：重复的验证逻辑
async createUser(userData: CreateUserDto): Promise<User> {
  if (!userData.email || !userData.name) {
    throw new BadRequestException('Required fields missing');
  }
  if (!this.isValidEmail(userData.email)) {
    throw new BadRequestException('Invalid email format');
  }
  // 创建用户逻辑
}

async updateUser(id: string, userData: UpdateUserDto): Promise<User> {
  if (!userData.email || !userData.name) {
    throw new BadRequestException('Required fields missing');
  }
  if (!this.isValidEmail(userData.email)) {
    throw new BadRequestException('Invalid email format');
  }
  // 更新用户逻辑
}

// ✅ 正确：抽象为可复用方法
async createUser(userData: CreateUserDto): Promise<User> {
  this.validateUserData(userData);
  // 创建用户逻辑
}

async updateUser(id: string, userData: UpdateUserDto): Promise<User> {
  this.validateUserData(userData);
  // 更新用户逻辑
}

private validateUserData(userData: CreateUserDto | UpdateUserDto): void {
  if (!userData.email || !userData.name) {
    throw new BadRequestException('Required fields missing');
  }
  if (!this.isValidEmail(userData.email)) {
    throw new BadRequestException('Invalid email format');
  }
}
```

## 🚨 异常处理完整性检查（关键规范）

### 问题定义
**异常吞没（Exception Swallowing）** 是指在 catch 块中捕获异常后，只记录日志但不重新抛出，导致：
- 调用方无法感知错误
- 方法返回 undefined 而非声明的类型
- 数据不一致或静默失败
- 难以调试和定位问题

### 检查规则

#### 规则1：catch 块必须有明确的异常处理策略
```typescript
// ❌ 严重错误：catch 块吞没异常
async create(createDto: CreateDto): Promise<ResponseDto> {
  try {
    const result = await this.repository.create(createDto);
    return this.toResponseDto(result);
  } catch (error) {
    this.logger.error('创建失败', error);
    // 错误：没有 throw，方法返回 undefined
    // 但声明返回 Promise<ResponseDto>
  }
}

// ❌ 错误：只记录日志不处理
async findById(id: string): Promise<Entity> {
  try {
    return await this.repository.findById(id);
  } catch (error) {
    monitor.error(error);
    // 错误：异常被吞没，调用方无法感知
  }
}

// ✅ 正确：重新抛出异常
async create(createDto: CreateDto): Promise<ResponseDto> {
  try {
    const result = await this.repository.create(createDto);
    return this.toResponseDto(result);
  } catch (error) {
    this.logger.error('创建失败', error);
    throw error;  // 必须重新抛出
  }
}

// ✅ 正确：转换为特定异常类型
async create(createDto: CreateDto): Promise<ResponseDto> {
  try {
    const result = await this.repository.create(createDto);
    return this.toResponseDto(result);
  } catch (error) {
    this.logger.error('创建失败', error);
    if (error.message.includes('duplicate')) {
      throw new ConflictException('记录已存在');
    }
    throw error;  // 其他错误继续抛出
  }
}

// ✅ 正确：返回错误响应（仅限顶层API）
async create(createDto: CreateDto): Promise<ApiResponse<ResponseDto>> {
  try {
    const result = await this.repository.create(createDto);
    return { success: true, data: this.toResponseDto(result) };
  } catch (error) {
    this.logger.error('创建失败', error);
    return { 
      success: false, 
      error: error.message,
      errorCode: 'CREATE_FAILED'
    };  // 顶层API可以返回错误响应
  }
}
```

#### 规则2：Service 层方法必须传播异常
```typescript
// ❌ 错误：Service 层吞没异常
@Injectable()
export class UserService {
  async update(id: string, dto: UpdateDto): Promise<ResponseDto> {
    try {
      const result = await this.repository.update(id, dto);
      return this.toResponseDto(result);
    } catch (error) {
      this.logger.error('更新失败', { id, error });
      // 错误：Service 层不应吞没异常
    }
  }
}

// ✅ 正确：Service 层传播异常
@Injectable()
export class UserService {
  async update(id: string, dto: UpdateDto): Promise<ResponseDto> {
    try {
      const result = await this.repository.update(id, dto);
      return this.toResponseDto(result);
    } catch (error) {
      this.logger.error('更新失败', { id, error });
      throw error;  // 传播给调用方处理
    }
  }
}
```

#### 规则3：Repository 层必须传播数据库异常
```typescript
// ❌ 错误：Repository 层吞没数据库异常
@Injectable()
export class UserRepository {
  async findById(id: bigint): Promise<User | null> {
    try {
      return await this.repository.findOne({ where: { id } });
    } catch (error) {
      this.logger.error('查询失败', { id, error });
      // 错误：数据库异常被吞没，调用方以为查询成功但返回 null
    }
  }
}

// ✅ 正确：Repository 层传播异常
@Injectable()
export class UserRepository {
  async findById(id: bigint): Promise<User | null> {
    try {
      return await this.repository.findOne({ where: { id } });
    } catch (error) {
      this.logger.error('查询失败', { id, error });
      throw error;  // 数据库异常必须传播
    }
  }
}
```

### 异常处理层级规范

| 层级 | 异常处理策略 | 说明 |
|------|-------------|------|
| **Repository 层** | 必须 throw | 数据访问异常必须传播 |
| **Service 层** | 必须 throw | 业务异常必须传播给调用方 |
| **Business 层** | 必须 throw | 业务逻辑异常必须传播 |
| **Gateway/Controller 层** | 可以转换为 HTTP 响应 | 顶层可以将异常转换为错误响应 |

### 检查清单

- [ ] **所有 catch 块是否有 throw 语句？**
- [ ] **方法返回类型与实际返回是否一致？**（避免返回 undefined）
- [ ] **Service/Repository 层是否传播异常？**
- [ ] **只有顶层 API 才能将异常转换为错误响应？**
- [ ] **异常日志是否包含足够的上下文信息？**

### 快速检查命令
```bash
# 搜索可能吞没异常的 catch 块（没有 throw 的 catch）
# 在代码审查时重点关注这些位置
grep -rn "catch.*error" --include="*.ts" | grep -v "throw"
```

### 常见错误模式

#### 模式1：性能监控后忘记抛出
```typescript
// ❌ 常见错误
} catch (error) {
  monitor.error(error);  // 只记录监控
  // 忘记 throw error;
}

// ✅ 正确
} catch (error) {
  monitor.error(error);
  throw error;  // 必须抛出
}
```

#### 模式2：条件分支遗漏 throw
```typescript
// ❌ 常见错误
} catch (error) {
  if (error.code === 'DUPLICATE') {
    throw new ConflictException('已存在');
  }
  // else 分支忘记 throw
  this.logger.error(error);
}

// ✅ 正确
} catch (error) {
  if (error.code === 'DUPLICATE') {
    throw new ConflictException('已存在');
  }
  this.logger.error(error);
  throw error;  // else 分支也要抛出
}
```

#### 模式3：返回类型不匹配
```typescript
// ❌ 错误：声明返回 Promise<Entity> 但可能返回 undefined
async findById(id: string): Promise<Entity> {
  try {
    return await this.repo.findById(id);
  } catch (error) {
    this.logger.error(error);
    // 没有 throw，TypeScript 不会报错但运行时返回 undefined
  }
}

// ✅ 正确
async findById(id: string): Promise<Entity> {
  try {
    return await this.repo.findById(id);
  } catch (error) {
    this.logger.error(error);
    throw error;
  }
}
```

## 🚫 TODO项处理（强制要求）

### 处理原则
**最终文件不能包含TODO项**，必须：
1. **真正实现功能**
2. **删除未完成代码**

### 常见TODO处理
```typescript
// ❌ 错误：包含TODO项的代码
async getUserProfile(id: string): Promise<UserProfile> {
  // TODO: 实现用户档案查询
  throw new Error('Not implemented');
}

async sendSmsVerification(phone: string): Promise<void> {
  // TODO: 集成短信服务提供商
  throw new Error('SMS service not implemented');
}

// ✅ 正确：真正实现功能
async getUserProfile(id: string): Promise<UserProfile> {
  const profile = await this.userProfileRepository.findOne({ 
    where: { userId: id } 
  });
  
  if (!profile) {
    throw new NotFoundException('用户档案不存在');
  }
  
  return profile;
}

// ✅ 正确：如果功能不需要，删除方法
// 删除sendSmsVerification方法及其调用
```

## 🎮 游戏服务器特殊质量要求

### WebSocket连接管理
```typescript
// ✅ 正确：完整的连接管理
const MAX_CONNECTIONS_PER_ROOM = 100;
const CONNECTION_TIMEOUT = 30000;
const HEARTBEAT_INTERVAL = 10000;

@WebSocketGateway()
export class LocationBroadcastGateway {
  private readonly connections = new Map<string, Socket>();
  
  handleConnection(client: Socket): void {
    this.validateConnection(client);
    this.setupHeartbeat(client);
    this.trackConnection(client);
  }
  
  private validateConnection(client: Socket): void {
    // 连接验证逻辑
  }
  
  private setupHeartbeat(client: Socket): void {
    // 心跳检测逻辑
  }
}
```

### 双模式服务质量
```typescript
// ✅ 正确：确保两种模式行为一致
const DEFAULT_USER_STATUS = UserStatus.PENDING;
const MAX_BATCH_SIZE = 1000;

@Injectable()
export class UsersMemoryService {
  private readonly users = new Map<string, User>();
  
  async create(userData: CreateUserDto): Promise<User> {
    this.validateUserData(userData);
    const user = this.buildUserEntity(userData);
    this.users.set(user.id, user);
    return user;
  }
  
  private validateUserData(userData: CreateUserDto): void {
    // 与数据库模式相同的验证逻辑
  }
  
  private buildUserEntity(userData: CreateUserDto): User {
    // 与数据库模式相同的实体构建逻辑
  }
}
```

### 属性测试质量
```typescript
// ✅ 正确：完整的属性测试实现
import * as fc from 'fast-check';

const PROPERTY_TEST_RUNS = 1000;
const MAX_USER_ID = 1000000;

describe('AdminService Properties', () => {
  it('should handle any valid user status update', () => {
    fc.assert(fc.property(
      fc.integer({ min: 1, max: MAX_USER_ID }),
      fc.constantFrom(...Object.values(UserStatus)),
      async (userId, status) => {
        try {
          const result = await adminService.updateUserStatus(userId, status);
          expect(result).toBeDefined();
          expect(result.status).toBe(status);
        } catch (error) {
          expect(error).toBeInstanceOf(NotFoundException || BadRequestException);
        }
      }
    ), { numRuns: PROPERTY_TEST_RUNS });
  });
});
```

## 🔍 检查执行步骤

1. **扫描未使用的导入**
   - 检查每个import语句是否被使用
   - 删除未使用的导入

2. **扫描未使用的变量和方法**
   - 检查变量是否被引用
   - 检查私有方法是否被调用
   - 删除未使用的代码

3. **检查常量定义**
   - 识别魔法数字和字符串
   - 提取为SCREAMING_SNAKE_CASE常量
   - 确保常量命名清晰

4. **检查方法长度**
   - 统计每个方法的行数
   - 识别超过50行的方法
   - 建议拆分复杂方法

5. **识别重复代码**
   - 查找相似的代码块
   - 抽象为可复用的工具方法
   - 消除代码重复

6. **🚨 检查异常处理完整性（关键步骤）**
   - 扫描所有 catch 块
   - 检查是否有 throw 语句
   - 验证 Service/Repository 层是否传播异常
   - 确认方法返回类型与实际返回一致
   - 识别异常吞没模式并修复

7. **处理所有TODO项**
   - 搜索所有TODO注释
   - 要求真正实现功能或删除代码
   - 确保最终文件无TODO项

8. **游戏服务器特殊检查**
   - WebSocket连接管理完整性
   - 双模式服务行为一致性
   - 属性测试实现质量

## 🔥 重要提醒

**如果在本步骤中执行了任何修改操作（删除未使用代码、提取常量、实现TODO项等），必须立即重新执行步骤3的完整检查！**

- ✅ 执行修改 → 🔥 立即重新执行步骤3 → 提供验证报告 → 等待用户确认
- ❌ 执行修改 → 直接进入步骤4（错误做法）

**🚨 重要强调：纯检查步骤不更新修改记录**
**如果检查发现代码质量已经符合规范，无需任何修改，则：**
- ❌ **禁止添加检查记录**：不要添加"AI代码检查步骤3：代码质量检查和优化"
- ❌ **禁止更新时间戳**：不要修改@lastModified字段
- ❌ **禁止递增版本号**：不要修改@version字段
- ✅ **仅提供检查报告**：说明检查结果，确认符合规范

**不能跳过重新检查环节！**