swe

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Software Engineering Best Practices

软件工程最佳实践

A comprehensive guide to writing maintainable, scalable, and high-quality software, organized by development phase.
一份按开发阶段组织的、关于编写可维护、可扩展且高质量软件的综合指南。

Key Principles Summary

核心原则摘要

  • Simplicity wins: Write the simplest code that works; add complexity only when required
  • Single responsibility: Each function/class/module should do one thing well
  • Self-documenting code: Code should explain itself; comments are a code smell
  • Fail fast: Validate inputs early, let unexpected errors propagate
  • Test behavior: Focus on what code does, not implementation details
  • No backwards compatibility: Don't add legacy support unless explicitly requested
  • Consistency: Match existing project conventions over personal preference

  • Simplicity wins: 编写能正常运行的最简代码;仅在必要时增加复杂度
  • Single responsibility: 每个函数/类/模块应只做好一件事
  • Self-documenting code: 代码应自我解释;注释是代码异味的表现
  • Fail fast: 尽早验证输入,让意外错误向上传播
  • Test behavior: 关注代码的功能,而非实现细节
  • No backwards compatibility: 除非明确要求,否则不要添加遗留支持
  • Consistency: 遵循现有项目约定,而非个人偏好

Phase 1: Design

第一阶段:设计

Extended guidelines for architecture, patterns, and advanced design topics.
关于架构、模式和高级设计主题的扩展指南。

Advanced Principles

进阶原则

Single Responsibility

Single Responsibility

Each function/class/module should do ONE thing well.
❌ MULTIPLE RESPONSIBILITIES         ✅ SINGLE RESPONSIBILITY
─────────────────────────────────────────────────────
function processUser(user) {         function validateUser(user) { }
  validate(user);                    function saveUser(user) { }
  save(user);                        function sendWelcomeEmail(user) { }
  sendEmail(user);                   function logUserCreation(user) { }
  logActivity(user);
}                                    // Compose in caller
Apply at every level:
  • Functions: Do one operation
  • Classes: Handle one concept
  • Modules: Own one domain
Analyze responsibilities:
  • Find callees of a function to see what it does
  • Find callers of a function to see who depends on it
每个函数/类/模块应只做好一件事。
❌ MULTIPLE RESPONSIBILITIES         ✅ SINGLE RESPONSIBILITY
─────────────────────────────────────────────────────
function processUser(user) {         function validateUser(user) { }
  validate(user);                    function saveUser(user) { }
  save(user);                        function sendWelcomeEmail(user) { }
  sendEmail(user);                   function logUserCreation(user) { }
  logActivity(user);
}                                    // Compose in caller
在每个层级应用:
  • 函数:执行单一操作
  • :处理单一概念
  • 模块:负责单一领域
分析职责:
  • 查看函数的被调用方,了解它的实际功能
  • 查看函数的调用方,了解谁依赖它

The Rule of Three

The Rule of Three

Duplicate code twice before extracting. Premature abstraction is worse than duplication.
  • Use duplication detection to find blocks duplicated 3+ times
重复代码出现三次后再提取抽象。过早的抽象比重复代码更糟糕。
  • 使用重复代码检测工具查找重复3次及以上的代码块

Avoid Backwards Compatibility

Avoid Backwards Compatibility

Don't introduce backwards compatibility unless explicitly requested.
  • Delete deprecated code, don't mark it
  • Don't write shims or polyfills unless asked
  • Don't maintain multiple code paths for old/new
  • If refactoring, replace entirely
Find dead code - unused files, exports, and dependencies that can be safely deleted.
除非明确要求,否则不要引入向后兼容性。
  • 删除已废弃的代码,不要只是标记
  • 除非被要求,否则不要编写shims或polyfills
  • 不要同时维护新旧代码路径
  • 如果进行重构,直接替换旧代码
查找死代码 - 可以安全删除的未使用文件、导出项和依赖项。

Feature Flags Are a Code Smell

Feature Flags Are a Code Smell

typescript
// ❌ FEATURE FLAGS: Hidden complexity
if (featureFlags.newCheckout) {
  await newCheckoutFlow(cart);
} else {
  await legacyCheckoutFlow(cart);
}

// ✅ SIMPLE: One code path
await checkoutFlow(cart);
typescript
// ❌ FEATURE FLAGS: Hidden complexity
if (featureFlags.newCheckout) {
  await newCheckoutFlow(cart);
} else {
  await legacyCheckoutFlow(cart);
}

// ✅ SIMPLE: One code path
await checkoutFlow(cart);

Architecture

架构

Layered Architecture

Layered Architecture

┌─────────────────────────────────────────────────────┐
│         Presentation Layer                          │  UI, API Controllers
├─────────────────────────────────────────────────────┤
│         Application Layer                           │  Use Cases, Orchestration
├─────────────────────────────────────────────────────┤
│           Domain Layer                              │  Business Logic, Entities
├─────────────────────────────────────────────────────┤
│        Infrastructure Layer                         │  Database, External Services
└─────────────────────────────────────────────────────┘

Rule: Dependencies point downward only
┌─────────────────────────────────────────────────────┐
│         Presentation Layer                          │  UI、API控制器
├─────────────────────────────────────────────────────┤
│         Application Layer                           │  用例、编排逻辑
├─────────────────────────────────────────────────────┤
│           Domain Layer                              │  业务逻辑、实体
├─────────────────────────────────────────────────────┤
│        Infrastructure Layer                         │  数据库、外部服务
└─────────────────────────────────────────────────────┘

Rule: Dependencies point downward only

Dependency Direction

Dependency Direction

✅ GOOD                              ❌ BAD
─────────────────────────────────────────────────────
Domain → nothing                     Domain → Infrastructure
Application → Domain                 UI → Database directly
Infrastructure → Domain              Circular dependencies
Analyze dependencies:
  • Check for circular dependencies between modules
  • Ensure domain doesn't depend on infrastructure
✅ GOOD                              ❌ BAD
─────────────────────────────────────────────────────
Domain → nothing                     Domain → Infrastructure
Application → Domain                 UI → Database directly
Infrastructure → Domain              Circular dependencies
分析依赖关系:
  • 检查模块之间的循环依赖
  • 确保领域层不依赖基础设施层

Design Patterns

Design Patterns

Use patterns when they solve a real problem, not preemptively.
CategoryPatternUse When
CreationalFactoryObject creation is complex
CreationalBuilderMany optional parameters
StructuralAdapterIntegrating incompatible interfaces
StructuralFacadeSimplifying complex subsystem
BehavioralStrategyMultiple algorithms, runtime selection
BehavioralObserverMany dependents need notification
仅在解决实际问题时使用模式,不要预先使用。
类别模式使用场景
CreationalFactory对象创建逻辑复杂时
CreationalBuilder存在多个可选参数时
StructuralAdapter集成不兼容的接口时
StructuralFacade简化复杂子系统时
BehavioralStrategy存在多种算法且需运行时选择时
BehavioralObserver多个依赖项需要通知时

Security Patterns

安全模式

Input Validation

输入验证

  • Validate all external input
  • Use allowlists over denylists
  • Validate on server side
  • 验证所有外部输入
  • 使用允许列表而非拒绝列表
  • 在服务器端进行验证

Data Protection

数据保护

  • Encrypt sensitive data at rest and in transit
  • Never log sensitive information
  • Use parameterized queries (prevent SQL injection)
  • Escape output (prevent XSS)
Search for security issues:
  • Find hardcoded secrets (password assignments, API keys)
  • Find logging of potentially sensitive data

  • 对静态和传输中的敏感数据进行加密
  • 永远不要记录敏感信息
  • 使用参数化查询(防止SQL注入)
  • 对输出进行转义(防止XSS)
查找安全问题:
  • 查找硬编码的密钥(密码赋值、API密钥)
  • 查找可能包含敏感数据的日志

Phase 2: Implementation

第二阶段:实现

Guidelines for self-documenting code, naming, functions, error handling, and avoiding code smells.
关于自文档化代码、命名、函数设计、错误处理和避免代码异味的指南。

Self-Documenting Code

自文档化代码

Write code that explains itself. Avoid inline comments.
Comments are a code smell - they indicate the code isn't clear enough. Instead of adding comments, improve the code:
❌ BAD: Comment explaining unclear code
// Check if user can access the resource
if (u.r === 1 && u.s !== 0 && checkTs(u.t)) { ... }

✅ GOOD: Self-documenting code needs no comment
if (user.isAdmin && user.isActive && !user.isSessionExpired()) { ... }
When you feel the need to write a comment, first try to:
  1. Rename variables/functions to be more descriptive
  2. Extract complex logic into well-named functions
  3. Break down long expressions into meaningful intermediates
Only acceptable comments:
  • Links to external documentation (bug trackers, RFCs, specs)
  • Legal/license headers
  • Warnings about non-obvious side effects or gotchas
❌ INLINE COMMENTS (Don't write these)
─────────────────────────────────────────────────────
// Increment i
// Loop through array
// Set x to 5
// This function does stuff
// Added by John on 2024-01-15
// Get the user
// Check if valid
// Return the result
// TODO: Fix this later (track in issue tracker instead)
// FIXME: This is broken (fix it now or create an issue)

✅ ACCEPTABLE COMMENTS (Rare exceptions)
─────────────────────────────────────────────────────
// See RFC 7231 Section 6.5.4 for status code semantics
// Workaround for browser bug https://bugs.webkit.org/12345
// WARNING: This mutates the input array for performance
编写能自我解释的代码。避免内联注释。
注释是代码异味的表现——它们表明代码不够清晰。与其添加注释,不如改进代码:
❌ BAD: Comment explaining unclear code
// Check if user can access the resource
if (u.r === 1 && u.s !== 0 && checkTs(u.t)) { ... }

✅ GOOD: Self-documenting code needs no comment
if (user.isAdmin && user.isActive && !user.isSessionExpired()) { ... }
当你觉得需要写注释时,先尝试:
  1. 重命名变量/函数使其更具描述性
  2. 将复杂逻辑提取到命名清晰的函数中
  3. 将长表达式拆分为有意义的中间变量
仅可接受的注释:
  • 指向外部文档的链接(bug追踪器、RFC、规范)
  • 法律/许可证头
  • 关于非明显副作用或陷阱的警告
❌ INLINE COMMENTS (Don't write these)
─────────────────────────────────────────────────────
// Increment i
// Loop through array
// Set x to 5
// This function does stuff
// Added by John on 2024-01-15
// Get the user
// Check if valid
// Return the result
// TODO: Fix this later (track in issue tracker instead)
// FIXME: This is broken (fix it now or create an issue)

✅ ACCEPTABLE COMMENTS (Rare exceptions)
─────────────────────────────────────────────────────
// See RFC 7231 Section 6.5.4 for status code semantics
// Workaround for browser bug https://bugs.webkit.org/12345
// WARNING: This mutates the input array for performance

Naming Conventions

命名规范

Be explicit, clear, and concise. Names should reveal intent.
✅ GOOD                              ❌ BAD
─────────────────────────────────────────────────────
getUserById(userId)                  get(id)
isValidEmail(email)                  check(email)
calculateTotalPrice(items)           calc(items)
MAX_RETRY_ATTEMPTS                   MAX
userRepository                       ur
fetchUserData()                      getData()
hasPermission(user, action)          perm(u, a)
activeUsers                          list
emailAddress                         str
retryCount                           n
isEnabled                            flag
createdAt                            date
明确、清晰、简洁。名称应体现意图。
✅ GOOD                              ❌ BAD
─────────────────────────────────────────────────────
getUserById(userId)                  get(id)
isValidEmail(email)                  check(email)
calculateTotalPrice(items)           calc(items)
MAX_RETRY_ATTEMPTS                   MAX
userRepository                       ur
fetchUserData()                      getData()
hasPermission(user, action)          perm(u, a)
activeUsers                          list
emailAddress                         str
retryCount                           n
isEnabled                            flag
createdAt                            date

Avoid Ambiguous Parameters

避免模糊参数

Never use single-letter or unclear parameter names.
❌ BAD: Ambiguous parameters
function process(x) { ... }
function calc(a, b, c) { ... }
const result = items.map(x => x.value);

✅ GOOD: Clear, descriptive parameters
function processOrder(order) { ... }
function calculateDiscount(price, quantity, discountRate) { ... }
const values = items.map(item => item.value);
永远不要使用单字母或模糊的参数名称。
❌ BAD: Ambiguous parameters
function process(x) { ... }
function calc(a, b, c) { ... }
const result = items.map(x => x.value);

✅ GOOD: Clear, descriptive parameters
function processOrder(order) { ... }
function calculateDiscount(price, quantity, discountRate) { ... }
const values = items.map(item => item.value);

Naming Guidelines by Type

按类型划分的命名指南

TypeConventionExamples
VariablescamelCase, noun/noun phrase
userName
,
activeCount
,
isValid
FunctionscamelCase, verb/verb phrase
getUser
,
calculateTotal
,
validateInput
BooleansPrefix:
is
,
has
,
can
,
should
isActive
,
hasPermission
,
canEdit
ConstantsUPPER_SNAKE_CASE
MAX_RETRIES
,
API_BASE_URL
ClassesPascalCase, noun
UserService
,
OrderRepository
InterfacesPascalCase, noun/adjective
Serializable
,
UserConfig
EnumsPascalCase (name), UPPER_SNAKE (values)
Status.PENDING
,
Role.ADMIN
Private membersPrefix
_
or
#
_cache
,
#internalState
Review naming consistency:
  • List all symbols to review naming patterns
  • Query specific symbol names to check consistency
类型规范示例
变量camelCase,名词/名词短语
userName
,
activeCount
,
isValid
函数camelCase,动词/动词短语
getUser
,
calculateTotal
,
validateInput
布尔值前缀:
is
,
has
,
can
,
should
isActive
,
hasPermission
,
canEdit
常量UPPER_SNAKE_CASE
MAX_RETRIES
,
API_BASE_URL
PascalCase,名词
UserService
,
OrderRepository
接口PascalCase,名词/形容词
Serializable
,
UserConfig
枚举PascalCase(名称),UPPER_SNAKE(值)
Status.PENDING
,
Role.ADMIN
私有成员前缀
_
#
_cache
,
#internalState
检查命名一致性:
  • 列出所有符号以检查命名模式
  • 查询特定符号名称以验证一致性

File Organization

文件组织

File Naming Conventions

文件命名规范

Follow existing project structure. Be consistent.
✅ CONSISTENT FILE NAMING
─────────────────────────────────────────────────────
kebab-case (recommended for most projects):
  user-service.ts
  order-repository.ts
  api-client.test.ts

PascalCase (React components, classes):
  UserProfile.tsx
  OrderList.tsx

snake_case (Python, Ruby):
  user_service.py
  order_repository.py

ALWAYS match existing project conventions!
遵循现有项目结构。保持一致。
✅ CONSISTENT FILE NAMING
─────────────────────────────────────────────────────
kebab-case(大多数项目推荐):
  user-service.ts
  order-repository.ts
  api-client.test.ts

PascalCase(React组件、类):
  UserProfile.tsx
  OrderList.tsx

snake_case(Python、Ruby):
  user_service.py
  order_repository.py

ALWAYS match existing project conventions!

Directory Structure

目录结构

✅ GOOD STRUCTURE                    ❌ BAD STRUCTURE
─────────────────────────────────────────────────────
src/                                 src/
  users/                               utils.ts (god file)
    user-service.ts                    helpers.ts (vague)
    user-repository.ts                 misc.ts (dumping ground)
    user.types.ts                      stuff.ts (meaningless)
    user-service.test.ts               file1.ts (lazy naming)
  orders/
    order-service.ts
    order-repository.ts
✅ GOOD STRUCTURE                    ❌ BAD STRUCTURE
─────────────────────────────────────────────────────
src/                                 src/
  users/                               utils.ts (god file)
    user-service.ts                    helpers.ts (vague)
    user-repository.ts                 misc.ts (dumping ground)
    user.types.ts                      stuff.ts (meaningless)
    user-service.test.ts               file1.ts (lazy naming)
  orders/
    order-service.ts
    order-repository.ts

Follow Existing Code Structure

遵循现有代码结构

Consistency trumps personal preference.
Before writing new code:
  1. Study existing patterns - How are similar files structured?
  2. Match naming style - Use same conventions as surrounding code
  3. Follow established architecture - Don't introduce new patterns arbitrarily
  4. Respect module boundaries - Place code where similar code lives
❌ DON'T: Introduce inconsistent patterns
// Existing: userService.getById(id)
// New code: fetchSingleOrder(orderId)  // Different naming style!

✅ DO: Match existing conventions
// Existing: userService.getById(id)
// New code: orderService.getById(orderId)  // Consistent!
一致性优先于个人偏好。
编写新代码前:
  1. 研究现有模式 - 类似文件的结构是怎样的?
  2. 匹配命名风格 - 使用与周边代码相同的规范
  3. 遵循既定架构 - 不要随意引入新模式
  4. 尊重模块边界 - 将代码放在同类代码所在的位置
❌ DON'T: Introduce inconsistent patterns
// Existing: userService.getById(id)
// New code: fetchSingleOrder(orderId)  // Different naming style!

✅ DO: Match existing conventions
// Existing: userService.getById(id)
// New code: orderService.getById(orderId)  // Consistent!

Avoid Barrel Files and Re-exports

避免桶文件和重导出

Barrel files (
index.ts
re-exporting siblings) are an anti-pattern.
They hide dependencies, create circular import risks, and force wide rebuilds when unrelated exports change.
❌ BAD: Barrel file
// src/users/index.ts
export * from "./user-service";
export * from "./user-repository";

// usage
import { userService } from "./users";

✅ GOOD: Direct imports
import { userService } from "./users/user-service";
import { userRepository } from "./users/user-repository";
Rules:
  • Import from the concrete module, not
    index.ts
  • Don't add re-export layers unless a framework explicitly requires it
  • Prefer explicit dependencies over convenience
Analyze existing patterns:
  • Map project structure to understand organization
  • Inspect existing services to see how they're structured
  • Query symbol names to check naming conventions
桶文件(
index.ts
重导出同级文件)是反模式。
它们会隐藏依赖关系,带来循环导入风险,并且当无关导出项变化时会强制大范围重新构建。
❌ BAD: Barrel file
// src/users/index.ts
export * from "./user-service";
export * from "./user-repository";

// usage
import { userService } from "./users";

✅ GOOD: Direct imports
import { userService } from "./users/user-service";
import { userRepository } from "./users/user-repository";
规则:
  • 从具体模块导入,而非
    index.ts
  • 除非框架明确要求,否则不要添加重导出层
  • 优先选择显式依赖而非便捷性
分析现有模式:
  • 映射项目结构以理解组织方式
  • 检查现有服务的结构
  • 查询符号名称以验证命名规范

Function Design

函数设计

✅ BEST PRACTICES                    ❌ ANTI-PATTERNS
─────────────────────────────────────────────────────
Small, focused functions             God functions (100+ lines)
2-3 parameters max                   6+ parameters
Return early for edge cases          Deep nesting
Pure functions when possible         Hidden side effects
Descriptive names                    Abbreviations
Single level of abstraction          Mixed abstraction levels
Analyze function complexity:
  • Find callees of a function (too many = does too much)
  • View function body to assess complexity
✅ BEST PRACTICES                    ❌ ANTI-PATTERNS
─────────────────────────────────────────────────────
Small, focused functions             God functions (100+ lines)
2-3 parameters max                   6+ parameters
Return early for edge cases          Deep nesting
Pure functions when possible         Hidden side effects
Descriptive names                    Abbreviations
Single level of abstraction          Mixed abstraction levels
分析函数复杂度:
  • 查看函数的被调用方(过多则说明职责过重)
  • 查看函数体以评估复杂度

Error Handling

错误处理

Best Practices

最佳实践

✅ DO                                ❌ DON'T
─────────────────────────────────────────────────────
Fail fast and loud                   Swallow exceptions silently
Use specific exception types         Catch generic Exception
Include context in error messages    Return null for errors
Validate inputs at boundaries        Trust external data
Log errors with stack traces         Log without context
Use Result/Either types              Return magic values (-1, null)
Handle errors at appropriate level   Handle everywhere or nowhere
Let unexpected errors propagate      Catch everything "just in case"
✅ DO                                ❌ DON'T
─────────────────────────────────────────────────────
Fail fast and loud                   Swallow exceptions silently
Use specific exception types         Catch generic Exception
Include context in error messages    Return null for errors
Validate inputs at boundaries        Trust external data
Log errors with stack traces         Log without context
Use Result/Either types              Return magic values (-1, null)
Handle errors at appropriate level   Handle everywhere or nowhere
Let unexpected errors propagate      Catch everything "just in case"

Never Silence Exceptions

永远不要静默异常

Don't catch exceptions unless you can handle them meaningfully.
typescript
// ❌ NEVER: Silent catch
try {
  await saveUser(user);
} catch (error) {
  // silently ignored
}

// ❌ NEVER: Catch and log only (still loses the error)
try {
  await saveUser(user);
} catch (error) {
  console.log(error);
}

// ✅ GOOD: Let it propagate (caller handles or app crashes visibly)
await saveUser(user);

// ✅ GOOD: Handle specific errors you can recover from
try {
  await saveUser(user);
} catch (error) {
  if (error instanceof DuplicateEmailError) {
    return { error: "Email already registered" };
  }
  throw error; // Re-throw unexpected errors
}

// ✅ GOOD: Add context and re-throw
try {
  await saveUser(user);
} catch (error) {
  throw new UserServiceError(`Failed to save user ${user.id}`, {
    cause: error,
  });
}
Find problematic error handling:
  • Search for empty catch blocks
  • Search for catch blocks that only log
  • Search for bare except clauses (Python)
Rules:
  • Empty catch blocks are always wrong
  • Catch only exceptions you can meaningfully handle
  • Re-throw or propagate everything else
  • If you catch, either recover or add context and re-throw
  • Prefer crashing visibly over failing silently
除非你能有意义地处理异常,否则不要捕获它。
typescript
// ❌ NEVER: Silent catch
try {
  await saveUser(user);
} catch (error) {
  // silently ignored
}

// ❌ NEVER: Catch and log only (still loses the error)
try {
  await saveUser(user);
} catch (error) {
  console.log(error);
}

// ✅ GOOD: Let it propagate (caller handles or app crashes visibly)
await saveUser(user);

// ✅ GOOD: Handle specific errors you can recover from
try {
  await saveUser(user);
} catch (error) {
  if (error instanceof DuplicateEmailError) {
    return { error: "Email already registered" };
  }
  throw error; // Re-throw unexpected errors
}

// ✅ GOOD: Add context and re-throw
try {
  await saveUser(user);
} catch (error) {
  throw new UserServiceError(`Failed to save user ${user.id}`, {
    cause: error,
  });
}
查找有问题的错误处理:
  • 搜索空的catch块
  • 搜索仅记录日志的catch块
  • 搜索bare except子句(Python)
规则:
  • 空catch块永远是错误的
  • 仅捕获你能有意义处理的异常
  • 重新抛出或传播所有其他异常
  • 如果捕获异常,要么恢复,要么添加上下文后重新抛出
  • 优先选择明显崩溃而非静默失败

Error Handling Patterns

错误处理模式

typescript
// ✅ Result type pattern
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };

function parseConfig(path: string): Result<Config> {
  try {
    const data = readFile(path);
    return { ok: true, value: JSON.parse(data) };
  } catch (error) {
    return { ok: false, error: new ConfigError(`Invalid config: ${path}`) };
  }
}

// ✅ Early return pattern
function processUser(user: User | null): string {
  if (!user) return "No user";
  if (!user.isActive) return "User inactive";
  if (!user.hasPermission) return "No permission";

  return performAction(user); // Happy path
}
typescript
// ✅ Result type pattern
type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };

function parseConfig(path: string): Result<Config> {
  try {
    const data = readFile(path);
    return { ok: true, value: JSON.parse(data) };
  } catch (error) {
    return { ok: false, error: new ConfigError(`Invalid config: ${path}`) };
  }
}

// ✅ Early return pattern
function processUser(user: User | null): string {
  if (!user) return "No user";
  if (!user.isActive) return "User inactive";
  if (!user.hasPermission) return "No permission";

  return performAction(user); // Happy path
}

Code Smells

代码异味

SmellDescriptionRefactoringDetection
God ClassClass knows/does too muchSplit into focused classesFind callees, inspect class
Feature EnvyMethod uses other class's data moreMove method to that classAnalyze dependencies
Data ClumpsSame data groups appear togetherExtract into a classFind duplicate code
Primitive ObsessionUsing primitives for domain conceptsCreate value objectsSearch code patterns
Long Parameter ListFunctions with 5+ parametersUse parameter objectSearch code patterns
Shotgun SurgeryOne change affects many classesConsolidate related codeFind callers
Divergent ChangeOne class changed for many reasonsSplit by responsibilityInspect class
Dead CodeUnused code left in codebaseDelete itFind unused code
Speculative GeneralityCode for hypothetical futuresDelete until neededFind unused code
Detect code smells:
  • Find unused code (dead code)
  • Find duplicate code (Data Clumps pattern)
  • Find callees of suspected god functions (too many = does too much)
  • Search for functions with 5+ parameters (long parameter lists)
  • Find unused exports
异味名称描述重构方案检测方式
God Class类的职责过多拆分为多个专注的类查找被调用方,检查类的内容
Feature Envy方法更多使用其他类的数据将方法移动到对应类中分析依赖关系
Data Clumps相同的数据组反复出现提取为类查找重复代码
Primitive Obsession使用原始类型表示领域概念创建值对象搜索代码模式
Long Parameter List函数参数超过5个使用参数对象搜索代码模式
Shotgun Surgery一处修改影响多个类整合相关代码查找调用方
Divergent Change一个类因多种原因被修改按职责拆分检查类的内容
Dead Code代码库中遗留的未使用代码删除它查找未使用代码
Speculative Generality为假设的未来场景编写的代码删除直到需要时再添加查找未使用代码
检测代码异味:
  • 查找未使用的代码(死代码)
  • 查找重复代码(Data Clumps模式)
  • 查找疑似上帝函数的被调用方(过多则说明职责过重)
  • 搜索参数超过5个的函数(长参数列表)
  • 查找未使用的导出项

Linting & Code Formatting

代码检查与格式化

Automate style enforcement. Don't argue about formatting in code reviews.
自动化风格检查。不要在代码评审中争论格式问题。

Principles

原则

PrincipleWhy
Automate formattingEliminates bikeshedding, ensures consistency
Use recommended rulesBattle-tested defaults, less configuration
Lint on save/commitCatch issues early, before PR
Zero warnings policyTreat warnings as errors in CI
Format on saveNever commit unformatted code
原则原因
自动化格式化消除无意义的争论,确保一致性
使用推荐规则经过实战检验的默认配置,减少配置工作
保存/提交时检查提前发现问题,在PR之前解决
零警告策略在CI中将警告视为错误
保存时格式化永远不要提交未格式化的代码

Separation of Concerns

关注点分离

ToolPurposeExamples
FormatterCode style (spacing, quotes, etc.)Prettier, dprint, Biome, ruff format
LinterCode quality (bugs, patterns)ESLint, Biome, Ruff, Pylint
Type checkerType safetyTypeScript, mypy, Pyright
Don't overlap responsibilities. Use a formatter for formatting, a linter for logic issues. Disable linter formatting rules when using a formatter.
工具类型用途示例
格式化工具代码风格(缩进、引号等)Prettier, dprint, Biome, ruff format
代码检查工具代码质量(bug、模式)ESLint, Biome, Ruff, Pylint
类型检查工具类型安全TypeScript, mypy, Pyright
不要重叠职责。 使用格式化工具处理格式,使用代码检查工具处理逻辑问题。使用格式化工具时禁用代码检查工具中的格式规则。

When to Disable Rules

何时禁用规则

Almost never. If a rule flags your code, fix the code - don't disable the rule.
typescript
// ❌ NEVER: Disable type safety - write proper types instead
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response: any = await legacyApi.fetch();

// ✅ CORRECT: Write types for untyped APIs
interface LegacyResponse {
  data: unknown;
  status: number;
}
const response: LegacyResponse = await legacyApi.fetch();
If you think you need to disable a rule:
  1. You're wrong - fix the code instead
  2. Recommended rules exist for good reasons - follow them
  3. If you can't satisfy a rule, your design is flawed - refactor
几乎永远不要。 如果规则标记了你的代码,修复代码——不要禁用规则。
typescript
// ❌ NEVER: Disable type safety - write proper types instead
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response: any = await legacyApi.fetch();

// ✅ CORRECT: Write types for untyped APIs
interface LegacyResponse {
  data: unknown;
  status: number;
}
const response: LegacyResponse = await legacyApi.fetch();
如果你认为需要禁用规则:
  1. 你错了——修复代码
  2. 推荐规则存在是有原因的——遵循它们
  3. 如果你无法满足规则,说明你的设计有缺陷——重构

While Writing Code Checklist

编码时检查清单

  • Write tests first (or alongside)
  • Keep functions small and focused
  • Use meaningful names
  • Handle errors properly
  • Run linter and fix issues
  • Format code before committing
  • Type check passes

  • 先写测试(或同步编写)
  • 保持函数小而专注
  • 使用有意义的名称
  • 正确处理错误
  • 运行代码检查工具并修复问题
  • 提交前格式化代码
  • 类型检查通过

Phase 3: Testing

第三阶段:测试

Guidelines for test pyramid, BDD, test quality, and avoiding test anti-patterns.
关于测试金字塔、BDD、测试质量和避免测试反模式的指南。

Test Pyramid

测试金字塔

        /\
       /  \     E2E Tests (few)
      /----\    - Critical user journeys
     /      \   - Slow, expensive
    /--------\
   /          \ Integration Tests (some)
  /------------\- Component interactions
 /              \- Database, APIs
/----------------\
   Unit Tests (many)
   - Fast, isolated
   - Business logic
        /\
       /  \     E2E Tests (few)
      /----\    - Critical user journeys
     /      \   - Slow, expensive
    /--------\
   /          \ Integration Tests (some)
  /------------\- Component interactions
 /              \- Database, APIs
/----------------\
   Unit Tests (many)
   - Fast, isolated
   - Business logic

What to Test

测试范围

✅ TEST                              ❌ SKIP
─────────────────────────────────────────────────────
Business logic                       Framework code
Edge cases and boundaries            Trivial getters/setters
Error handling paths                 Third-party libraries
Public API contracts                 Private implementation details
Integration points                   UI layout (use visual tests)
Security-sensitive code              Configuration files
✅ TEST                              ❌ SKIP
─────────────────────────────────────────────────────
Business logic                       Framework code
Edge cases and boundaries            Trivial getters/setters
Error handling paths                 Third-party libraries
Public API contracts                 Private implementation details
Integration points                   UI layout (use visual tests)
Security-sensitive code              Configuration files

Test Quality Checklist

测试质量检查清单

  • Tests are independent and isolated
  • Tests are deterministic (no flakiness)
  • Test names describe behavior being tested
  • Each test has a single reason to fail
  • Tests run fast (< 100ms for unit tests)
  • Tests use meaningful assertions
  • Setup/teardown is minimal and clear
  • 测试独立且隔离
  • 测试具有确定性(无随机性失败)
  • 测试名称描述了要验证的行为
  • 每个测试只有一个失败原因
  • 测试运行快速(单元测试<100ms)
  • 测试使用有意义的断言
  • 初始化/清理逻辑简洁清晰

Behavior-Driven Development (BDD)

Behavior-Driven Development (BDD)

BDD bridges the gap between business requirements and technical implementation by using a shared language that all stakeholders understand.
Business Need → Executable Specification → Working Software
BDD通过使用所有利益相关者都能理解的通用语言,弥合业务需求与技术实现之间的差距。
Business Need → Executable Specification → Working Software

Structure: Given-When-Then

结构:Given-When-Then

Organize tests around three phases:
PhasePurposeExample
GivenPreconditions, initial state"a registered user exists"
WhenAction being performed"the user logs in with valid credentials"
ThenExpected outcome"the user should see their dashboard"
将测试组织为三个阶段:
阶段用途示例
Given前置条件、初始状态"存在一个已注册用户"
When执行的操作"用户使用有效凭据登录"
Then预期结果"用户应看到其仪表板"

Writing Good Scenarios

编写良好的场景

❌ BAD: Implementation details, unclear intent
─────────────────────────────────────────────────────
"open browser, navigate to /login, find element with
id email, type test@test.com, click submit button"

✅ GOOD: Business language, clear intent
─────────────────────────────────────────────────────
Given a registered user exists
When the user logs in with valid credentials
Then the user should see their dashboard
❌ BAD: Implementation details, unclear intent
─────────────────────────────────────────────────────
"open browser, navigate to /login, find element with
id email, type test@test.com, click submit button"

✅ GOOD: Business language, clear intent
─────────────────────────────────────────────────────
Given a registered user exists
When the user logs in with valid credentials
Then the user should see their dashboard

BDD Best Practices

BDD最佳实践

✅ DO                                ❌ DON'T
─────────────────────────────────────────────────────
Write from user's perspective        Use technical jargon
One behavior per scenario            Test multiple things
Use declarative style                Include implementation details
Keep scenarios independent           Share state between scenarios
Use meaningful data                  Use "test", "foo", "bar"
Focus on business outcomes           Focus on UI interactions
✅ DO                                ❌ DON'T
─────────────────────────────────────────────────────
Write from user's perspective        Use technical jargon
One behavior per scenario            Test multiple things
Use declarative style                Include implementation details
Keep scenarios independent           Share state between scenarios
Use meaningful data                  Use "test", "foo", "bar"
Focus on business outcomes           Focus on UI interactions

Three Amigos

Three Amigos

BDD works best when three perspectives collaborate:
  1. Business/Product: What problem are we solving?
  2. Development: How will we build it?
  3. Testing: What could go wrong?
Before writing code:
  • Discuss requirements together
  • Write scenarios collaboratively
  • Agree on acceptance criteria
  • Identify edge cases early
BDD在三种角色协作时效果最佳:
  1. 业务/产品:我们要解决什么问题?
  2. 开发:我们将如何构建它?
  3. 测试:可能会出什么问题?
编写代码前:
  • 共同讨论需求
  • 协作编写场景
  • 达成验收标准一致
  • 提前识别边缘情况

Writing BDD Tests

编写BDD测试

Basic BDD Structure

基础BDD结构

typescript
describe("UserService", () => {
  describe("given a new user with valid data", () => {
    const userData = { name: "Alice", email: "alice@example.com" };

    describe("when creating the user", () => {
      it("then the user should be created with an ID", async () => {
        const userService = new UserService();
        const user = await userService.create(userData);

        expect(user.id).toBeDefined();
        expect(user.name).toBe("Alice");
        expect(user.email).toBe("alice@example.com");
      });
    });
  });

  describe("given user data with an invalid email", () => {
    const userData = { name: "Bob", email: "invalid-email" };

    describe("when creating the user", () => {
      it("then it should reject with a validation error", async () => {
        const userService = new UserService();

        await expect(userService.create(userData)).rejects.toThrow(
          "Invalid email",
        );
      });
    });
  });
});
typescript
describe("UserService", () => {
  describe("given a new user with valid data", () => {
    const userData = { name: "Alice", email: "alice@example.com" };

    describe("when creating the user", () => {
      it("then the user should be created with an ID", async () => {
        const userService = new UserService();
        const user = await userService.create(userData);

        expect(user.id).toBeDefined();
        expect(user.name).toBe("Alice");
        expect(user.email).toBe("alice@example.com");
      });
    });
  });

  describe("given user data with an invalid email", () => {
    const userData = { name: "Bob", email: "invalid-email" };

    describe("when creating the user", () => {
      it("then it should reject with a validation error", async () => {
        const userService = new UserService();

        await expect(userService.create(userData)).rejects.toThrow(
          "Invalid email",
        );
      });
    });
  });
});

BDD with Shared Context

带共享上下文的BDD

typescript
describe("User Login", () => {
  describe("given a registered user exists", () => {
    let user: User;

    beforeEach(async () => {
      user = await createUser({
        email: "alice@example.com",
        password: "secure123",
      });
    });

    describe("when the user logs in with valid credentials", () => {
      let session: Session;

      beforeEach(async () => {
        session = await login(user.email, "secure123");
      });

      it("then a valid session should be created", () => {
        expect(session.token).toBeDefined();
        expect(session.userId).toBe(user.id);
      });

      it("then the user should be able to access their dashboard", async () => {
        const dashboard = await getDashboard(session);

        expect(dashboard.userId).toBe(user.id);
        expect(dashboard.welcomeMessage).toContain(user.name);
      });
    });

    describe("when the user logs in with wrong password", () => {
      it("then login should fail with authentication error", async () => {
        await expect(login(user.email, "wrongpassword")).rejects.toThrow(
          "Invalid credentials",
        );
      });
    });
  });
});
typescript
describe("User Login", () => {
  describe("given a registered user exists", () => {
    let user: User;

    beforeEach(async () => {
      user = await createUser({
        email: "alice@example.com",
        password: "secure123",
      });
    });

    describe("when the user logs in with valid credentials", () => {
      let session: Session;

      beforeEach(async () => {
        session = await login(user.email, "secure123");
      });

      it("then a valid session should be created", () => {
        expect(session.token).toBeDefined();
        expect(session.userId).toBe(user.id);
      });

      it("then the user should be able to access their dashboard", async () => {
        const dashboard = await getDashboard(session);

        expect(dashboard.userId).toBe(user.id);
        expect(dashboard.welcomeMessage).toContain(user.name);
      });
    });

    describe("when the user logs in with wrong password", () => {
      it("then login should fail with authentication error", async () => {
        await expect(login(user.email, "wrongpassword")).rejects.toThrow(
          "Invalid credentials",
        );
      });
    });
  });
});

BDD Error Handling Tests

BDD错误处理测试

typescript
describe("User Processing", () => {
  describe("given a null user input", () => {
    describe("when processing the user", () => {
      it("then it should throw a validation error", () => {
        expect(() => processUser(null)).toThrow("User cannot be null");
      });
    });
  });

  describe("given an invalid user ID", () => {
    describe("when fetching the user", () => {
      it("then it should throw a ValidationError", async () => {
        await expect(fetchUser(-1)).rejects.toBeInstanceOf(ValidationError);
      });

      it("then the error should include the invalid ID", async () => {
        await expect(fetchUser(-1)).rejects.toThrow(/invalid user id.*-1/i);
      });
    });
  });
});
typescript
describe("User Processing", () => {
  describe("given a null user input", () => {
    describe("when processing the user", () => {
      it("then it should throw a validation error", () => {
        expect(() => processUser(null)).toThrow("User cannot be null");
      });
    });
  });

  describe("given an invalid user ID", () => {
    describe("when fetching the user", () => {
      it("then it should throw a ValidationError", async () => {
        await expect(fetchUser(-1)).rejects.toBeInstanceOf(ValidationError);
      });

      it("then the error should include the invalid ID", async () => {
        await expect(fetchUser(-1)).rejects.toThrow(/invalid user id.*-1/i);
      });
    });
  });
});

BDD with Parametrized Tests

带参数化测试的BDD

typescript
describe("Order Discount Calculation", () => {
  describe("given different order totals", () => {
    const testCases = [
      { orderTotal: 50, expectedDiscount: 0, scenario: "order under $100" },
      { orderTotal: 100, expectedDiscount: 10, scenario: "order exactly $100" },
      {
        orderTotal: 250,
        expectedDiscount: 25,
        scenario: "order between $100-$500",
      },
      { orderTotal: 500, expectedDiscount: 75, scenario: "order exactly $500" },
      { orderTotal: 1000, expectedDiscount: 150, scenario: "order over $500" },
    ];

    testCases.forEach(({ orderTotal, expectedDiscount, scenario }) => {
      describe(`given an ${scenario} ($${orderTotal})`, () => {
        describe("when calculating the discount", () => {
          it(`then the discount should be $${expectedDiscount}`, () => {
            const discount = calculateDiscount(orderTotal);
            expect(discount).toBe(expectedDiscount);
          });
        });
      });
    });
  });
});
typescript
describe("Order Discount Calculation", () => {
  describe("given different order totals", () => {
    const testCases = [
      { orderTotal: 50, expectedDiscount: 0, scenario: "order under $100" },
      { orderTotal: 100, expectedDiscount: 10, scenario: "order exactly $100" },
      {
        orderTotal: 250,
        expectedDiscount: 25,
        scenario: "order between $100-$500",
      },
      { orderTotal: 500, expectedDiscount: 75, scenario: "order exactly $500" },
      { orderTotal: 1000, expectedDiscount: 150, scenario: "order over $500" },
    ];

    testCases.forEach(({ orderTotal, expectedDiscount, scenario }) => {
      describe(`given an ${scenario} ($${orderTotal})`, () => {
        describe("when calculating the discount", () => {
          it(`then the discount should be $${expectedDiscount}`, () => {
            const discount = calculateDiscount(orderTotal);
            expect(discount).toBe(expectedDiscount);
          });
        });
      });
    });
  });
});

Finding Untested Code

查找未测试代码

  • Generate coverage reports to see which lines/branches are untested
  • Find tests for a specific symbol to see what's covered
  • Find untested symbols to identify gaps
  • Find what production code a test file touches
  • 生成覆盖率报告查看哪些行/分支未被测试
  • 查找特定符号的测试,了解覆盖情况
  • 查找未被测试的符号以识别缺口
  • 查找测试文件涉及的生产代码

Testing Anti-Patterns

测试反模式

Anti-PatternProblemSolution
Ice Cream ConeMore E2E tests than unit testsInvert the pyramid
Flaky TestsTests randomly failFix race conditions, use mocks
Slow TestsTest suite takes too longIsolate, parallelize, mock I/O
Testing ImplementationTests break on refactorTest behavior, not internals
No AssertionsTests without meaningful checksAdd specific assertions
Test Data CouplingTests depend on shared stateIsolate test data
反模式名称问题解决方案
Ice Cream ConeE2E测试数量超过单元测试反转测试金字塔
Flaky Tests测试随机失败修复竞态条件,使用mock
Slow Tests测试套件运行时间过长隔离测试,并行执行,mock I/O
Testing Implementation重构时测试会失败测试行为,而非内部实现
No Assertions测试没有有意义的检查添加具体断言
Test Data Coupling测试依赖共享状态隔离测试数据

BDD Anti-Patterns

BDD反模式

Anti-PatternProblemSolution
UI-focused stepsBrittle, hard to readUse domain language
Too many stepsHard to understandSplit into focused scenarios
Incidental detailsNoise obscures intentInclude only relevant data
No clear outcomeCan't tell what's testedEnd with business assertion
Coupled scenariosOrder-dependent testsMake scenarios independent
Developer jargonBusiness can't validateUse ubiquitous language
Detect test anti-patterns:
  • Search for test blocks without assertions
  • Run tests with verbose timing to find slow tests
反模式名称问题解决方案
UI-focused steps脆弱、难以阅读使用领域语言
Too many steps难以理解拆分为专注的场景
Incidental details无关信息掩盖意图仅包含相关数据
No clear outcome无法明确测试目标以业务断言结尾
Coupled scenarios测试依赖执行顺序使场景相互独立
Developer jargon业务人员无法验证使用通用语言
检测测试反模式:
  • 搜索没有断言的测试块
  • 运行测试并查看详细计时以找到慢测试

Test Organization

测试组织

File Structure

文件结构

src/
  users/
    user-service.ts
    user-service.test.ts    # Co-located tests
  orders/
    order-service.ts
    order-service.test.ts
src/
  users/
    user-service.ts
    user-service.test.ts    # 同目录测试
  orders/
    order-service.ts
    order-service.test.ts

OR

OR

src/ users/ user-service.ts tests/ users/ user-service.test.ts # Mirrored structure
undefined
src/ users/ user-service.ts tests/ users/ user-service.test.ts # 镜像结构
undefined

Naming Tests (BDD Style)

测试命名(BDD风格)

typescript
// ❌ BAD: Vague names, no context
it("works", () => {});
it("handles error", () => {});
it("test1", () => {});

// ❌ BAD: Missing Given-When-Then structure
describe("UserService", () => {
  it("creates user", () => {});
  it("throws on invalid email", () => {});
});

// ✅ GOOD: Full BDD structure with Given-When-Then
describe("UserService", () => {
  describe("given valid user data", () => {
    describe("when creating a user", () => {
      it("then the user should be persisted with an ID", () => {});
    });
  });

  describe("given an invalid email format", () => {
    describe("when creating a user", () => {
      it("then a ValidationError should be thrown", () => {});
    });
  });
});

typescript
// ❌ BAD: Vague names, no context
it("works", () => {});
it("handles error", () => {});
it("test1", () => {});

// ❌ BAD: Missing Given-When-Then structure
describe("UserService", () => {
  it("creates user", () => {});
  it("throws on invalid email", () => {});
});

// ✅ GOOD: Full BDD structure with Given-When-Then
describe("UserService", () => {
  describe("given valid user data", () => {
    describe("when creating a user", () => {
      it("then the user should be persisted with an ID", () => {});
    });
  });

  describe("given an invalid email format", () => {
    describe("when creating a user", () => {
      it("then a ValidationError should be thrown", () => {});
    });
  });
});

Phase 4: Review

第四阶段:评审

Code review checklist and self-review guidelines before PR.
代码评审检查清单和PR前的自审指南。

Self-Review Before PR

PR前自审

Before submitting code for review, run these checks:
提交代码评审前,执行以下检查:

Automated Checks

自动化检查

  • Type check passes
  • Linter passes (fix issues)
  • Formatter applied
  • All tests pass
  • Coverage meets threshold
  • 类型检查通过
  • 代码检查通过(修复问题)
  • 代码已格式化
  • 所有测试通过
  • 覆盖率达到阈值

Code Quality Checks

代码质量检查

  • Find unused code
  • Find duplicate code
  • Check for circular dependencies
  • 查找未使用代码
  • 查找重复代码
  • 检查循环依赖

Manual Checklist

手动检查清单

  • Code compiles and runs without errors
  • All tests pass
  • No debug code or console.log left behind
  • No commented-out code
  • Code is properly formatted
  • Branch is up to date with main
  • 代码编译并能正常运行
  • 所有测试通过
  • 没有遗留调试代码或console.log
  • 没有注释掉的代码
  • 代码已正确格式化
  • 分支已与主分支同步

Code Review Checklist

代码评审检查清单

Correctness

正确性

  • Does the code do what it's supposed to?
  • Are edge cases handled?
  • Are there any obvious bugs?
  • Are error cases properly handled?
Verify:
  • Trace the call flow to understand what code does
  • Find callees of a function to see what it depends on
  • 代码是否实现了预期功能?
  • 边缘情况是否被处理?
  • 是否存在明显的bug?
  • 错误情况是否被正确处理?
验证:
  • 跟踪调用流程以理解代码功能
  • 查找函数的被调用方以了解其依赖

Design

设计

  • Is the code at the right abstraction level?
  • Does it follow SOLID principles?
  • Are there any code smells?
  • Is there unnecessary complexity?
  • Are dependencies appropriate?
Verify:
  • Find duplicate code
  • Check dependency direction
  • Check for circular dependencies
  • Find unused code
  • 代码的抽象层级是否合适?
  • 是否遵循SOLID原则?
  • 是否存在代码异味?
  • 是否存在不必要的复杂度?
  • 依赖关系是否合理?
验证:
  • 查找重复代码
  • 检查依赖方向
  • 检查循环依赖
  • 查找未使用代码

Readability

可读性

  • Is the code easy to understand?
  • Are names meaningful and consistent?
  • Is the logic straightforward?
  • Are there unnecessary comments? (code should be self-documenting)
  • Is the file organization clear?
Review:
  • Map module structure to understand organization
  • Check naming consistency by querying symbols
  • 代码是否易于理解?
  • 名称是否有意义且一致?
  • 逻辑是否直接明了?
  • 是否存在不必要的注释?(代码应自我解释)
  • 文件组织是否清晰?
评审:
  • 映射模块结构以理解组织方式
  • 查询符号以检查命名一致性

Maintainability

可维护性

  • Is the code testable?
  • Are dependencies injected?
  • Is there appropriate documentation for public APIs?
  • Will this be easy to modify in the future?
  • Are magic numbers/strings avoided?
Find issues:
  • Search for hardcoded numbers (magic values)
  • Search for hardcoded strings that should be constants
  • 代码是否可测试?
  • 是否使用了依赖注入?
  • 公共API是否有适当的文档?
  • 未来是否易于修改?
  • 是否避免了魔法数字/字符串?
查找问题:
  • 搜索硬编码数字(魔法值)
  • 搜索应作为常量的硬编码字符串

Security

安全性

  • Is user input validated?
  • Are there any injection vulnerabilities?
  • Are secrets properly handled?
  • Is authentication/authorization correct?
  • Is sensitive data protected?
Security checks:
  • Search for string concatenation in queries (SQL injection)
  • Search for template literals in queries
  • Search for hardcoded passwords and API keys
  • Search for eval() usage
  • 用户输入是否被验证?
  • 是否存在注入漏洞?
  • 密钥是否被正确处理?
  • 认证/授权是否正确?
  • 敏感数据是否被保护?
安全检查:
  • 搜索查询中的字符串拼接(SQL注入)
  • 搜索查询中的模板字符串
  • 搜索硬编码的密码和API密钥
  • 搜索eval()的使用

Performance

性能

  • Are there any obvious performance issues?
  • Are N+1 queries avoided?
  • Is caching considered where appropriate?
  • Are there unnecessary computations?
  • Is memory usage reasonable?
Find performance issues:
  • Search for await inside loops (N+1 patterns)
  • Search for async map/forEach patterns
  • 是否存在明显的性能问题?
  • 是否避免了N+1查询?
  • 是否在合适的地方考虑了缓存?
  • 是否存在不必要的计算?
  • 内存使用是否合理?
查找性能问题:
  • 搜索循环中的await(N+1模式)
  • 搜索async map/forEach模式

Test Coverage

测试覆盖率

  • Are there sufficient tests?
  • Do tests cover edge cases?
  • Are tests testing behavior, not implementation?
Check:
  • Find untested symbols
  • Find tests for specific functions
  • Run coverage report
  • 测试是否充分?
  • 测试是否覆盖了边缘情况?
  • 测试是否验证行为而非实现?
检查:
  • 查找未被测试的符号
  • 查找特定函数的测试
  • 运行覆盖率报告

Review Best Practices

评审最佳实践

For Reviewers

评审者

  • Focus on the code, not the author
  • Ask questions rather than make demands
  • Explain the "why" behind suggestions
  • Distinguish between blocking issues and nitpicks
  • Acknowledge good solutions
Use analysis to support reviews:
  • View the diff to understand what changed
  • Find callers of changed functions to trace impact
  • Find tests for changed functions to verify coverage
  • 关注代码而非作者
  • 提出问题而非下达命令
  • 解释建议背后的原因
  • 区分阻塞问题和小细节
  • 认可好的解决方案
使用分析支持评审:
  • 查看差异以理解变更内容
  • 查找变更函数的调用方以跟踪影响
  • 查找变更函数的测试以验证覆盖率

For Authors

作者

  • Keep PRs small and focused
  • Provide context in PR description
  • Respond to all comments
  • Don't take feedback personally
  • Ask for clarification when needed
Before requesting review:
  • Run all automated checks (type check, lint, tests)
  • Self-review the diff
  • Check for common issues (unused code, duplication)
  • 保持PR小而专注
  • 在PR描述中提供上下文
  • 回复所有评论
  • 不要把反馈个人化
  • 需要时请求澄清
请求评审前:
  • 运行所有自动化检查(类型检查、代码检查、测试)
  • 自审差异
  • 检查常见问题(未使用代码、重复代码)

Common Review Questions

常见评审问题

Architecture:
  • Does this belong in this module/layer?
  • Are dependencies flowing in the right direction?
  • Is this the right level of abstraction?
Testing:
  • Are there sufficient tests?
  • Do tests cover edge cases?
  • Are tests testing behavior, not implementation?
Future-proofing:
  • Will this scale?
  • Is this maintainable?
  • Are we introducing technical debt?

架构:
  • 代码是否属于当前模块/层级?
  • 依赖方向是否正确?
  • 抽象层级是否合适?
测试:
  • 测试是否充分?
  • 测试是否覆盖了边缘情况?
  • 测试是否验证行为而非实现?
未来兼容性:
  • 代码是否可扩展?
  • 是否易于维护?
  • 是否引入了技术债务?

Phase 5: Maintenance

第五阶段:维护

Guidelines for refactoring, technical debt, performance, and documentation.
关于重构、技术债务、性能和文档的指南。

Refactoring

重构

Safe Refactoring Steps

安全重构步骤

  1. Ensure test coverage before refactoring
  2. Make small, incremental changes
  3. Run tests after each change
  4. Commit frequently
  5. Refactor OR add features, never both
  1. 确保测试覆盖率 在重构前
  2. 进行小的、增量式变更
  3. 每次变更后运行测试
  4. 频繁提交
  5. 要么重构要么添加功能,不要同时进行

Pre-Refactoring Analysis

重构前分析

  • Check test coverage for the code you're refactoring
  • Find callers of the function to understand what depends on it
  • Find callees of the function to understand what it depends on
  • Find duplicate code that should be refactored together
  • 检查要重构代码的测试覆盖率
  • 查找函数的调用方以了解依赖
  • 查找函数的被调用方以了解其依赖
  • 查找应一起重构的重复代码

Common Refactorings

常见重构技巧

TechniqueWhen to UseAnalysis
Extract MethodLong method, reusable logicSearch for patterns to replace
Extract ClassClass has multiple responsibilitiesFind callees to identify groups
Inline MethodMethod body is as clear as nameSearch and replace pattern
Move MethodMethod uses another class's data moreAnalyze dependencies
RenameName doesn't reveal intentSearch and replace across codebase
Replace Conditional with PolymorphismComplex type-checking logicSearch for switch/if chains
Replace Magic Number with ConstantUnexplained numeric literalsSearch for hardcoded values
Introduce Parameter ObjectLong parameter listsSearch for long parameter patterns
Replace Inheritance with CompositionInheritance is forcedAnalyze class hierarchy
技巧名称使用场景分析方式
Extract Method长方法、可复用逻辑搜索可替换的模式
Extract Class类有多个职责查找被调用方以识别职责组
Inline Method方法体与名称一样清晰搜索并替换模式
Move Method方法更多使用其他类的数据分析依赖关系
Rename名称无法体现意图全代码库搜索替换
Replace Conditional with Polymorphism复杂的类型检查逻辑搜索switch/if链
Replace Magic Number with Constant无法解释的数值字面量搜索硬编码值
Introduce Parameter Object长参数列表搜索长参数模式
Replace Inheritance with Composition强制使用继承分析类层级

Refactoring Workflow

重构工作流

  1. Analyze - Find callers, callees, and tests for the target
  2. Preview changes - Dry-run search/replace to see what would change
  3. Apply changes - Execute the refactoring
  4. Run tests - Verify nothing broke
  5. Commit - Save progress with meaningful message
  1. 分析 - 查找目标代码的调用方、被调用方和测试
  2. 预览变更 - 试运行搜索替换以查看影响范围
  3. 应用变更 - 执行重构
  4. 运行测试 - 验证没有问题
  5. 提交 - 用有意义的消息保存进度

Technical Debt

技术债务

Types of Technical Debt

技术债务类型

TypeDescriptionHandlingDetection
DeliberateConscious shortcutsDocument, schedule paybackIssues tracker
AccidentalUnintentional issuesFix when discoveredLint warnings, code review
Bit RotCode ages poorlyRegular maintenanceUnused code, dependency analysis
Outdated DependenciesSecurity/compatibilityRegular updatesDependency audit
类型描述处理方式检测方式
Deliberate有意识的捷径记录,安排偿还时间问题追踪器
Accidental无意引入的问题发现后立即修复代码检查警告、代码评审
Bit Rot代码随时间老化定期维护未使用代码、依赖分析
Outdated Dependencies安全/兼容性问题定期更新依赖审计

Finding Technical Debt

查找技术债务

  • Find unused code (dead code debt) - files, exports, dependencies
  • Find duplicate code (DRY violation debt)
  • Find circular dependencies (architecture debt)
  • Find outdated dependencies
  • 查找未使用代码(死代码债务)- 文件、导出项、依赖项
  • 查找重复代码(违反DRY原则债务)
  • 查找循环依赖(架构债务)
  • 查找过时依赖

Managing Debt

管理债务

  1. Track it - Document in issues/backlog
  2. Quantify it - Estimate effort to fix
  3. Prioritize it - Balance with features
  4. Pay it down - Allocate time each sprint
  5. Prevent it - Code reviews, standards
  1. 跟踪 - 在问题/待办事项中记录
  2. 量化 - 估算修复工作量
  3. 优先级排序 - 与功能需求平衡
  4. 偿还 - 每个迭代分配时间
  5. 预防 - 代码评审、标准规范

Performance

性能

Optimization Rules

优化规则

  1. Don't optimize prematurely - Make it work first
  2. Measure before optimizing - Profile to find bottlenecks
  3. Optimize the right thing - Focus on hot paths
  4. Know the costs - Understand time/space complexity
  1. 不要过早优化 - 先让代码运行起来
  2. 优化前先测量 - 通过分析找到瓶颈
  3. 优化正确的部分 - 关注热点路径
  4. 了解成本 - 理解时间/空间复杂度

Common Performance Pitfalls

常见性能陷阱

PitfallSolutionDetection
N+1 queriesBatch queries, use joinsSearch for await in loops
Unnecessary computationCache results, lazy evaluationProfiling
Memory leaksClean up references, use weak refsMemory profiling
Blocking I/OUse async operationsCode review
Large payloadsPaginate, compress, filter fieldsNetwork profiling
No indexingAdd database indexesQuery analysis
Find performance issues:
  • Search for N+1 query patterns (await inside loops)
  • Search for synchronous file operations
  • Search for expensive operations in loops (e.g., JSON.parse in loop)
陷阱名称解决方案检测方式
N+1 queries批量查询、使用连接搜索循环中的await
Unnecessary computation缓存结果、延迟计算性能分析
Memory leaks清理引用、使用弱引用内存分析
Blocking I/O使用异步操作代码评审
Large payloads分页、压缩、过滤字段网络分析
No indexing添加数据库索引查询分析
查找性能问题:
  • 搜索N+1查询模式(循环中的await)
  • 搜索同步文件操作
  • 搜索循环中的昂贵操作(如JSON.parse)

Cleanup and Maintenance

清理与维护

Regular Maintenance Tasks

定期维护任务

  1. Update dependencies - Keep packages current
  2. Check for security issues - Run security audits
  3. Remove unused code - Delete unused files/exports
  4. Remove duplicate code - Extract and reuse
  5. Fix circular dependencies - Refactor to break cycles
  6. Update outdated patterns - Modernize legacy code
  1. 更新依赖 - 保持包为最新版本
  2. 检查安全问题 - 运行安全审计
  3. 删除未使用代码 - 删除未使用的文件/导出项
  4. 删除重复代码 - 提取并复用
  5. 修复循环依赖 - 重构以打破循环
  6. 更新过时模式 - 现代化遗留代码

Documentation

文档

What to Document

文档范围

✅ DOCUMENT                          ❌ SKIP
─────────────────────────────────────────────────────
Public APIs                          Obvious code
Architecture decisions (ADRs)        Implementation details
Setup and deployment                 Every function
Non-obvious behavior                 Self-documenting code
Known limitations                    Temporary hacks (fix them)
✅ DOCUMENT                          ❌ SKIP
─────────────────────────────────────────────────────
Public APIs                          Obvious code
Architecture decisions (ADRs)        Implementation details
Setup and deployment                 Every function
Non-obvious behavior                 Self-documenting code
Known limitations                    Temporary hacks (fix them)

Documentation Types

文档类型

TypePurposeLocation
READMEProject overview, setupRepository root
API DocsEndpoint/function referenceGenerated from code
ADRsArchitecture decisions
docs/adr/
RunbooksOperational procedures
docs/runbooks/
Inline CommentsNon-obvious code explanationsIn source code (rare)
类型用途位置
README项目概述、安装配置仓库根目录
API Docs端点/函数参考文档从代码生成
ADRs架构决策记录
docs/adr/
Runbooks操作流程文档
docs/runbooks/
Inline Comments非明显代码的解释源代码中(罕见)

Architectural Anti-Patterns

架构反模式

Anti-PatternProblemSolutionDetection
Big Ball of MudNo clear structureDefine boundaries and layersMap structure, analyze deps
Golden HammerUsing one solution for everythingChoose right tool for jobCode review
Spaghetti CodeTangled, unstructured codeModularize, add structureCheck circular dependencies
Lava FlowDead code nobody dares removeDocument and deleteFind unused code
Copy-Paste ProgrammingDuplicated code everywhereExtract and reuseFind duplicate code
Magic Numbers/StringsHardcoded values without contextUse named constantsSearch for hardcoded values
Circular DependenciesModules depend on each otherIntroduce abstraction layerAnalyze dependency cycles
Leaky AbstractionImplementation details leak outStrengthen encapsulationCheck exports vs internals
反模式名称问题解决方案检测方式
Big Ball of Mud没有清晰的结构定义边界和层级映射结构、分析依赖
Golden Hammer用一种解决方案解决所有问题选择合适的工具代码评审
Spaghetti Code代码混乱无结构模块化、添加结构检查循环依赖
Lava Flow无人敢删除的死代码记录并删除查找未使用代码
Copy-Paste Programming代码重复到处都是提取并复用查找重复代码
Magic Numbers/Strings无上下文的硬编码值使用命名常量搜索硬编码值
Circular Dependencies模块相互依赖引入抽象层分析依赖循环
Leaky Abstraction实现细节暴露加强封装检查导出项与内部实现

After Writing Code Checklist

代码编写后检查清单

  • Self-review before PR
  • Ensure tests pass
  • Update documentation
  • Clean up debug code
  • Check for unused code
  • Check for duplication
  • Commit with meaningful message
  • PR前自审
  • 确保测试通过
  • 更新文档
  • 清理调试代码
  • 检查未使用代码
  • 检查重复代码
  • 用有意义的消息提交

Code Quality Mantras

代码质量格言

"Make it work, make it right, make it fast" - Kent Beck
"Any fool can write code that a computer can understand.
 Good programmers write code that humans can understand." - Martin Fowler
"Simplicity is the ultimate sophistication" - Leonardo da Vinci
"The best code is no code at all" - Jeff Atwood
"Make it work, make it right, make it fast" - Kent Beck
"Any fool can write code that a computer can understand.
 Good programmers write code that humans can understand." - Martin Fowler
"Simplicity is the ultimate sophistication" - Leonardo da Vinci
"The best code is no code at all" - Jeff Atwood