phase-2-convention

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Phase 2: Coding Convention

第二阶段:编码规范

Define code writing rules
定义代码编写规则

Purpose

目的

Maintain consistent code style. Especially important when collaborating with AI - clarify what style AI should use when writing code.
保持代码风格一致。在与AI协作时尤为重要——明确AI编写代码时应遵循的风格。

What to Do in This Phase

本阶段需完成事项

  1. Naming Rules: Variables, functions, files, folder names
  2. Code Style: Indentation, quotes, semicolons, etc.
  3. Structure Rules: Folder structure, file separation criteria
  4. Pattern Definition: Frequently used code patterns
  1. 命名规则:变量、函数、文件、文件夹命名
  2. 代码风格:缩进、引号、分号等
  3. 结构规则:文件夹结构、文件拆分标准
  4. 模式定义:常用代码模式

Deliverables

交付物

Project Root/
├── CONVENTIONS.md          # Full conventions
└── docs/01-plan/
    ├── naming.md           # Naming rules
    └── structure.md        # Structure rules
Project Root/
├── CONVENTIONS.md          # 完整规范文档
└── docs/01-plan/
    ├── naming.md           # 命名规则
    └── structure.md        # 结构规则

PDCA Application

PDCA循环应用

  • Plan: Identify necessary convention items
  • Design: Design detailed rules
  • Do: Write convention documents
  • Check: Review consistency/practicality
  • Act: Finalize and proceed to Phase 3
  • Plan(计划):确定所需的规范条目
  • Design(设计):制定详细规则
  • Do(执行):编写规范文档
  • Check(检查):审核一致性与实用性
  • Act(处理):最终确定并进入第三阶段

Level-wise Application

分级别应用

LevelApplication Level
StarterBasic (essential rules only)
DynamicExtended (including API, state management)
EnterpriseExtended (per-service rules)
级别应用程度
Starter基础版(仅包含核心规则)
Dynamic扩展版(包含API、状态管理相关规则)
Enterprise企业版(按服务制定专属规则)

Core Convention Items

核心规范条目

Naming

命名规则

  • Components: PascalCase
  • Functions: camelCase
  • Constants: UPPER_SNAKE_CASE
  • Files: kebab-case or PascalCase
  • 组件:PascalCase
  • 函数:camelCase
  • 常量:UPPER_SNAKE_CASE
  • 文件:kebab-case 或 PascalCase

Folder Structure

文件夹结构

src/
├── components/     # Reusable components
├── features/       # Feature modules
├── hooks/          # Custom hooks
├── utils/          # Utilities
└── types/          # Type definitions

src/
├── components/     # 可复用组件
├── features/       # 功能模块
├── hooks/          # 自定义hooks
├── utils/          # 工具函数
└── types/          # 类型定义

Environment Variable Convention

环境变量规范

Why Define at Design Stage?

为何在设计阶段定义?

❌ Organizing env vars just before deployment
   → Missing variables, naming inconsistency, deployment delays

✅ Establish convention at design stage
   → Consistent naming, clear categorization, fast deployment
❌ 临近部署时才整理环境变量
   → 遗漏变量、命名不一致、部署延迟

✅ 在设计阶段确立规范
   → 命名统一、分类清晰、部署高效

Environment Variable Naming Rules

环境变量命名规则

PrefixPurposeExposure ScopeExample
NEXT_PUBLIC_
Client-exposedBrowser
NEXT_PUBLIC_API_URL
DB_
DatabaseServer only
DB_HOST
,
DB_PASSWORD
API_
External API keysServer only
API_STRIPE_SECRET
AUTH_
AuthenticationServer only
AUTH_SECRET
,
AUTH_GOOGLE_ID
SMTP_
Email serviceServer only
SMTP_HOST
,
SMTP_PASSWORD
STORAGE_
File storageServer only
STORAGE_S3_BUCKET
⚠️ Security Principles
- Never expose anything except NEXT_PUBLIC_* to client
- API keys and passwords must be server-only variables
- Never commit sensitive info in .env files
前缀用途暴露范围示例
NEXT_PUBLIC_
客户端可访问浏览器
NEXT_PUBLIC_API_URL
DB_
数据库相关仅服务端
DB_HOST
,
DB_PASSWORD
API_
外部API密钥仅服务端
API_STRIPE_SECRET
AUTH_
认证相关仅服务端
AUTH_SECRET
,
AUTH_GOOGLE_ID
SMTP_
邮件服务仅服务端
SMTP_HOST
,
SMTP_PASSWORD
STORAGE_
文件存储仅服务端
STORAGE_S3_BUCKET
⚠️ 安全原则
- 仅允许NEXT_PUBLIC_*开头的变量暴露给客户端
- API密钥与密码必须设为仅服务端变量
- 切勿在.env文件中提交敏感信息

.env File Structure

.env文件结构

Project Root/
├── .env.example        # Template (in Git, values empty)
├── .env.local          # Local development (Git ignored)
├── .env.development    # Development env defaults
├── .env.staging        # Staging env defaults
├── .env.production     # Production defaults (no sensitive info)
└── .env.test           # Test environment
Project Root/
├── .env.example        # 模板文件(纳入Git,值为空)
├── .env.local          # 本地开发配置(Git忽略)
├── .env.development    # 开发环境默认配置
├── .env.staging        # 预发布环境默认配置
├── .env.production     # 生产环境默认配置(不含敏感信息)
└── .env.test           # 测试环境配置

.env.example Template

.env.example模板

bash
undefined
bash
undefined

.env.example - This file is included in Git

.env.example - 该文件需纳入Git

Set actual values in .env.local

在.env.local中设置实际值

===== App Settings =====

===== 应用设置 =====

NODE_ENV=development NEXT_PUBLIC_APP_URL=http://localhost:3000
NODE_ENV=development NEXT_PUBLIC_APP_URL=http://localhost:3000

===== Database =====

===== 数据库 =====

DB_HOST= DB_PORT=5432 DB_NAME= DB_USER= DB_PASSWORD=
DB_HOST= DB_PORT=5432 DB_NAME= DB_USER= DB_PASSWORD=

===== Authentication =====

===== 认证配置 =====

AUTH_SECRET= # openssl rand -base64 32 AUTH_GOOGLE_ID= AUTH_GOOGLE_SECRET=
AUTH_SECRET= # 生成方式:openssl rand -base64 32 AUTH_GOOGLE_ID= AUTH_GOOGLE_SECRET=

===== External Services =====

===== 外部服务 =====

NEXT_PUBLIC_API_URL= API_STRIPE_SECRET= SMTP_HOST= SMTP_USER= SMTP_PASSWORD=
undefined
NEXT_PUBLIC_API_URL= API_STRIPE_SECRET= SMTP_HOST= SMTP_USER= SMTP_PASSWORD=
undefined

Environment-wise Value Classification

分环境值分类

Variable Type.env.example.env.localCI/CD Secrets
App URLTemplateLocal valuePer-env value
API endpointsTemplateLocal/devPer-env value
DB passwordEmptyLocal value✅ Secrets
API keysEmptyTest key✅ Secrets
JWT SecretEmptyLocal value✅ Secrets
变量类型.env.example.env.localCI/CD Secrets
应用URL模板值本地值分环境配置值
API端点模板值本地/开发值分环境配置值
数据库密码空值本地值✅ 存储在Secrets中
API密钥空值测试密钥✅ 存储在Secrets中
JWT密钥空值本地值✅ 存储在Secrets中

Environment Variable Validation

环境变量验证

typescript
// lib/env.ts - Validate env vars at app startup
import { z } from 'zod';

const envSchema = z.object({
  // Required
  DATABASE_URL: z.string().url(),
  AUTH_SECRET: z.string().min(32),

  // Optional (with defaults)
  NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),

  // Client-exposed
  NEXT_PUBLIC_APP_URL: z.string().url(),
});

// Validation and type inference
export const env = envSchema.parse(process.env);

// Type-safe usage
// env.DATABASE_URL  ← autocomplete supported
typescript
// lib/env.ts - 应用启动时验证环境变量
import { z } from 'zod';

const envSchema = z.object({
  // 必填项
  DATABASE_URL: z.string().url(),
  AUTH_SECRET: z.string().min(32),

  // 可选项(含默认值)
  NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),

  // 客户端可访问项
  NEXT_PUBLIC_APP_URL: z.string().url(),
});

// 验证并推导类型
export const env = envSchema.parse(process.env);

// 类型安全使用
// env.DATABASE_URL  ← 支持自动补全

Environment Variable Checklist

环境变量检查清单

  • Naming Consistency
    • Follow prefix rules (NEXT_PUBLIC_, DB_, API_, etc.)
    • Use UPPER_SNAKE_CASE
  • File Structure
    • Create .env.example (template)
    • Register .env.local in .gitignore
    • Separate .env files per environment
  • Security
    • Classify sensitive info
    • Verify client-exposed variables
    • Organize Secrets list (for Phase 9 deployment)

  • 命名一致性
    • 遵循前缀规则(NEXT_PUBLIC_、DB_、API_等)
    • 使用UPPER_SNAKE_CASE格式
  • 文件结构
    • 创建.env.example模板文件
    • 在.gitignore中注册.env.local
    • 按环境拆分.env文件
  • 安全性
    • 对敏感信息进行分类
    • 验证客户端可访问变量
    • 整理Secrets清单(用于第九阶段部署)

Clean Architecture Principles

整洁架构原则

Why Define at Design Stage?

为何在设计阶段定义?

Clean Architecture = Code resilient to change

❌ Developing without architecture
   → Spaghetti code, multiple file changes for each modification

✅ Define layers at design stage
   → Separation of concerns, easy testing, easy maintenance
整洁架构 = 具备变更韧性的代码

❌ 无架构指导下开发
   → 面条代码、每次修改需改动多个文件

✅ 在设计阶段定义分层结构
   → 关注点分离、易于测试、便于维护

4-Layer Architecture (Recommended)

推荐4层架构

src/
├── presentation/        # or app/, pages/
│   ├── components/      # UI components
│   ├── hooks/           # State management hooks
│   └── pages/           # Page components
├── application/         # or services/, features/
│   ├── use-cases/       # Business use cases
│   └── services/        # API service wrappers
├── domain/              # or types/, entities/
│   ├── entities/        # Domain entities
│   ├── types/           # Type definitions
│   └── constants/       # Domain constants
└── infrastructure/      # or lib/, api/
    ├── api/             # API clients
    ├── db/              # Database connections
    └── external/        # External services
src/
├── presentation/        # 或命名为app/、pages/
│   ├── components/      # UI组件
│   ├── hooks/           # 状态管理hooks
│   └── pages/           # 页面组件
├── application/         # 或命名为services/、features/
│   ├── use-cases/       # 业务用例
│   └── services/        # API服务封装
├── domain/              # 或命名为types/、entities/
│   ├── entities/        # 领域实体
│   ├── types/           # 类型定义
│   └── constants/       # 领域常量
└── infrastructure/      # 或命名为lib/、api/
    ├── api/             # API客户端
    ├── db/              # 数据库连接
    └── external/        # 外部服务集成

Layer Responsibilities and Rules

分层职责与规则

LayerResponsibilityCan Depend OnCannot Depend On
PresentationUI rendering, user eventsApplication, DomainInfrastructure directly
ApplicationBusiness logic orchestrationDomain, InfrastructurePresentation
DomainCore business rules, typesNothing (independent)All external layers
InfrastructureExternal system connectionsDomainApplication, Presentation
层级职责可依赖层级不可依赖层级
Presentation(表现层)UI渲染、用户事件处理Application、Domain直接依赖Infrastructure
Application(应用层)业务逻辑编排Domain、InfrastructurePresentation
Domain(领域层)核心业务规则、类型定义无(独立存在)所有外部层级
Infrastructure(基础设施层)外部系统连接DomainApplication、Presentation

Dependency Rule

依赖规则

typescript
// ❌ Bad: Presentation directly calls Infrastructure
// components/UserList.tsx
import { apiClient } from '@/lib/api/client';  // Direct import forbidden!

export function UserList() {
  const users = apiClient.get('/users');  // ❌
}

// ✅ Good: Presentation → Application → Infrastructure
// hooks/useUsers.ts
import { userService } from '@/services/user.service';

export function useUsers() {
  return useQuery({
    queryKey: ['users'],
    queryFn: userService.getList,  // ✅ Call through Service
  });
}

// components/UserList.tsx
import { useUsers } from '@/hooks/useUsers';

export function UserList() {
  const { data: users } = useUsers();  // ✅ Call through Hook
}
typescript
// ❌ 错误示例:表现层直接调用基础设施层
// components/UserList.tsx
import { apiClient } from '@/lib/api/client';  // 禁止直接导入!

export function UserList() {
  const users = apiClient.get('/users');  // ❌
}

// ✅ 正确示例:表现层 → 应用层 → 基础设施层
// hooks/useUsers.ts
import { userService } from '@/services/user.service';

export function useUsers() {
  return useQuery({
    queryKey: ['users'],
    queryFn: userService.getList,  // ✅ 通过Service调用
  });
}

// components/UserList.tsx
import { useUsers } from '@/hooks/useUsers';

export function UserList() {
  const { data: users } = useUsers();  // ✅ 通过Hook调用
}

File Import Rules

文件导入规则

typescript
// ===== Allowed import directions =====

// In presentation/:
import { User } from '@/domain/types';           // ✅ Domain OK
import { useUsers } from '@/hooks/useUsers';     // ✅ Same layer OK
import { userService } from '@/services/user';   // ✅ Application OK

// In application/:
import { User } from '@/domain/types';           // ✅ Domain OK
import { apiClient } from '@/lib/api/client';    // ✅ Infrastructure OK

// In domain/:
// Minimize external imports (pure types/logic only)

// In infrastructure/:
import { User } from '@/domain/types';           // ✅ Domain OK

// ===== Forbidden imports =====

// In domain/:
import { apiClient } from '@/lib/api/client';    // ❌ Infrastructure forbidden
import { Button } from '@/components/ui/button'; // ❌ Presentation forbidden

// In infrastructure/:
import { useUsers } from '@/hooks/useUsers';     // ❌ Presentation forbidden
typescript
// ===== 允许的导入方向 =====

// 在presentation/中:
import { User } from '@/domain/types';           // ✅ 可导入Domain层
import { useUsers } from '@/hooks/useUsers';     // ✅ 可导入同层级文件
import { userService } from '@/services/user';   // ✅ 可导入Application层

// 在application/中:
import { User } from '@/domain/types';           // ✅ 可导入Domain层
import { apiClient } from '@/lib/api/client';    // ✅ 可导入Infrastructure层

// 在domain/中:
// 尽量减少外部导入(仅保留纯类型/逻辑)

// 在infrastructure/中:
import { User } from '@/domain/types';           // ✅ 可导入Domain层

// ===== 禁止的导入方向 =====

// 在domain/中:
import { apiClient } from '@/lib/api/client';    // ❌ 禁止导入Infrastructure层
import { Button } from '@/components/ui/button'; // ❌ 禁止导入Presentation层

// 在infrastructure/中:
import { useUsers } from '@/hooks/useUsers';     // ❌ 禁止导入Presentation层

Level-wise Application

分级别应用

LevelArchitecture Application
StarterSimple structure (components, lib)
Dynamic3-4 layer separation (recommended structure)
EnterpriseStrict layer separation + DI container
级别架构应用程度
Starter简单结构(components、lib)
Dynamic3-4层分离(推荐结构)
Enterprise严格分层 + 依赖注入容器

Starter Level Folder Structure

Starter级别文件夹结构

src/
├── components/     # UI components
├── lib/            # Utilities, API
└── types/          # Type definitions
src/
├── components/     # UI组件
├── lib/            # 工具函数、API集成
└── types/          # 类型定义

Dynamic Level Folder Structure

Dynamic级别文件夹结构

src/
├── components/     # Presentation
│   └── ui/
├── features/       # Feature modules (Application + Presentation)
│   ├── auth/
│   └── product/
├── hooks/          # Presentation (state management)
├── services/       # Application
├── types/          # Domain
└── lib/            # Infrastructure
    └── api/
src/
├── components/     # 表现层
│   └── ui/
├── features/       # 功能模块(应用层 + 表现层)
│   ├── auth/
│   └── product/
├── hooks/          # 表现层(状态管理)
├── services/       # 应用层
├── types/          # 领域层
└── lib/            # 基础设施层
    └── api/

Enterprise Level Folder Structure

Enterprise级别文件夹结构

src/
├── presentation/
│   ├── components/
│   ├── hooks/
│   └── pages/
├── application/
│   ├── use-cases/
│   └── services/
├── domain/
│   ├── entities/
│   └── types/
└── infrastructure/
    ├── api/
    └── db/

src/
├── presentation/
│   ├── components/
│   ├── hooks/
│   └── pages/
├── application/
│   ├── use-cases/
│   └── services/
├── domain/
│   ├── entities/
│   └── types/
└── infrastructure/
    ├── api/
    └── db/

Phase Connection

阶段关联

Conventions defined in this Phase are verified in later Phases:
Definition (Phase 2)Verification (Phase 8)
Naming rulesNaming consistency check
Folder structureStructure consistency check
Environment variable conventionEnv var naming check
Clean architecture principlesDependency direction check

本阶段定义的规范将在后续阶段进行验证:
定义阶段(第二阶段)验证阶段(第八阶段)
命名规则命名一致性检查
文件夹结构结构一致性检查
环境变量规范环境变量命名检查
整洁架构原则依赖方向检查

Template

模板

See
templates/pipeline/phase-2-convention.template.md
详见
templates/pipeline/phase-2-convention.template.md

Next Phase

下一阶段

Phase 3: Mockup Development → Rules are set, now rapid prototyping

第三阶段:Mockup开发 → 规则已确立,进入快速原型开发阶段

6. Reusability Principles

6. 可复用性原则

6.1 Function Design

6.1 函数设计

Creating Generic Functions

通用函数创建

typescript
// ❌ Handles only specific case
function formatUserName(user: User) {
  return `${user.firstName} ${user.lastName}`
}

// ✅ Generic
function formatFullName(firstName: string, lastName: string) {
  return `${firstName} ${lastName}`
}

// Usage
formatFullName(user.firstName, user.lastName)
formatFullName(author.first, author.last)
typescript
// ❌ 仅处理特定场景
function formatUserName(user: User) {
  return `${user.firstName} ${user.lastName}`
}

// ✅ 通用型函数
function formatFullName(firstName: string, lastName: string) {
  return `${firstName} ${lastName}`
}

// 使用示例
formatFullName(user.firstName, user.lastName)
formatFullName(author.first, author.last)

Parameter Generalization

参数通用化

typescript
// ❌ Tied to specific type
function calculateOrderTotal(order: Order) {
  return order.items.reduce((sum, item) => sum + item.price, 0)
}

// ✅ Generalized with interface
interface HasPrice { price: number }
function calculateTotal<T extends HasPrice>(items: T[]) {
  return items.reduce((sum, item) => sum + item.price, 0)
}

// Can be used in various places
calculateTotal(order.items)
calculateTotal(cart.products)
calculateTotal(invoice.lineItems)
typescript
// ❌ 绑定特定类型
function calculateOrderTotal(order: Order) {
  return order.items.reduce((sum, item) => sum + item.price, 0)
}

// ✅ 通过接口实现通用化
interface HasPrice { price: number }
function calculateTotal<T extends HasPrice>(items: T[]) {
  return items.reduce((sum, item) => sum + item.price, 0)
}

// 可在多场景使用
calculateTotal(order.items)
calculateTotal(cart.products)
calculateTotal(invoice.lineItems)

6.2 Component Design

6.2 组件设计

Composable Components

可组合组件

tsx
// ❌ Hardcoded structure
function UserCard({ user }: { user: User }) {
  return (
    <div className="card">
      <img src={user.avatar} />
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  )
}

// ✅ Composable
function Card({ children, className }: CardProps) {
  return <div className={cn("card", className)}>{children}</div>
}

function Avatar({ src, alt }: AvatarProps) {
  return <img src={src} alt={alt} className="avatar" />
}

// Use by combining
<Card>
  <Avatar src={user.avatar} alt={user.name} />
  <h3>{user.name}</h3>
  <p>{user.email}</p>
</Card>
tsx
// ❌ 结构硬编码
function UserCard({ user }: { user: User }) {
  return (
    <div className="card">
      <img src={user.avatar} />
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  )
}

// ✅ 可组合型组件
function Card({ children, className }: CardProps) {
  return <div className={cn("card", className)}>{children}</div>
}

function Avatar({ src, alt }: AvatarProps) {
  return <img src={src} alt={alt} className="avatar" />
}

// 组合使用示例
<Card>
  <Avatar src={user.avatar} alt={user.name} />
  <h3>{user.name}</h3>
  <p>{user.email}</p>
</Card>

Props Extensibility

属性扩展性

tsx
// ❌ Limited props
interface ButtonProps {
  label: string
  onClick: () => void
}

// ✅ Extend HTML attributes
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'default' | 'outline' | 'ghost'
  size?: 'sm' | 'md' | 'lg'
}

// All button attributes available
<Button type="submit" disabled={isLoading}>
  Save
</Button>
tsx
// ❌ 属性有限
interface ButtonProps {
  label: string
  onClick: () => void
}

// ✅ 扩展HTML属性
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'default' | 'outline' | 'ghost'
  size?: 'sm' | 'md' | 'lg'
}

// 支持所有原生button属性
<Button type="submit" disabled={isLoading}>
  Save
</Button>

6.3 Extraction Criteria

6.3 提取标准

When to Extract as Function

何时提取为函数

1. Same logic used 2+ times
2. Logic is complex enough to need a name
3. Logic that needs testing
4. Can be used in other files
1. 相同逻辑被使用2次及以上
2. 逻辑复杂度高,需通过命名提升可读性
3. 逻辑需要单独测试
4. 可被其他文件复用

When to Extract as Component

何时提取为组件

1. Same UI pattern repeats
2. Has independent state
3. Is a reusable unit
4. JSX over 50 lines

1. 相同UI模式重复出现
2. 具备独立状态
3. 是可复用的独立单元
4. JSX代码超过50行

7. Extensibility Principles

7. 可扩展性原则

7.1 Configuration-Based Design

7.1 基于配置的设计

typescript
// ❌ Listing conditionals
function getStatusColor(status: string) {
  if (status === 'active') return 'green'
  if (status === 'pending') return 'yellow'
  if (status === 'error') return 'red'
  return 'gray'
}

// ✅ Configuration object
const STATUS_CONFIG = {
  active: { color: 'green', label: 'Active' },
  pending: { color: 'yellow', label: 'Pending' },
  error: { color: 'red', label: 'Error' },
} as const

function getStatusConfig(status: keyof typeof STATUS_CONFIG) {
  return STATUS_CONFIG[status] ?? { color: 'gray', label: status }
}

// Adding new status = just add config
typescript
// ❌ 条件判断罗列
function getStatusColor(status: string) {
  if (status === 'active') return 'green'
  if (status === 'pending') return 'yellow'
  if (status === 'error') return 'red'
  return 'gray'
}

// ✅ 配置对象模式
const STATUS_CONFIG = {
  active: { color: 'green', label: 'Active' },
  pending: { color: 'yellow', label: 'Pending' },
  error: { color: 'red', label: 'Error' },
} as const

function getStatusConfig(status: keyof typeof STATUS_CONFIG) {
  return STATUS_CONFIG[status] ?? { color: 'gray', label: status }
}

// 添加新状态只需修改配置

7.2 Strategy Pattern

7.2 策略模式

typescript
// ❌ Listing switch statements
function processPayment(method: string, amount: number) {
  switch (method) {
    case 'card':
      // Card payment logic
      break
    case 'bank':
      // Bank transfer logic
      break
  }
}

// ✅ Strategy pattern
interface PaymentStrategy {
  process(amount: number): Promise<Result>
}

const paymentStrategies: Record<string, PaymentStrategy> = {
  card: new CardPayment(),
  bank: new BankTransfer(),
}

function processPayment(method: string, amount: number) {
  const strategy = paymentStrategies[method]
  if (!strategy) throw new Error(`Unknown method: ${method}`)
  return strategy.process(amount)
}

// Adding new payment method = just add strategy
typescript
// ❌ switch语句罗列
function processPayment(method: string, amount: number) {
  switch (method) {
    case 'card':
      // 银行卡支付逻辑
      break
    case 'bank':
      // 银行转账逻辑
      break
  }
}

// ✅ 策略模式
interface PaymentStrategy {
  process(amount: number): Promise<Result>
}

const paymentStrategies: Record<string, PaymentStrategy> = {
  card: new CardPayment(),
  bank: new BankTransfer(),
}

function processPayment(method: string, amount: number) {
  const strategy = paymentStrategies[method]
  if (!strategy) throw new Error(`Unknown method: ${method}`)
  return strategy.process(amount)
}

// 添加新支付方式只需新增策略

7.3 Plugin Structure

7.3 插件化结构

typescript
// Extensible system
interface Plugin {
  name: string
  init(): void
  execute(data: unknown): unknown
}

class PluginManager {
  private plugins: Plugin[] = []

  register(plugin: Plugin) {
    this.plugins.push(plugin)
  }

  executeAll(data: unknown) {
    return this.plugins.reduce(
      (result, plugin) => plugin.execute(result),
      data
    )
  }
}

// New feature = add plugin

typescript
// 可扩展系统
interface Plugin {
  name: string
  init(): void
  execute(data: unknown): unknown
}

class PluginManager {
  private plugins: Plugin[] = []

  register(plugin: Plugin) {
    this.plugins.push(plugin)
  }

  executeAll(data: unknown) {
    return this.plugins.reduce(
      (result, plugin) => plugin.execute(result),
      data
    )
  }
}

// 新增功能只需添加插件

8. Duplication Prevention Checklist

8. 重复代码预防检查清单

Before Writing Code

编写代码前

  • Is there a similar function in utils/?
  • Is there a similar component in components/?
  • Is there a similar hook in hooks/?
  • Did you search the entire project?
  • utils/中是否有类似函数?
  • components/中是否有类似组件?
  • hooks/中是否有类似hook?
  • 是否搜索过整个项目?

After Writing Code

编写代码后

  • Is the same code in 2+ places? → Extract
  • Can this code be used elsewhere? → Move
  • Are there hardcoded values? → Make constants
  • Is it tied to a specific type? → Generalize
  • 相同代码是否出现在2个及以上位置?→ 提取为公共代码
  • 这段代码是否可被其他场景复用?→ 迁移到公共目录
  • 是否存在硬编码值?→ 改为常量
  • 是否绑定特定类型?→ 通用化改造