code-quality

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Code Quality

代码质量

Overview

概述

Principles and practices for writing maintainable, readable, and reliable code.

编写可维护、可读且可靠代码的原则与实践。

Clean Code Principles

整洁代码原则

Meaningful Names

有意义的命名

typescript
// ❌ Cryptic names
const d = new Date();
const u = getU();
const arr = data.filter(x => x.s === 'a');

// ✅ Descriptive names
const currentDate = new Date();
const currentUser = getCurrentUser();
const activeUsers = users.filter(user => user.status === 'active');

// ❌ Hungarian notation (outdated)
const strName = 'John';
const arrItems = [];
const bIsActive = true;

// ✅ Let the type system handle types
const name = 'John';
const items: Item[] = [];
const isActive = true;
typescript
// ❌ 晦涩的命名
const d = new Date();
const u = getU();
const arr = data.filter(x => x.s === 'a');

// ✅ 描述性命名
const currentDate = new Date();
const currentUser = getCurrentUser();
const activeUsers = users.filter(user => user.status === 'active');

// ❌ 匈牙利命名法(已过时)
const strName = 'John';
const arrItems = [];
const bIsActive = true;

// ✅ 让类型系统处理类型
const name = 'John';
const items: Item[] = [];
const isActive = true;

Functions

函数

typescript
// ❌ Does too much
function processUserData(userId: string) {
  const user = db.findUser(userId);
  const orders = db.findOrders(userId);
  const total = orders.reduce((sum, o) => sum + o.amount, 0);
  sendEmail(user.email, `Your total: ${total}`);
  updateAnalytics(userId, total);
  return { user, orders, total };
}

// ✅ Single responsibility
function getUser(userId: string): User {
  return db.findUser(userId);
}

function getUserOrders(userId: string): Order[] {
  return db.findOrders(userId);
}

function calculateTotal(orders: Order[]): number {
  return orders.reduce((sum, o) => sum + o.amount, 0);
}

function sendOrderSummary(user: User, total: number): void {
  sendEmail(user.email, `Your total: ${total}`);
}

// ❌ Too many parameters
function createUser(name, email, age, role, department, manager, startDate) {}

// ✅ Use object parameter
interface CreateUserParams {
  name: string;
  email: string;
  age?: number;
  role: Role;
  department: string;
  managerId?: string;
  startDate: Date;
}

function createUser(params: CreateUserParams): User {}
typescript
// ❌ 职责过多
function processUserData(userId: string) {
  const user = db.findUser(userId);
  const orders = db.findOrders(userId);
  const total = orders.reduce((sum, o) => sum + o.amount, 0);
  sendEmail(user.email, `Your total: ${total}`);
  updateAnalytics(userId, total);
  return { user, orders, total };
}

// ✅ 单一职责
function getUser(userId: string): User {
  return db.findUser(userId);
}

function getUserOrders(userId: string): Order[] {
  return db.findOrders(userId);
}

function calculateTotal(orders: Order[]): number {
  return orders.reduce((sum, o) => sum + o.amount, 0);
}

function sendOrderSummary(user: User, total: number): void {
  sendEmail(user.email, `Your total: ${total}`);
}

// ❌ 参数过多
function createUser(name, email, age, role, department, manager, startDate) {}

// ✅ 使用对象参数
interface CreateUserParams {
  name: string;
  email: string;
  age?: number;
  role: Role;
  department: string;
  managerId?: string;
  startDate: Date;
}

function createUser(params: CreateUserParams): User {}

Comments

注释

typescript
// ❌ Redundant comment
// Increment counter by 1
counter++;

// ❌ Outdated comment (code changed, comment didn't)
// Returns the user's full name
function getUserEmail(user: User) {
  return user.email;
}

// ✅ Explains WHY, not WHAT
// Use binary search because the list is sorted and can have 100k+ items
const index = binarySearch(sortedItems, target);

// ✅ Warns about non-obvious behavior
// IMPORTANT: This function mutates the input array for performance reasons
function quickSort(arr: number[]): number[] {
  // ...
}

// ✅ TODO with context
// TODO(john): Remove after migration completes - tracking in JIRA-1234
const legacyAdapter = new LegacyAdapter();

typescript
// ❌ 冗余注释
// 将计数器加1
counter++;

// ❌ 过时注释(代码已修改,注释未更新)
// 返回用户的全名
function getUserEmail(user: User) {
  return user.email;
}

// ✅ 解释原因,而非内容
// 由于列表已排序且可能包含10万+条数据,使用二分查找
const index = binarySearch(sortedItems, target);

// ✅ 提示非直观行为
// 重要:出于性能考虑,此函数会修改输入数组
function quickSort(arr: number[]): number[] {
  // ...
}

// ✅ 带上下文的TODO
// TODO(john): 迁移完成后移除 - 跟踪于JIRA-1234
const legacyAdapter = new LegacyAdapter();

SOLID Principles

SOLID原则

Single Responsibility Principle

单一职责原则

typescript
// ❌ Multiple responsibilities
class UserManager {
  createUser(data: UserData) { /* DB logic */ }
  validateEmail(email: string) { /* Validation logic */ }
  sendWelcomeEmail(user: User) { /* Email logic */ }
  generateReport(users: User[]) { /* Report logic */ }
}

// ✅ Single responsibility each
class UserRepository {
  create(data: UserData): User { /* DB logic */ }
  findById(id: string): User | null { /* DB logic */ }
}

class UserValidator {
  validateEmail(email: string): boolean { /* Validation */ }
  validatePassword(password: string): ValidationResult { /* Validation */ }
}

class EmailService {
  sendWelcomeEmail(user: User): void { /* Email logic */ }
}

class UserReportGenerator {
  generate(users: User[]): Report { /* Report logic */ }
}
typescript
// ❌ 多职责
class UserManager {
  createUser(data: UserData) { /* 数据库逻辑 */ }
  validateEmail(email: string) { /* 验证逻辑 */ }
  sendWelcomeEmail(user: User) { /* 邮件逻辑 */ }
  generateReport(users: User[]) { /* 报表逻辑 */ }
}

// ✅ 单一职责
class UserRepository {
  create(data: UserData): User { /* 数据库逻辑 */ }
  findById(id: string): User | null { /* 数据库逻辑 */ }
}

class UserValidator {
  validateEmail(email: string): boolean { /* 验证逻辑 */ }
  validatePassword(password: string): ValidationResult { /* 验证逻辑 */ }
}

class EmailService {
  sendWelcomeEmail(user: User): void { /* 邮件逻辑 */ }
}

class UserReportGenerator {
  generate(users: User[]): Report { /* 报表逻辑 */ }
}

Open/Closed Principle

开闭原则

typescript
// ❌ Must modify to add new payment methods
class PaymentProcessor {
  process(payment: Payment) {
    if (payment.type === 'credit') {
      // Credit card logic
    } else if (payment.type === 'paypal') {
      // PayPal logic
    } else if (payment.type === 'crypto') {
      // Crypto logic - had to modify existing code!
    }
  }
}

// ✅ Open for extension, closed for modification
interface PaymentMethod {
  process(amount: number): Promise<PaymentResult>;
}

class CreditCardPayment implements PaymentMethod {
  async process(amount: number): Promise<PaymentResult> { /* ... */ }
}

class PayPalPayment implements PaymentMethod {
  async process(amount: number): Promise<PaymentResult> { /* ... */ }
}

// New payment method - no modification to existing code
class CryptoPayment implements PaymentMethod {
  async process(amount: number): Promise<PaymentResult> { /* ... */ }
}

class PaymentProcessor {
  constructor(private method: PaymentMethod) {}

  async process(amount: number): Promise<PaymentResult> {
    return this.method.process(amount);
  }
}
typescript
// ❌ 添加新支付方式时必须修改现有代码
class PaymentProcessor {
  process(payment: Payment) {
    if (payment.type === 'credit') {
      // 信用卡逻辑
    } else if (payment.type === 'paypal') {
      // PayPal逻辑
    } else if (payment.type === 'crypto') {
      // 加密货币逻辑 - 不得不修改现有代码!
    }
  }
}

// ✅ 对扩展开放,对修改关闭
interface PaymentMethod {
  process(amount: number): Promise<PaymentResult>;
}

class CreditCardPayment implements PaymentMethod {
  async process(amount: number): Promise<PaymentResult> { /* ... */ }
}

class PayPalPayment implements PaymentMethod {
  async process(amount: number): Promise<PaymentResult> { /* ... */ }
}

// 新增支付方式 - 无需修改现有代码
class CryptoPayment implements PaymentMethod {
  async process(amount: number): Promise<PaymentResult> { /* ... */ }
}

class PaymentProcessor {
  constructor(private method: PaymentMethod) {}

  async process(amount: number): Promise<PaymentResult> {
    return this.method.process(amount);
  }
}

Liskov Substitution Principle

里氏替换原则

typescript
// ❌ Violates LSP - Square breaks Rectangle contract
class Rectangle {
  constructor(public width: number, public height: number) {}

  setWidth(w: number) { this.width = w; }
  setHeight(h: number) { this.height = h; }
  getArea() { return this.width * this.height; }
}

class Square extends Rectangle {
  setWidth(w: number) {
    this.width = w;
    this.height = w; // Unexpected side effect!
  }
  setHeight(h: number) {
    this.width = h;
    this.height = h; // Unexpected side effect!
  }
}

// ✅ Proper abstraction
interface Shape {
  getArea(): number;
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {}
  getArea() { return this.width * this.height; }
}

class Square implements Shape {
  constructor(private side: number) {}
  getArea() { return this.side * this.side; }
}
typescript
// ❌ 违反LSP - Square破坏了Rectangle的契约
class Rectangle {
  constructor(public width: number, public height: number) {}

  setWidth(w: number) { this.width = w; }
  setHeight(h: number) { this.height = h; }
  getArea() { return this.width * this.height; }
}

class Square extends Rectangle {
  setWidth(w: number) {
    this.width = w;
    this.height = w; // 意外的副作用!
  }
  setHeight(h: number) {
    this.width = h;
    this.height = h; // 意外的副作用!
  }
}

// ✅ 正确的抽象
interface Shape {
  getArea(): number;
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {}
  getArea() { return this.width * this.height; }
}

class Square implements Shape {
  constructor(private side: number) {}
  getArea() { return this.side * this.side; }
}

Interface Segregation Principle

接口隔离原则

typescript
// ❌ Fat interface
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
  attendMeeting(): void;
  writeReport(): void;
}

// Robot can't eat or sleep!
class Robot implements Worker {
  work() { /* ... */ }
  eat() { throw new Error('Robots do not eat'); }  // Forced to implement
  sleep() { throw new Error('Robots do not sleep'); }
  // ...
}

// ✅ Segregated interfaces
interface Workable {
  work(): void;
}

interface Eatable {
  eat(): void;
}

interface Sleepable {
  sleep(): void;
}

class Human implements Workable, Eatable, Sleepable {
  work() { /* ... */ }
  eat() { /* ... */ }
  sleep() { /* ... */ }
}

class Robot implements Workable {
  work() { /* ... */ }
}
typescript
// ❌ 臃肿接口
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
  attendMeeting(): void;
  writeReport(): void;
}

// 机器人不能吃饭或睡觉!
class Robot implements Worker {
  work() { /* ... */ }
  eat() { throw new Error('Robots do not eat'); }  // 被迫实现
  sleep() { throw new Error('Robots do not sleep'); }
  // ...
}

// ✅ 拆分后的接口
interface Workable {
  work(): void;
}

interface Eatable {
  eat(): void;
}

interface Sleepable {
  sleep(): void;
}

class Human implements Workable, Eatable, Sleepable {
  work() { /* ... */ }
  eat() { /* ... */ }
  sleep() { /* ... */ }
}

class Robot implements Workable {
  work() { /* ... */ }
}

Dependency Inversion Principle

依赖倒置原则

typescript
// ❌ High-level depends on low-level
class OrderService {
  private db = new MySQLDatabase();  // Concrete dependency
  private mailer = new SendGridMailer();  // Concrete dependency

  createOrder(data: OrderData) {
    const order = this.db.insert('orders', data);
    this.mailer.send(data.email, 'Order confirmed');
    return order;
  }
}

// ✅ Depend on abstractions
interface Database {
  insert(table: string, data: unknown): unknown;
  find(table: string, query: unknown): unknown[];
}

interface Mailer {
  send(to: string, message: string): void;
}

class OrderService {
  constructor(
    private db: Database,
    private mailer: Mailer
  ) {}

  createOrder(data: OrderData) {
    const order = this.db.insert('orders', data);
    this.mailer.send(data.email, 'Order confirmed');
    return order;
  }
}

// Now we can inject any implementation
const service = new OrderService(
  new PostgresDatabase(),
  new SESMailer()
);

typescript
// ❌ 高层模块依赖低层模块
class OrderService {
  private db = new MySQLDatabase();  // 具体依赖
  private mailer = new SendGridMailer();  // 具体依赖

  createOrder(data: OrderData) {
    const order = this.db.insert('orders', data);
    this.mailer.send(data.email, 'Order confirmed');
    return order;
  }
}

// ✅ 依赖抽象
interface Database {
  insert(table: string, data: unknown): unknown;
  find(table: string, query: unknown): unknown[];
}

interface Mailer {
  send(to: string, message: string): void;
}

class OrderService {
  constructor(
    private db: Database,
    private mailer: Mailer
  ) {}

  createOrder(data: OrderData) {
    const order = this.db.insert('orders', data);
    this.mailer.send(data.email, 'Order confirmed');
    return order;
  }
}

// 现在我们可以注入任何实现
const service = new OrderService(
  new PostgresDatabase(),
  new SESMailer()
);

Code Review Best Practices

代码评审最佳实践

What to Look For

评审要点

markdown
undefined
markdown
undefined

Code Review Checklist

代码评审检查清单

Correctness

正确性

  • Logic is correct and handles edge cases
  • Error handling is appropriate
  • No obvious bugs or regressions
  • 逻辑正确且处理了边界情况
  • 错误处理得当
  • 无明显bug或回归问题

Design

设计

  • Code is at the right abstraction level
  • No unnecessary complexity
  • Follows existing patterns in codebase
  • 代码处于合适的抽象层级
  • 无不必要的复杂度
  • 遵循代码库中的现有模式

Readability

可读性

  • Clear naming and intent
  • Comments explain "why" not "what"
  • Code is self-documenting where possible
  • 命名清晰且表意明确
  • 注释解释“原因”而非“内容”
  • 代码尽可能自文档化

Testing

测试

  • Adequate test coverage
  • Tests are meaningful (not just coverage padding)
  • Edge cases are tested
  • 测试覆盖率充足
  • 测试用例有意义(不只是为了凑覆盖率)
  • 边界情况已测试

Performance

性能

  • No obvious N+1 queries or inefficiencies
  • Appropriate data structures used
  • Caching considered if needed
  • 无明显的N+1查询或低效操作
  • 使用了合适的数据结构
  • 必要时考虑了缓存

Security

安全

  • Input validation present
  • No secrets in code
  • Authentication/authorization correct
undefined
  • 存在输入验证
  • 代码中无敏感信息
  • 身份认证/授权逻辑正确
undefined

Giving Feedback

给出反馈的技巧

markdown
undefined
markdown
undefined

Good Review Comments

优秀的评审评语

✅ Specific and actionable

✅ 具体且可执行

"This loop has O(n²) complexity. Consider using a Map for O(n) lookup."
"此循环的时间复杂度为O(n²),考虑使用Map实现O(n)时间复杂度的查找。"

✅ Explain the why

✅ 解释原因

"Let's extract this to a separate function - it makes the logic easier to test and the main function more readable."
"我们将这部分提取为独立函数——这会让逻辑更易于测试,主函数也更易读。"

✅ Offer alternatives

✅ 提供替代方案

"Instead of mutating the array, consider using
filter()
which returns a new array:
const active = items.filter(i => i.active)
"
"与其修改原数组,不如使用
filter()
返回新数组:
const active = items.filter(i => i.active)
"

✅ Distinguish severity

✅ 区分严重程度

  • "nit: " - Minor style issue, optional
  • "suggestion: " - Good to have, not blocking
  • "blocking: " - Must fix before merge
  • "nit: " - 轻微风格问题,可选修改
  • "suggestion: " - 建议优化,不阻塞合并
  • "blocking: " - 必须修复才能合并

Avoid

需避免的情况

❌ Vague criticism

❌ 模糊批评

"This code is confusing"
"这段代码很混乱"

❌ Personal attacks

❌ 人身攻击

"You always make this mistake"
"你总是犯这个错误"

❌ No explanation

❌ 无解释的要求

"Use a different approach"

---
"换一种实现方式"

---

Code Metrics

代码度量

Cyclomatic Complexity

圈复杂度

typescript
// High complexity (10+) - hard to test and maintain
function processOrder(order: Order): Result {
  if (order.status === 'pending') {           // +1
    if (order.paymentMethod === 'card') {     // +1
      if (order.amount > 1000) {              // +1
        // ...
      } else if (order.amount > 100) {        // +1
        // ...
      } else {
        // ...
      }
    } else if (order.paymentMethod === 'cash') {  // +1
      // ...
    }
  } else if (order.status === 'processing') {  // +1
    // ...
  }
  // ... more branches
}

// Lower complexity - extract conditions
function processOrder(order: Order): Result {
  const processor = getProcessor(order.paymentMethod);
  const tier = getPricingTier(order.amount);
  return processor.process(order, tier);
}
typescript
// 高复杂度(10+)- 难以测试和维护
function processOrder(order: Order): Result {
  if (order.status === 'pending') {           // +1
    if (order.paymentMethod === 'card') {     // +1
      if (order.amount > 1000) {              // +1
        // ...
      } else if (order.amount > 100) {        // +1
        // ...
      } else {
        // ...
      }
    } else if (order.paymentMethod === 'cash') {  // +1
      // ...
    }
  } else if (order.status === 'processing') {  // +1
    // ...
  }
  // ... 更多分支
}

// 低复杂度 - 提取条件
function processOrder(order: Order): Result {
  const processor = getProcessor(order.paymentMethod);
  const tier = getPricingTier(order.amount);
  return processor.process(order, tier);
}

Metrics to Track

需跟踪的度量指标

MetricTargetWhy
Cyclomatic Complexity< 10 per functionTestability
Function Length< 50 linesReadability
File Length< 400 linesMaintainability
Test Coverage> 80%Confidence
Duplication< 3%DRY principle

指标目标值原因
圈复杂度每个函数<10可测试性
函数长度<50行可读性
文件长度<400行可维护性
测试覆盖率>80%可信度
代码重复率<3%DRY原则

Linting & Formatting

代码检查与格式化

ESLint Configuration

ESLint配置

javascript
// .eslintrc.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
  ],
  rules: {
    // Prevent bugs
    'no-unused-vars': 'error',
    '@typescript-eslint/no-floating-promises': 'error',
    '@typescript-eslint/no-misused-promises': 'error',

    // Code quality
    'complexity': ['warn', 10],
    'max-lines-per-function': ['warn', 50],
    'max-depth': ['warn', 3],

    // Consistency
    'prefer-const': 'error',
    'no-var': 'error',
  }
};
javascript
// .eslintrc.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
  ],
  rules: {
    // 预防bug
    'no-unused-vars': 'error',
    '@typescript-eslint/no-floating-promises': 'error',
    '@typescript-eslint/no-misused-promises': 'error',

    // 代码质量
    'complexity': ['warn', 10],
    'max-lines-per-function': ['warn', 50],
    'max-depth': ['warn', 3],

    // 一致性
    'prefer-const': 'error',
    'no-var': 'error',
  }
};

Pre-commit Hooks

提交前钩子

json
// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md}": [
      "prettier --write"
    ]
  }
}

json
// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md}": [
      "prettier --write"
    ]
  }
}

Related Skills

相关技能

  • [[refactoring]] - Improving existing code
  • [[testing-strategies]] - Ensuring quality through tests
  • [[design-patterns]] - Proven solutions

  • [[refactoring]] - 改进现有代码
  • [[testing-strategies]] - 通过测试保障质量
  • [[design-patterns]] - 经实践验证的解决方案

Sharp Edges(常見陷阱)

常见陷阱(Sharp Edges)

這些是程式碼品質中最常見且代價最高的錯誤
这些是代码质量中最常见且代价最高的错误

SE-1: 過度工程 (Over-engineering)

SE-1: 过度工程 (Over-engineering)

  • 嚴重度: high
  • 情境: 為了「未來可能需要」而增加不必要的抽象和複雜度
  • 原因: YAGNI 原則被忽視、設計模式濫用、「萬一以後要...」的心態
  • 症狀:
    • 簡單功能需要改動 10+ 個檔案
    • 新人看不懂架構
    • 程式碼比需求複雜 10 倍
  • 檢測:
    Factory.*Factory|Abstract.*Abstract|interface.*\{.*\}(?=.*interface.*\{.*\})|Strategy.*Strategy
  • 解法: YAGNI(You Aren't Gonna Need It)、先寫最簡單的實作、需要時再重構
  • 严重程度: 高
  • 情境: 为了「未来可能需要」而增加不必要的抽象和复杂度
  • 原因: 忽视YAGNI原则、滥用设计模式、「万一以后要...」的心态
  • 症状:
    • 简单功能需要修改10+个文件
    • 新人看不懂架构
    • 代码比需求复杂10倍
  • 检测:
    Factory.*Factory|Abstract.*Abstract|interface.*\{.*\}(?=.*interface.*\{.*\})|Strategy.*Strategy
  • 解法: YAGNI(You Aren't Gonna Need It)、先实现最简单的版本、需要时再重构

SE-2: 命名不一致

SE-2: 命名不一致

  • 嚴重度: medium
  • 情境: 同一個概念在不同地方用不同名稱,或不同概念用相似名稱
  • 原因: 沒有統一術語、多人開發沒有對齊、複製貼上沒改名
  • 症狀:
    • user
      ,
      customer
      ,
      client
      ,
      account
      指同一件事
    • 搜尋不到相關程式碼
    • 新人經常問「這個和那個有什麼差別?」
  • 檢測:
    (user|customer|client|account).*=.*find|(get|fetch|retrieve|load).*User
  • 解法: 建立術語表(Ubiquitous Language)、Code Review 時檢查命名、重構統一命名
  • 严重程度: 中
  • 情境: 同一个概念在不同地方使用不同名称,或不同概念使用相似名称
  • 原因: 没有统一术语、多人开发未对齐、复制粘贴未改名
  • 症状:
    • user
      ,
      customer
      ,
      client
      ,
      account
      指代同一事物
    • 搜索不到相关代码
    • 新人经常问「这个和那个有什么区别?」
  • 检测:
    (user|customer|client|account).*=.*find|(get|fetch|retrieve|load).*User
  • 解法: 建立术语表(通用语言)、代码评审时检查命名、重构统一命名

SE-3: 深層巢狀 (Deep Nesting)

SE-3: 深层嵌套 (Deep Nesting)

  • 嚴重度: medium
  • 情境: if-else 或 callback 巢狀超過 3-4 層,難以閱讀
  • 原因: 沒有提早 return、沒有抽取函數、callback hell
  • 症狀:
    • 需要橫向捲動才能看到程式碼
    • 很難追蹤哪個
      }
      對應哪個
      {
    • Cyclomatic complexity 超高
  • 檢測:
    \{.*\{.*\{.*\{|if.*if.*if.*if|\.then\(.*\.then\(.*\.then\(
  • 解法: Guard clause(提早 return)、抽取函數、使用 async/await 取代 callback
  • 严重程度: 中
  • 情境: if-else或callback嵌套超过3-4层,难以阅读
  • 原因: 未提前return、未抽取函数、回调地狱
  • 症状:
    • 需要横向滚动才能看到完整代码
    • 很难追踪
      }
      对应的
      {
    • 圈复杂度极高
  • 检测:
    \{.*\{.*\{.*\{|if.*if.*if.*if|\.then\(.*\.then\(.*\.then\(
  • 解法: 卫语句(提前return)、抽取函数、使用async/await替代callback

SE-4: 神奇數字/字串 (Magic Numbers)

SE-4: 魔法数字/字符串 (Magic Numbers)

  • 嚴重度: medium
  • 情境: 程式碼中直接使用意義不明的數字或字串
  • 原因: 懶得定義常數、「只用一次不用抽出來」
  • 症狀:
    • 看到
      86400
      不知道是什麼(一天的秒數)
    • 修改時需要全域搜尋 replace
    • 同一個數字在不同地方意義不同但值相同
  • 檢測:
    \b(86400|3600|1000|60000|1024|65535)\b|status\s*===?\s*['"][^'"]+['"]
  • 解法: 抽取為有意義名稱的常數、使用 enum、集中管理設定值
  • 严重程度: 中
  • 情境: 代码中直接使用意义不明的数字或字符串
  • 原因: 懒得定义常量、「只用一次不用抽出来」
  • 症状:
    • 看到
      86400
      不知道是一天的秒数
    • 修改时需要全局搜索替换
    • 同一个数字在不同地方意义不同但值相同
  • 检测:
    \b(86400|3600|1000|60000|1024|65535)\b|status\s*===?\s*['"][^'"]+['"]
  • 解法: 提取为有意义名称的常量、使用enum、集中管理配置值

SE-5: 大泥球 (Big Ball of Mud)

SE-5: 大泥球 (Big Ball of Mud)

  • 嚴重度: critical
  • 情境: 程式碼沒有明確架構,所有東西混在一起,到處都有依賴
  • 原因: 沒有模組化設計、趕時間「先 work 再說」、缺乏重構
  • 症狀:
    • 改 A 會壞 B
    • 單一檔案 1000+ 行
    • 所有東西都 import 所有東西
  • 檢測:
    import.*from.*\.\.\/\.\.\/\.\.\/|require\(.*\.\..*\.\..*\.\.\)|lines.*>\s*1000
  • 解法: 分層架構、明確的模組邊界、定期重構、嚴格的 import 規則

  • 严重程度: 关键
  • 情境: 代码没有明确架构,所有内容混在一起,依赖关系混乱
  • 原因: 未进行模块化设计、赶时间「先跑起来再说」、缺乏重构
  • 症状:
    • 修改A会导致B出错
    • 单个文件超过1000行
    • 所有模块都互相导入
  • 检测:
    import.*from.*\.\.\/\.\.\/\.\.\/|require\(.*\.\..*\.\..*\.\.\)|lines.*>\s*1000
  • 解法: 分层架构、明确模块边界、定期重构、严格的导入规则

Validations

代码验证规则

V-1: 禁止 console.log (生產代碼)

V-1: 禁止 console.log (生产代码)

  • 類型: regex
  • 嚴重度: medium
  • 模式:
    console\.(log|debug|info)\(
  • 訊息: console.log should not be in production code
  • 修復建議: Use a proper logger (winston, pino) or remove debug statements
  • 適用:
    *.ts
    ,
    *.js
  • 类型: 正则表达式
  • 严重程度: 中
  • 模式:
    console\.(log|debug|info)\(
  • 提示信息: console.log不应出现在生产代码中
  • 修复建议: 使用专业日志工具(winston, pino)或移除调试语句
  • 适用范围:
    *.ts
    ,
    *.js

V-2: 禁止 any 類型

V-2: 禁止 any 类型

  • 類型: ast
  • 嚴重度: high
  • 模式:
    TSAnyKeyword
  • 訊息: 'any' type defeats TypeScript's type safety
  • 修復建議: Use specific type, 'unknown', or generic type parameter
  • 適用:
    *.ts
    ,
    *.tsx
  • 类型: 抽象语法树
  • 严重程度: 高
  • 模式:
    TSAnyKeyword
  • 提示信息: 'any'类型会破坏TypeScript的类型安全性
  • 修复建议: 使用具体类型、'unknown'或泛型类型参数
  • 适用范围:
    *.ts
    ,
    *.tsx

V-3: 函數參數過多

V-3: 函数参数过多

  • 類型: regex
  • 嚴重度: medium
  • 模式:
    function\s+\w+\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*\)|=>\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*\)
  • 訊息: Function has more than 4 parameters - consider using an object
  • 修復建議: Replace multiple params with single options object:
    function(options: Options)
  • 適用:
    *.ts
    ,
    *.js
  • 类型: 正则表达式
  • 严重程度: 中
  • 模式:
    function\s+\w+\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*\)|=>\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*\)
  • 提示信息: 函数参数超过4个 - 考虑使用对象参数
  • 修复建议: 用单个选项对象替换多个参数:
    function(options: Options)
  • 适用范围:
    *.ts
    ,
    *.js

V-4: TODO 無追蹤

V-4: 无跟踪的TODO

  • 類型: regex
  • 嚴重度: low
  • 模式:
    //\s*TODO(?!.*#\d|.*JIRA|.*\w+-\d+)
  • 訊息: TODO comment without tracking reference
  • 修復建議: Add issue reference:
    // TODO(#123): description
    or create ticket
  • 適用:
    *.ts
    ,
    *.js
    ,
    *.tsx
    ,
    *.jsx
  • 类型: 正则表达式
  • 严重程度: 低
  • 模式:
    //\s*TODO(?!.*#\d|.*JIRA|.*\w+-\d+)
  • 提示信息: TODO注释未关联跟踪项
  • 修复建议: 添加问题引用:
    // TODO(#123): 描述
    或创建工单
  • 适用范围:
    *.ts
    ,
    *.js
    ,
    *.tsx
    ,
    *.jsx

V-5: 深層 import 路徑

V-5: 深层相对导入

  • 類型: regex
  • 嚴重度: medium
  • 模式:
    import.*from\s+['"]\.\.\/\.\.\/\.\.\/|require\s*\(\s*['"]\.\.\/\.\.\/\.\.\/
  • 訊息: Deep relative imports indicate poor module boundaries
  • 修復建議: Use path aliases:
    import { X } from '@/modules/x'
  • 適用:
    *.ts
    ,
    *.js
    ,
    *.tsx
    ,
    *.jsx
  • 类型: 正则表达式
  • 严重程度: 中
  • 模式:
    import.*from\s+['"]\.\.\/\.\.\/\.\.\/|require\s*\(\s*['"]\.\.\/\.\.\/\.\.\/
  • 提示信息: 深层相对导入表明模块边界设计不佳
  • 修复建议: 使用路径别名:
    import { X } from '@/modules/x'
  • 适用范围:
    *.ts
    ,
    *.js
    ,
    *.tsx
    ,
    *.jsx