正在加载,请稍候…

整洁代码原则:编写可读且可维护的代码

应用 Robert Martin 的整洁代码原则,学习命名、函数、注释、错误处理和代码结构的最佳实践,提升代码可读性和可维护性。

整洁代码原则:编写可读且可维护的代码

整洁代码原则:编写可读且可维护的代码

整洁代码读起来像优美的散文——其意图无需解释便一目了然。

有意义的命名

// 糟糕
const d = 86400; // d 是什么?
function calc(a: number[], b: number) { /* ... */ }
class Mgr { /* ... */ }

// 良好
const SECONDS_PER_DAY = 86400;
function calculateDailyRevenue(transactions: Transaction[], taxRate: number) { /* ... */ }
class AccountManager { /* ... */ }

// 变量应揭示意图
// 糟糕
const list = users.filter(u => u.a > 18);

// 良好
const adults = users.filter(user => user.age > LEGAL_DRINKING_AGE);

整洁代码原则:编写可读且可维护的代码插图

小函数

函数应该只做一件事,做好它,并且只做这一件事。

// 糟糕:函数做了太多事情
async function processUserRegistration(data: any) {
  // 验证
  if (!data.email || !data.password) throw new Error('Missing fields');
  if (!/^[^@]+@[^@]+$/.test(data.email)) throw new Error('Invalid email');

  // 哈希密码
  const salt = await bcrypt.genSalt(10);
  const hash = await bcrypt.hash(data.password, salt);

  // 保存到数据库
  const user = await db.query('INSERT INTO users ...');

  // 发送邮件
  await emailClient.send({ to: data.email, subject: 'Welcome!' });

  return user;
}

// 良好:每个函数只有一个职责
async function processUserRegistration(data: RegistrationData) {
  validateRegistrationData(data);
  const hashedPassword = await hashPassword(data.password);
  const user = await createUserAccount(data.email, hashedPassword);
  await sendWelcomeEmail(user.email);
  return user;
}

function validateRegistrationData(data: RegistrationData): void {
  if (!data.email || !data.password) throw new ValidationError('Missing fields');
  if (!isValidEmail(data.email)) throw new ValidationError('Invalid email');
}

整洁代码原则:编写可读且可维护的代码插图

有意义的注释

// 糟糕:注释解释了“什么”(代码本身已明显)
// 递增计数器
i++;

// 糟糕:被注释掉的代码
// const oldResult = computeOldWay(x);
const result = computeNewWay(x);

// 良好:注释解释“为什么”
// 使用 2^31 - 1 以避免在遗留 32 位系统中整数溢出
const MAX_SAFE_ID = 2147483647;

// 良好:澄清复杂算法
// 这实现了 Levenshtein 距离算法
// 参见:https://en.wikipedia.org/wiki/Levenshtein_distance
function editDistance(s1: string, s2: string): number { /* ... */ }

整洁代码原则:编写可读且可维护的代码插图

错误处理

// 糟糕:错误码和 null 返回
function findUser(id: string): User | null {
  // 调用者每次都必须检查 null
  return null;
}

// 良好:抛出领域异常
class UserNotFoundError extends Error {
  constructor(id: string) {
    super(`User with id ${id} not found`);
    this.name = 'UserNotFoundError';
  }
}

async function findUser(id: string): Promise<User> {
  const user = await db.users.findById(id);
  if (!user) throw new UserNotFoundError(id);
  return user;
}

// 良好:对预期失败使用 Result 类型
type Result<T, E = Error> = 
  | { success: true; data: T }
  | { success: false; error: E };

async function tryLogin(email: string, password: string): Promise<Result<User, LoginError>> {
  const user = await userRepo.findByEmail(email);
  if (!user) return { success: false, error: new LoginError('Invalid credentials') };
  const valid = await verifyPassword(password, user.passwordHash);
  if (!valid) return { success: false, error: new LoginError('Invalid credentials') };
  return { success: true, data: user };
}

不要重复自己(DRY)

// 糟糕:重复的验证
function createUser(email: string) {
  if (!/^[^@]+@[^@]+$/.test(email)) throw new Error('Invalid email');
  // ...
}

function updateUserEmail(userId: string, email: string) {
  if (!/^[^@]+@[^@]+$/.test(email)) throw new Error('Invalid email');
  // ...
}

// 良好:提取函数
function assertValidEmail(email: string): void {
  if (!/^[^@]+@[^@]+$/.test(email)) throw new ValidationError('Invalid email');
}

整洁代码不是一次写成的——它通过重构不断改进。