Skip to content
On this page

代码审查常见问题

在代码审查过程中,经常会遇到一些常见问题。了解这些问题及其解决方案有助于提高代码质量和审查效率。

代码质量问题

1. 重复代码(DRY原则违反)

问题示例:

javascript
// Bad: 重复的验证逻辑
function processUser(user) {
  if (!user || !user.email || user.email.length === 0) {
    throw new Error('Invalid user email');
  }
  // 处理用户逻辑
}

function processOrder(order) {
  if (!order || !order.email || order.email.length === 0) {
    throw new Error('Invalid order email');
  }
  // 处理订单逻辑
}

function processContact(contact) {
  if (!contact || !contact.email || contact.email.length === 0) {
    throw new Error('Invalid contact email');
  }
  // 处理联系人逻辑
}

解决方案:

javascript
// Good: 提取公共验证逻辑
function validateEmail(email, context = 'email') {
  if (!email || email.length === 0) {
    throw new Error(`Invalid ${context}`);
  }
}

function processUser(user) {
  validateEmail(user.email, 'user email');
  // 处理用户逻辑
}

function processOrder(order) {
  validateEmail(order.email, 'order email');
  // 处理订单逻辑
}

function processContact(contact) {
  validateEmail(contact.email, 'contact email');
  // 处理联系人逻辑
}

2. 函数过长

问题示例:

javascript
// Bad: 过长的函数,职责不清
function processUserData(userData) {
  // 数据验证
  if (!userData) {
    throw new Error('User data is required');
  }
  
  if (!userData.email) {
    throw new Error('Email is required');
  }
  
  if (!userData.name) {
    throw new Error('Name is required');
  }
  
  // 数据格式化
  const formattedEmail = userData.email.trim().toLowerCase();
  const formattedName = userData.name.trim();
  
  // 数据验证(更多验证)
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(formattedEmail)) {
    throw new Error('Invalid email format');
  }
  
  if (formattedName.length < 2) {
    throw new Error('Name must be at least 2 characters');
  }
  
  // 数据处理
  const processedUser = {
    id: generateId(),
    email: formattedEmail,
    name: formattedName,
    createdAt: new Date(),
    isActive: true,
    profile: {
      preferences: {},
      settings: {}
    }
  };
  
  // 数据存储
  try {
    const result = await saveUserToDatabase(processedUser);
    return result;
  } catch (error) {
    console.error('Failed to save user:', error);
    throw error;
  }
}

解决方案:

javascript
// Good: 将函数拆分为更小的、专注的函数
function validateUserData(userData) {
  if (!userData) {
    throw new Error('User data is required');
  }
  
  if (!userData.email) {
    throw new Error('Email is required');
  }
  
  if (!userData.name) {
    throw new Error('Name is required');
  }
}

function formatUserData(userData) {
  return {
    email: userData.email.trim().toLowerCase(),
    name: userData.name.trim()
  };
}

function validateFormattedData(formattedData) {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(formattedData.email)) {
    throw new Error('Invalid email format');
  }
  
  if (formattedData.name.length < 2) {
    throw new Error('Name must be at least 2 characters');
  }
}

function createProcessedUser(formattedData) {
  return {
    id: generateId(),
    email: formattedData.email,
    name: formattedData.name,
    createdAt: new Date(),
    isActive: true,
    profile: {
      preferences: {},
      settings: {}
    }
  };
}

async function saveUser(processedUser) {
  try {
    return await saveUserToDatabase(processedUser);
  } catch (error) {
    console.error('Failed to save user:', error);
    throw error;
  }
}

// 主函数变得简洁
async function processUserData(userData) {
  validateUserData(userData);
  
  const formattedData = formatUserData(userData);
  validateFormattedData(formattedData);
  
  const processedUser = createProcessedUser(formattedData);
  return await saveUser(processedUser);
}

3. 命名不当

问题示例:

javascript
// Bad: 意图不明确的命名
function calc(x, y, z) {
  let temp = 0;
  for (let i = 0; i < x.length; i++) {
    if (x[i] > y) {
      temp += x[i] * z;
    }
  }
  return temp;
}

const d = new Date().getTime();
const list = getUsers();
const flag = checkStatus();

解决方案:

javascript
// Good: 清晰表达意图的命名
function calculateTotalWithMultiplier(numbers, threshold, multiplier) {
  let total = 0;
  for (let i = 0; i < numbers.length; i++) {
    if (numbers[i] > threshold) {
      total += numbers[i] * multiplier;
    }
  }
  return total;
}

const currentTime = Date.now();
const userList = getUsers();
const isValidStatus = checkStatus();

性能问题

1. 低效的循环

问题示例:

javascript
// Bad: 在循环中进行重复计算
function findUsersWithRole(users, role) {
  const result = [];
  for (let i = 0; i < users.length; i++) {
    // 每次循环都调用users.length
    if (users[i].role === role) {
      result.push(users[i]);
    }
  }
  return result;
}

// Bad: 在循环中进行DOM操作
function updateList(items) {
  const listElement = document.getElementById('list');
  for (let i = 0; i < items.length; i++) {
    // 每次循环都修改DOM - 性能差
    listElement.innerHTML += `<li>${items[i].name}</li>`;
  }
}

解决方案:

javascript
// Good: 优化循环性能
function findUsersWithRole(users, role) {
  const result = [];
  const length = users.length; // 缓存长度
  for (let i = 0; i < length; i++) {
    if (users[i].role === role) {
      result.push(users[i]);
    }
  }
  return result;
}

// Better: 使用数组方法
function findUsersWithRole(users, role) {
  return users.filter(user => user.role === role);
}

// Good: 批量DOM操作
function updateList(items) {
  const listElement = document.getElementById('list');
  // 创建文档片段进行批量操作
  const fragment = document.createDocumentFragment();
  
  items.forEach(item => {
    const li = document.createElement('li');
    li.textContent = item.name;
    fragment.appendChild(li);
  });
  
  listElement.appendChild(fragment);
}

2. 内存泄漏

问题示例:

javascript
// Bad: 未清理事件监听器
class Component {
  constructor(element) {
    this.element = element;
    this.handleClick = this.handleClick.bind(this);
    this.element.addEventListener('click', this.handleClick);
  }
  
  handleClick() {
    console.log('Element clicked');
  }
  
  // 缺少清理方法
}

// Bad: 未清理定时器
function startTimer() {
  const intervalId = setInterval(() => {
    console.log('Timer tick');
  }, 1000);
  
  // 忘记清理定时器
}

解决方案:

javascript
// Good: 清理事件监听器
class Component {
  constructor(element) {
    this.element = element;
    this.handleClick = this.handleClick.bind(this);
    this.element.addEventListener('click', this.handleClick);
  }
  
  handleClick() {
    console.log('Element clicked');
  }
  
  destroy() {
    // 清理事件监听器
    this.element.removeEventListener('click', this.handleClick);
    this.element = null;
  }
}

// Good: 清理定时器
function startTimer() {
  const intervalId = setInterval(() => {
    console.log('Timer tick');
  }, 1000);
  
  // 返回清理函数
  return () => {
    clearInterval(intervalId);
  };
}

// 使用示例
const cleanup = startTimer();
// 在适当时机调用清理函数
cleanup();

安全问题

1. 输入验证缺失

问题示例:

javascript
// Bad: 直接使用用户输入
app.get('/user/:id', (req, res) => {
  const userId = req.params.id;
  // 直接将用户输入用于数据库查询,可能导致SQL注入
  const user = db.query(`SELECT * FROM users WHERE id = ${userId}`);
  res.json(user);
});

// Bad: XSS漏洞
app.post('/comment', (req, res) => {
  const comment = req.body.comment;
  // 直接将用户输入插入HTML,可能导致XSS
  res.send(`<div>Comment: ${comment}</div>`);
});

解决方案:

javascript
// Good: 验证和清理用户输入
app.get('/user/:id', async (req, res) => {
  const userId = req.params.id;
  
  // 验证输入类型
  if (!/^\d+$/.test(userId)) {
    return res.status(400).json({ error: 'Invalid user ID' });
  }
  
  // 使用参数化查询防止SQL注入
  const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);
  res.json(user);
});

// Good: 防止XSS
import { escape } from 'lodash';

app.post('/comment', (req, res) => {
  const comment = req.body.comment;
  
  // 转义HTML特殊字符
  const safeComment = escape(comment);
  res.send(`<div>Comment: ${safeComment}</div>`);
});

2. 权限控制缺失

问题示例:

javascript
// Bad: 缺少权限验证
app.delete('/user/:id', async (req, res) => {
  const userId = req.params.id;
  // 任何人都可以删除任何用户
  await db.deleteUser(userId);
  res.json({ success: true });
});

解决方案:

javascript
// Good: 添加权限验证
app.delete('/user/:id', async (req, res) => {
  const userId = req.params.id;
  const requesterId = req.user.id; // 假设用户已认证
  
  // 验证权限
  if (requesterId !== userId && !req.user.isAdmin) {
    return res.status(403).json({ error: 'Permission denied' });
  }
  
  await db.deleteUser(userId);
  res.json({ success: true });
});

可维护性问题

1. 魔法数字和字符串

问题示例:

javascript
// Bad: 魔法数字和字符串
function calculateDiscount(price) {
  if (price > 100) {
    return price * 0.9; // 0.9是什么?100是什么?
  }
  return price;
}

function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // 复杂的正则表达式
  return regex.test(email);
}

// Bad: 硬编码的配置值
const API_URL = 'https://api.example.com/v1';
const MAX_RETRY = 3;
const TIMEOUT = 5000;

解决方案:

javascript
// Good: 使用常量
const MIN_ORDER_AMOUNT_FOR_DISCOUNT = 100;
const DISCOUNT_RATE = 0.9;
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const API_BASE_URL = 'https://api.example.com/v1';
const MAX_RETRY_ATTEMPTS = 3;
const REQUEST_TIMEOUT_MS = 5000;

function calculateDiscount(price) {
  if (price > MIN_ORDER_AMOUNT_FOR_DISCOUNT) {
    return price * DISCOUNT_RATE;
  }
  return price;
}

function validateEmail(email) {
  return EMAIL_REGEX.test(email);
}

2. 紧耦合

问题示例:

javascript
// Bad: 紧耦合的类
class UserService {
  constructor() {
    // 直接依赖具体实现
    this.db = new MySQLDatabase();
    this.emailService = new SMTPEmailService();
    this.cache = new RedisCache();
  }
  
  async createUser(userData) {
    // 直接使用具体实现
    await this.db.insert('users', userData);
    await this.emailService.sendWelcomeEmail(userData.email);
    await this.cache.set(`user:${userData.id}`, userData);
  }
}

解决方案:

javascript
// Good: 依赖注入和接口抽象
class UserService {
  constructor({ database, emailService, cache }) {
    this.database = database;
    this.emailService = emailService;
    this.cache = cache;
  }
  
  async createUser(userData) {
    await this.database.insert('users', userData);
    await this.emailService.sendWelcomeEmail(userData.email);
    await this.cache.set(`user:${userData.id}`, userData);
  }
}

// 使用示例
const userService = new UserService({
  database: new MySQLDatabase(),
  emailService: new SMTPEmailService(),
  cache: new RedisCache()
});

审查检查清单

在进行代码审查时,可以使用以下检查清单:

  • [ ] 代码逻辑是否正确
  • [ ] 是否存在重复代码
  • [ ] 函数长度是否合适(通常不超过50行)
  • [ ] 变量和函数命名是否清晰
  • [ ] 是否有适当的注释
  • [ ] 是否存在安全漏洞
  • [ ] 是否有性能问题
  • [ ] 是否正确处理错误
  • [ ] 是否遵循团队编码规范
  • [ ] 是否有适当的测试覆盖
  • [ ] 是否正确清理资源(事件监听器、定时器等)
  • [ ] 是否正确验证用户输入
  • [ ] 是否有适当的权限控制

通过识别和解决这些常见问题,可以显著提高代码质量、可维护性和安全性。