phase-2-convention
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePhase 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
本阶段需完成事项
- Naming Rules: Variables, functions, files, folder names
- Code Style: Indentation, quotes, semicolons, etc.
- Structure Rules: Folder structure, file separation criteria
- Pattern Definition: Frequently used code patterns
- 命名规则:变量、函数、文件、文件夹命名
- 代码风格:缩进、引号、分号等
- 结构规则:文件夹结构、文件拆分标准
- 模式定义:常用代码模式
Deliverables
交付物
Project Root/
├── CONVENTIONS.md # Full conventions
└── docs/01-plan/
├── naming.md # Naming rules
└── structure.md # Structure rulesProject 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
分级别应用
| Level | Application Level |
|---|---|
| Starter | Basic (essential rules only) |
| Dynamic | Extended (including API, state management) |
| Enterprise | Extended (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 definitionssrc/
├── 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
环境变量命名规则
| Prefix | Purpose | Exposure Scope | Example |
|---|---|---|---|
| Client-exposed | Browser | |
| Database | Server only | |
| External API keys | Server only | |
| Authentication | Server only | |
| Email service | Server only | |
| File storage | Server only | |
⚠️ 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| 前缀 | 用途 | 暴露范围 | 示例 |
|---|---|---|---|
| 客户端可访问 | 浏览器 | |
| 数据库相关 | 仅服务端 | |
| 外部API密钥 | 仅服务端 | |
| 认证相关 | 仅服务端 | |
| 邮件服务 | 仅服务端 | |
| 文件存储 | 仅服务端 | |
⚠️ 安全原则
- 仅允许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 environmentProject Root/
├── .env.example # 模板文件(纳入Git,值为空)
├── .env.local # 本地开发配置(Git忽略)
├── .env.development # 开发环境默认配置
├── .env.staging # 预发布环境默认配置
├── .env.production # 生产环境默认配置(不含敏感信息)
└── .env.test # 测试环境配置.env.example Template
.env.example模板
bash
undefinedbash
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=
undefinedNEXT_PUBLIC_API_URL=
API_STRIPE_SECRET=
SMTP_HOST=
SMTP_USER=
SMTP_PASSWORD=
undefinedEnvironment-wise Value Classification
分环境值分类
| Variable Type | .env.example | .env.local | CI/CD Secrets |
|---|---|---|---|
| App URL | Template | Local value | Per-env value |
| API endpoints | Template | Local/dev | Per-env value |
| DB password | Empty | Local value | ✅ Secrets |
| API keys | Empty | Test key | ✅ Secrets |
| JWT Secret | Empty | Local value | ✅ Secrets |
| 变量类型 | .env.example | .env.local | CI/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 supportedtypescript
// 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 servicessrc/
├── 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
分层职责与规则
| Layer | Responsibility | Can Depend On | Cannot Depend On |
|---|---|---|---|
| Presentation | UI rendering, user events | Application, Domain | Infrastructure directly |
| Application | Business logic orchestration | Domain, Infrastructure | Presentation |
| Domain | Core business rules, types | Nothing (independent) | All external layers |
| Infrastructure | External system connections | Domain | Application, Presentation |
| 层级 | 职责 | 可依赖层级 | 不可依赖层级 |
|---|---|---|---|
| Presentation(表现层) | UI渲染、用户事件处理 | Application、Domain | 直接依赖Infrastructure |
| Application(应用层) | 业务逻辑编排 | Domain、Infrastructure | Presentation |
| Domain(领域层) | 核心业务规则、类型定义 | 无(独立存在) | 所有外部层级 |
| Infrastructure(基础设施层) | 外部系统连接 | Domain | Application、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 forbiddentypescript
// ===== 允许的导入方向 =====
// 在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
分级别应用
| Level | Architecture Application |
|---|---|
| Starter | Simple structure (components, lib) |
| Dynamic | 3-4 layer separation (recommended structure) |
| Enterprise | Strict layer separation + DI container |
| 级别 | 架构应用程度 |
|---|---|
| Starter | 简单结构(components、lib) |
| Dynamic | 3-4层分离(推荐结构) |
| Enterprise | 严格分层 + 依赖注入容器 |
Starter Level Folder Structure
Starter级别文件夹结构
src/
├── components/ # UI components
├── lib/ # Utilities, API
└── types/ # Type definitionssrc/
├── 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 rules | Naming consistency check |
| Folder structure | Structure consistency check |
| Environment variable convention | Env var naming check |
| Clean architecture principles | Dependency direction check |
本阶段定义的规范将在后续阶段进行验证:
| 定义阶段(第二阶段) | 验证阶段(第八阶段) |
|---|---|
| 命名规则 | 命名一致性检查 |
| 文件夹结构 | 结构一致性检查 |
| 环境变量规范 | 环境变量命名检查 |
| 整洁架构原则 | 依赖方向检查 |
Template
模板
See
templates/pipeline/phase-2-convention.template.md详见
templates/pipeline/phase-2-convention.template.mdNext 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 files1. 相同逻辑被使用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 lines1. 相同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 configtypescript
// ❌ 条件判断罗列
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 strategytypescript
// ❌ 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 plugintypescript
// 可扩展系统
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个及以上位置?→ 提取为公共代码
- 这段代码是否可被其他场景复用?→ 迁移到公共目录
- 是否存在硬编码值?→ 改为常量
- 是否绑定特定类型?→ 通用化改造