附录

附录 B 软件开发基础知识 Wiki

本节最后更新:2026-05-11
验证环境:无(参考章节)

本节是为 Vibe Coding 读者准备的"最小必要知识"——不是大学计算机课程的精简版,而是你一个人做软件时需要知道的核心概念。

B.1 计算机工作原理地图

从你写代码到程序运行,经过以下层次:

你写的代码(高级语言)
    ↓
编译/解释(变成机器指令)
    ↓
操作系统(管理资源分配)
    ↓
硬件(CPU → 内存 → 存储)

B.1.1 CPU(中央处理器)

电脑的"大脑",执行指令。速度极快(每秒几十亿次运算),但一次只能做一件事。多任务是通过快速切换实现的。

核心概念:

B.1.2 内存(RAM)

短期记忆。程序和正在处理的数据放在这里。速度快,断电即消失。容量通常 8GB~32GB。

核心概念:

B.1.3 存储(硬盘/SSD)

长期记忆。文件、安装的程序、操作系统放在这里。速度比内存慢 10~100 倍,但断电后数据不丢失。

核心概念:

B.1.4 I/O(输入/输出)

与外部世界的交互——键盘、鼠标、屏幕、网络、磁盘读写。

核心概念:

B.1.5 理解这些有什么实际用处

B.2 操作系统核心概念

B.2.1 文件系统

文件在硬盘上的组织方式。路径有绝对路径(/home/user/project/)和相对路径(./src/index.js)。

常见文件系统:

文件系统特点适用系统
NTFS支持大文件、权限管理Windows
FAT32兼容性好,单个文件最大 4GBU盘、移动硬盘
ext4高性能、可靠性高Linux
APFS苹果文件系统,支持加密macOS

路径类型:

B.2.2 进程与线程

进程:正在运行的程序实例。每个进程有独立的内存空间。进程之间默认不共享数据。

线程:进程内的执行单元。同一进程内的线程共享进程的内存空间,但有独立的执行栈。

关键区别:

特性进程线程
内存空间独立共享
创建开销
通信方式IPC(进程间通信)直接共享内存
隔离性

进程状态:

B.2.3 环境变量

操作系统级别的配置键值对。用于存储不随代码变化的配置:

# 设置(当前终端)
export DATABASE_URL="postgresql://localhost:5432/mydb"
export ANTHROPIC_API_KEY="sk-ant-xxx"

# 查看
echo $DATABASE_URL

# 查看所有环境变量
env

# 写入文件(持久化)
# Linux/macOS:添加到 ~/.bashrc 或 ~/.zshrc
# Windows:系统属性 -> 环境变量

为什么环境变量重要:

B.2.4 标准流

每个进程有三个默认通道:

名称用途文件描述符
stdin标准输入键盘输入0
stdout标准输出正常输出(屏幕)1
stderr标准错误错误信息2

重定向:

# 将 stdout 重定向到文件(覆盖)
node app.js > output.log

# 将 stdout 追加到文件
node app.js >> output.log

# 将 stderr 重定向到文件
node app.js 2> error.log

# 将 stdout 和 stderr 都重定向到同一文件
node app.js > combined.log 2>&1

# 丢弃输出(黑洞)
node app.js > /dev/null 2>&1

B.2.5 退出码

程序正常退出返回 0,出错返回非零值。Shell 脚本中常用 $? 获取上一个命令的退出码。

# 运行命令
node app.js

# 检查退出码
if [ $? -eq 0 ]; then
  echo "成功"
else
  echo "失败"
fi

常见退出码:

退出码含义
0成功
1通用错误
2用法错误
127命令未找到
128无效参数
128+n收到信号 n 而终止

B.2.6 信号处理

操作系统通过信号与进程通信。常见信号:

信号名称含义默认行为
SIGINT (2)中断用户按 Ctrl+C终止
SIGTERM (15)终止请求优雅关闭终止
SIGKILL (9)杀死强制终止(无法捕获)终止
SIGQUIT (3)退出用户按 Ctrl+\终止并转储核心
SIGHUP (1)挂起终端关闭终止
# 发送信号
kill -TERM <PID>    # 优雅终止
kill -KILL <PID>    # 强制终止
kill -INT <PID>     # 模拟 Ctrl+C

# 捕获信号(Node.js 示例)
process.on('SIGTERM', () => {
  console.log('收到 SIGTERM,正在优雅关闭...');
  server.close(() => {
    process.exit(0);
  });
});

B.2.7 进程间通信(IPC)

进程之间交换数据的方式:

方式描述适用场景
管道 (Pipe)单向数据流父子进程通信
命名管道 (FIFO)双向命名管道无亲缘关系进程
信号简单通知事件通知
共享内存内存区域共享高性能数据共享
消息队列消息传递异步通信
Socket网络通信跨机器通信
# 管道示例
ls -la | grep ".txt"  # 将 ls 输出传给 grep

# 命名管道
mkfifo mypipe
cat < mypipe &        # 后台读取
echo "hello" > mypipe # 写入

B.3 网络基础

B.3.1 IP 地址

互联网上的"门牌号"。IPv4 格式如 192.168.1.1,IPv6 格式如 2001:db8::1

IP 地址分类:

NAT(网络地址转换):

B.3.2 DNS(域名系统)

google.com 这样的域名翻译成 IP 地址。类似电话本。

DNS 查询过程:

  1. 浏览器检查本地缓存
  2. 查询本地 DNS 服务器
  3. 递归查询根域名服务器 → 顶级域名服务器 → 权威域名服务器

常见 DNS 记录:

记录类型用途
A域名 → IPv4 地址
AAAA域名 → IPv6 地址
CNAME域名别名
MX邮件服务器
TXT文本记录(常用于验证)
# 查询 DNS 记录
dig google.com
nslookup example.com

# 刷新 DNS 缓存(macOS)
dscacheutil -flushcache

# 刷新 DNS 缓存(Windows)
ipconfig /flushdns

B.3.3 HTTP/HTTPS

浏览器和服务器之间的通信协议。HTTPS = HTTP + 加密(SSL/TLS)。

HTTP 特点:

HTTPS 特点:

TLS 握手过程:

  1. 客户端发送支持的加密套件
  2. 服务器返回证书
  3. 客户端验证证书
  4. 协商对称密钥
  5. 加密通信

B.3.4 常见的 HTTP 方法

方法含义幂等性常用场景
GET获取数据查看资源
POST创建数据提交表单、创建资源
PUT更新数据替换资源
PATCH部分更新更新资源的部分字段
DELETE删除数据删除资源
HEAD获取响应头检查资源是否存在
OPTIONS获取服务器支持的方法CORS 预检请求

幂等性:多次调用产生相同的效果

B.3.5 HTTP 状态码

状态码类别含义
1xx信息性请求已接收,继续处理
2xx成功请求成功处理
3xx重定向需要进一步操作
4xx客户端错误请求有问题
5xx服务器错误服务器处理失败

常见状态码:

状态码含义
200OK(成功)
201Created(创建成功)
204No Content(无内容)
301Moved Permanently(永久重定向)
302Found(临时重定向)
400Bad Request(请求错误)
401Unauthorized(未授权)
403Forbidden(禁止访问)
404Not Found(未找到)
500Internal Server Error(服务器错误)
503Service Unavailable(服务不可用)

B.3.6 端口

一台服务器上可以运行多个网络服务,通过端口号区分。端口范围:0~65535。

知名端口(0~1023):

端口服务
21FTP
22SSH
25SMTP
53DNS
80HTTP
443HTTPS
3306MySQL
5432PostgreSQL

注册端口(1024~49151):

端口服务
3000Next.js / React 开发服务器
5000Flask / FastAPI 开发服务器
8080HTTP 替代端口
8000Django 开发服务器

动态端口(49152~65535):

B.3.7 WebSocket

HTTP 只能由"客户端请求、服务器响应"。WebSocket 允许服务器主动向客户端推送数据——适合聊天、实时通知、实时数据更新。

WebSocket 特点:

WebSocket 握手:

客户端 → 服务器:HTTP 请求(包含 Upgrade: websocket)
服务器 → 客户端:101 Switching Protocols

适用场景:

B.3.8 TCP/IP 协议栈

网络通信的层次模型:

层次协议功能
应用层HTTP, HTTPS, FTP, DNS用户交互
传输层TCP, UDP端到端通信
网络层IP, ICMP, ARP路由和寻址
链路层Ethernet, Wi-Fi物理介质传输

TCP 三次握手:

客户端 → 服务器:SYN(请求建立连接)
服务器 → 客户端:SYN + ACK(确认收到,同意建立)
客户端 → 服务器:ACK(确认,连接建立)

TCP 四次挥手:

客户端 → 服务器:FIN(请求关闭)
服务器 → 客户端:ACK(确认收到)
服务器 → 客户端:FIN(准备关闭)
客户端 → 服务器:ACK(确认,连接关闭)

UDP vs TCP:

特性TCPUDP
可靠性可靠(重传机制)不可靠
连接面向连接无连接
速度较慢较快
适用场景文件传输、网页、API视频通话、游戏、流媒体

B.3.9 CDN(内容分发网络)

将静态资源分发到全球边缘节点,降低延迟。

CDN 工作原理:

  1. 用户请求资源
  2. DNS 解析到最近的边缘节点
  3. 边缘节点返回缓存的资源
  4. 若未缓存,向源站请求并缓存

CDN 配置示例:

// Cloudflare CDN 配置(next.config.js)
module.exports = {
  images: {
    domains: ['example.com'],
    loader: 'cloudflare',
    path: '/cdn-cgi/image/',
  },
};

B.4 数据格式

B.4.1 JSON

Web 应用中最通用的数据格式。

{
  "name": "Alice",
  "age": 30,
  "isActive": true,
  "skills": ["JavaScript", "Python"],
  "address": {
    "city": "Beijing",
    "zip": "100000"
  },
  "tags": null
}

JSON 语法规则:

JSON 与 JavaScript 对象的区别:

JSON 操作(JavaScript):

// 对象 → JSON 字符串
const data = { name: "Alice", age: 30 };
const jsonStr = JSON.stringify(data);

// JSON 字符串 → 对象
const parsed = JSON.parse(jsonStr);

// 格式化输出
const pretty = JSON.stringify(data, null, 2);

JSON 操作(Python):

import json

# 对象 → JSON 字符串
data = {"name": "Alice", "age": 30}
json_str = json.dumps(data, indent=2)

# JSON 字符串 → 对象
parsed = json.loads(json_str)

# 读取文件
with open("data.json", "r") as f:
    data = json.load(f)

# 写入文件
with open("data.json", "w") as f:
    json.dump(data, f, indent=2)

B.4.2 YAML

比 JSON"更可读"的配置格式。用缩进表示层级,支持注释。

# 配置示例
server:
  host: "0.0.0.0"
  port: 3000
  timeout: 30
  debug: false

database:
  url: "postgresql://localhost:5432/mydb"
  username: "admin"
  password: "secret"
  options:
    pool_size: 20
    max_overflow: 5

logging:
  level: "info"
  format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  handlers:
    - console
    - file

features:
  enable_notifications: true
  enable_analytics: false
  api_keys:
    - "key1"
    - "key2"
    - "key3"

YAML 语法规则:

YAML 数据类型:

# 字符串
name: "Alice"
name2: Alice  # 简单字符串可以不加引号

# 数字
count: 42
price: 3.14
big_number: 1e10

# 布尔值
is_active: true
is_deleted: false

# 空值
empty: null
empty2: ~

# 日期时间
date: 2024-01-15
datetime: 2024-01-15T10:30:00Z

# 列表
fruits:
  - apple
  - banana
  - cherry

# 嵌套对象
user:
  name: "Alice"
  age: 30
  address:
    city: "Beijing"

B.4.3 Markdown

本书使用的格式。简单的标记语法:

# 一级标题
## 二级标题
### 三级标题

**粗体文本**
*斜体文本*
~~删除线~~

- 无序列表项 1
- 无序列表项 2
  - 嵌套列表项
  - 嵌套列表项

1. 有序列表项 1
2. 有序列表项 2
3. 有序列表项 3

[链接文本](https://example.com)
![图片替代文本](image.jpg)

> 引用文本
>> 嵌套引用

`行内代码`

// 代码块

function hello() {

console.log("Hello World");

}


| 列1 | 列2 | 列3 |
|-----|-----|-----|
| 值1 | 值2 | 值3 |
| 值4 | 值5 | 值6 |

---

脚注[^1]

[^1]: 这是脚注内容

Markdown 扩展语法(GitHub Flavored Markdown):

- [x] 已完成任务
- [ ] 未完成任务

~~删除线文本~~

| 左对齐 | 居中 | 右对齐 |
|:-------|:----:|-------:|
| 内容 | 内容 | 内容 |

> [!NOTE]
> 注意信息

> [!WARNING]
> 警告信息

\*转义星号\*

B.4.4 CSV(逗号分隔值)

简单的表格数据格式,广泛用于数据交换。

name,age,city,email
Alice,30,Beijing,alice@example.com
Bob,25,Shanghai,bob@example.com
Charlie,35,Guangzhou,charlie@example.com

CSV 语法规则:

CSV 操作(Python):

import csv

# 读取 CSV
with open('data.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['name'], row['age'])

# 写入 CSV
with open('output.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['name', 'age', 'city'])
    writer.writerow(['Alice', 30, 'Beijing'])

B.4.5 XML(可扩展标记语言)

结构化数据格式,曾广泛用于配置和数据交换。

<?xml version="1.0" encoding="UTF-8"?>
<users>
  <user id="1">
    <name>Alice</name>
    <age>30</age>
    <city>Beijing</city>
    <active>true</active>
  </user>
  <user id="2">
    <name>Bob</name>
    <age>25</age>
    <city>Shanghai</city>
    <active>false</active>
  </user>
</users>

XML 与 JSON 对比:

特性XMLJSON
可读性较复杂简洁
大小较大较小
解析速度较慢较快
支持注释
属性支持

B.4.6 Protobuf(Protocol Buffers)

Google 开发的高效序列化格式,适合高性能数据传输。

// user.proto
syntax = "proto3";

message User {
  string name = 1;
  int32 age = 2;
  string city = 3;
  bool is_active = 4;
  repeated string skills = 5;
}

Protobuf 特点:

B.5 安全常识

B.5.1 API 密钥保护

最佳实践:

做法是否推荐说明
❌ 写在代码里会被提交到 Git 仓库
✅ 使用环境变量安全且不进入版本控制
❌ 在聊天或邮件中发送容易泄露
✅ 密钥泄露后立即吊销在服务商控制台操作
❌ 多个服务共用密钥一个泄露全部受影响
✅ 使用 .env 文件确保在 .gitignore
✅ 定期轮换密钥降低泄露风险
❌ 硬编码在客户端代码中可被轻易提取

.gitignore 示例:

# 环境变量文件
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# 日志文件
*.log
npm-debug.log*
yarn-debug.log*

# 依赖目录
node_modules/
__pycache__/

B.5.2 CORS(跨域资源共享)

浏览器安全机制——默认不允许一个域名下的网页访问另一个域名下的 API。

CORS 响应头:

响应头作用
Access-Control-Allow-Origin指定允许的源(* 表示所有)
Access-Control-Allow-Methods指定允许的 HTTP 方法
Access-Control-Allow-Headers指定允许的请求头
Access-Control-Allow-Credentials是否允许携带凭证
Access-Control-Max-Age预检请求的缓存时间

CORS 预检请求(OPTIONS):

常见 CORS 配置(Express.js):

const express = require('express');
const cors = require('cors');

const app = express();

// 允许所有来源(开发环境)
app.use(cors());

// 允许指定来源
app.use(cors({
  origin: 'https://example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true
}));

常见 CORS 配置(FastAPI):

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

B.5.3 XSS(跨站脚本攻击)

攻击者把恶意脚本注入到你的网站中。

XSS 类型:

类型描述
存储型恶意脚本存储在服务器(如评论、帖子)
反射型恶意脚本在 URL 中,服务器直接返回
DOM 型恶意脚本通过客户端 JavaScript 执行

防御方案:

  1. 永远不要直接把用户输入插入到 HTML 中
  2. 使用框架提供的安全机制(React、Vue 等默认转义)
  3. 对用户输入进行验证和清理
  4. 使用 textContent 而非 innerHTML
  5. 配置 CSP(内容安全策略)

CSP 示例:

<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
">

B.5.4 CSRF(跨站请求伪造)

攻击者诱导用户在已登录的状态下执行非本意的操作。

防御方案:

  1. CSRF Token:在表单中加入随机 token
  2. Same-Site Cookie 属性:限制 Cookie 发送范围
  3. 验证 Referer 头:检查请求来源
  4. 双重提交 Cookie:将 CSRF token 放在 Cookie 和请求体中

CSRF Token 示例:

<form action="/submit" method="POST">
  <input type="hidden" name="csrf_token" value="random-token">
  <input type="text" name="content">
  <button type="submit">提交</button>
</form>

B.5.5 SQL 注入

攻击者通过输入恶意 SQL 语句来操作数据库。

危险示例:

// 直接拼接用户输入(危险!)
const username = req.body.username;
const query = `SELECT * FROM users WHERE username = '${username}'`;
// 如果 username 是 ' OR '1'='1,则会变成:
// SELECT * FROM users WHERE username = '' OR '1'='1'
// 这会返回所有用户!

防御方案:

  1. 使用参数化查询(Prepared Statements)
  2. 使用 ORM(如 Prisma、SQLAlchemy)
  3. 对用户输入进行验证
  4. 最小权限原则:数据库用户只授予必要权限

安全示例(参数化查询):

// 使用参数化查询
const username = req.body.username;
const query = 'SELECT * FROM users WHERE username = ?';
db.query(query, [username], (err, results) => {
  // 处理结果
});

B.5.6 HTTPS 强制

生产环境必须使用 HTTPS——浏览器会标记非 HTTPS 网站为"不安全"。

HTTPS 证书获取:

HTTPS 配置:

B.5.7 密码安全

密码存储最佳实践:

密码哈希示例(Node.js):

const bcrypt = require('bcrypt');
const saltRounds = 12;

// 哈希密码
async function hashPassword(password) {
  return bcrypt.hash(password, saltRounds);
}

// 验证密码
async function verifyPassword(password, hash) {
  return bcrypt.compare(password, hash);
}

密码哈希示例(Python):

import bcrypt

# 哈希密码
password = b"my_password"
salt = bcrypt.gensalt()
hashed = bcrypt.hashpw(password, salt)

# 验证密码
bcrypt.checkpw(password, hashed)  # True

密码策略:

规则建议
最小长度12-16 位
复杂度混合大小写、数字、特殊字符
过期时间90-180 天
历史记录禁止使用最近 3-5 个密码
重试限制5 次失败后锁定账户

B.5.8 会话管理

会话安全最佳实践:

措施说明
使用 HttpOnly Cookie防止 XSS 获取会话 ID
使用 Secure Cookie只通过 HTTPS 传输
设置 SameSite 属性防止 CSRF
设置合理过期时间短期会话更安全
定期轮换会话 ID登录成功后重新生成
注销时清除会话服务器端和客户端都清除

Cookie 配置示例:

res.cookie('sessionId', sessionId, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict',
  maxAge: 24 * 60 * 60 * 1000, // 24小时
  path: '/'
});

B.5.9 安全审计清单

检查项说明
输入验证所有用户输入都经过验证和清理
输出编码动态内容正确转义
身份认证使用强密码策略和多因素认证
授权控制最小权限原则,验证权限
敏感数据使用环境变量存储密钥
日志监控记录安全事件,定期审查
依赖检查定期更新依赖,检查漏洞
备份恢复定期备份,测试恢复流程

B.6 软件许可与合规

B.6.1 开源许可证速查

许可证允许商用要求开源说明
MIT最宽松,几乎无限制
Apache 2.0MIT 基础上增加了专利保护
GPL v3使用 GPL 代码的项目必须也使用 GPL
GPL v2比 GPL v3 限制稍宽松
LGPL部分库可以商用,但修改的库代码需开源
BSD 2-Clause简单宽松,保留版权声明
BSD 3-Clause比 2-Clause 多了广告限制
MPL部分Mozilla 公共许可证

许可证选择建议:

B.6.2 AI 生成代码的版权问题

截至 2026 年,各国对 AI 生成内容的版权尚无统一法律定论。实际建议:

使用场景风险评估建议
个人项目基本不需要担心
开源项目在 LICENSE 中说明使用了 AI
商业产品避免直接复制,进行修改
直接复制 GPL 代码有潜在风险
通用代码(CRUD、UI组件)通常不涉及版权问题

最佳实践:

  1. 避免让 AI 重写现有库——这明显是越过许可使用
  2. 对 AI 生成的代码进行审查和修改——加入自己的理解
  3. 保留修改记录——证明是自己的工作
  4. 使用 AI 作为辅助工具——而非直接复制粘贴

B.6.3 隐私合规

GDPR(欧盟通用数据保护条例):

CCPA(加州消费者隐私法案):

数据处理原则:

原则说明
合法、公平、透明处理数据必须合法,用户知情
目的限制只收集实现特定目的所需的数据
数据最小化收集的数据量不超过必要
准确性保持数据准确及时更新
存储限制只在需要的时间内存储
完整性和保密性保护数据安全

隐私政策要点:

B.7 容器与虚拟化

B.7.1 容器基础概念

容器 vs 虚拟机:

特性容器虚拟机
隔离方式操作系统级隔离硬件级隔离
资源开销低(共享内核)高(完整操作系统)
启动速度秒级分钟级
镜像大小小(通常 MB 级)大(通常 GB 级)
移植性较低

容器核心组件:

  1. 容器引擎:负责运行和管理容器(如 Docker Engine)
  2. 容器镜像:只读模板,包含应用程序及其依赖
  3. 容器运行时:执行容器的环境(如 runc)
  4. 容器编排:管理大规模容器部署(如 Kubernetes)

B.7.2 Docker 核心概念

Dockerfile 最佳实践:

# 使用多阶段构建减少镜像大小
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]

Docker 网络模式:

模式描述
bridge默认模式,容器之间通过虚拟网桥通信
host容器共享宿主机网络栈
none容器无网络连接
container:共享另一个容器的网络命名空间

Docker 存储:

类型描述
卷(Volume)持久化存储,由 Docker 管理
绑定挂载(Bind Mount)挂载宿主机文件或目录
tmpfs临时文件系统,容器退出后数据丢失

B.7.3 Kubernetes 基础

核心组件:

组件描述
Pod最小部署单元,可包含一个或多个容器
Service为 Pod 提供稳定的网络访问
Deployment管理 Pod 的部署和更新
ReplicaSet确保指定数量的 Pod 副本运行
ConfigMap存储配置数据
Secret存储敏感数据(base64 编码)
Volume持久化存储

Pod 配置示例:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  containers:
    - name: web
      image: my-app:latest
      ports:
        - containerPort: 3000
      env:
        - name: NODE_ENV
          value: "production"
      resources:
        requests:
          memory: "128Mi"
          cpu: "100m"
        limits:
          memory: "256Mi"
          cpu: "200m"
      volumeMounts:
        - name: data
          mountPath: /app/data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: my-pvc

Service 配置示例:

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000

B.8 CI/CD 基础

B.8.1 CI/CD 概念

CI(持续集成):

CD(持续交付):

CD(持续部署):

B.8.2 GitHub Actions 示例

name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18
      - name: Install dependencies
        run: npm ci
      - name: Run tests
        run: npm test
      - name: Run lint
        run: npm run lint

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: build
          path: dist/
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

B.8.3 GitLab CI 示例

stages:
  - test
  - build
  - deploy

test:
  stage: test
  image: node:18
  script:
    - npm ci
    - npm test
    - npm run lint

build:
  stage: build
  image: node:18
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/

deploy:
  stage: deploy
  image: alpine
  script:
    - apk add --no-cache curl
    - curl -X POST https://api.vercel.com/v1/integrations/deploy/prj_xxx/${{ secrets.VERCEL_TOKEN }}
  only:
    - main

B.9 监控与日志

B.9.1 监控指标

关键指标类型:

类型描述示例
基础设施指标CPU、内存、磁盘、网络CPU 使用率、内存占用
应用指标请求数、响应时间、错误率QPS、P95 响应时间
业务指标用户数、转化率、收入日活用户、订单数

常用监控工具:

工具用途
Prometheus开源监控系统
Grafana可视化仪表盘
Datadog云原生监控
New Relic全栈监控

Prometheus 指标类型:

# Counter - 递增计数器
http_requests_total{method="GET", endpoint="/api/users"} 12345

# Gauge - 瞬时值
cpu_usage{core="0"} 42.5

# Histogram - 直方图
http_request_duration_seconds_bucket{le="0.1"} 100
http_request_duration_seconds_bucket{le="0.5"} 200
http_request_duration_seconds_sum 150.5
http_request_duration_seconds_count 250

# Summary - 摘要
http_request_duration_seconds{quantile="0.5"} 0.2
http_request_duration_seconds{quantile="0.95"} 0.8

B.9.2 日志管理

日志级别:

级别描述使用场景
DEBUG详细调试信息开发阶段调试
INFO一般信息正常运行状态
WARN警告信息潜在问题
ERROR错误信息可恢复的错误
FATAL致命错误程序崩溃

日志最佳实践:

// 结构化日志
const logger = {
  info: (message, context = {}) => {
    console.log(JSON.stringify({
      level: 'INFO',
      timestamp: new Date().toISOString(),
      message,
      ...context
    }));
  },
  error: (message, error, context = {}) => {
    console.error(JSON.stringify({
      level: 'ERROR',
      timestamp: new Date().toISOString(),
      message,
      error: {
        name: error.name,
        message: error.message,
        stack: error.stack
      },
      ...context
    }));
  }
};

// 使用示例
logger.info('User logged in', { userId: 123, ip: '192.168.1.1' });
logger.error('Failed to fetch user', new Error('Network error'), { userId: 123 });

日志收集工具:

工具用途
ELK StackElasticsearch、Logstash、Kibana
LokiGrafana 生态日志系统
Datadog Logs云原生日志管理
Splunk企业级日志分析

B.10 性能优化

B.10.1 前端性能优化

加载优化:

技术描述
代码分割将代码拆分成小块,按需加载
懒加载延迟加载非关键资源
缓存策略使用 HTTP 缓存和 Service Worker
图片优化使用 WebP/AVIF 格式,响应式图片
压缩Gzip/Brotli 压缩

运行时优化:

技术描述
虚拟列表只渲染可见区域
防抖节流减少频繁操作
Web Workers后台处理耗时任务
内存管理及时清理不再使用的引用

代码示例:

// 防抖
function debounce(fn, delay = 300) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

// 节流
function throttle(fn, limit = 100) {
  let inThrottle = false;
  return function(...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
}

// 虚拟列表(简化版)
class VirtualList {
  constructor({ container, itemHeight, totalItems, renderItem }) {
    this.container = container;
    this.itemHeight = itemHeight;
    this.totalItems = totalItems;
    this.renderItem = renderItem;
    this.container.addEventListener('scroll', this.handleScroll.bind(this));
  }
  
  handleScroll() {
    const scrollTop = this.container.scrollTop;
    const startIndex = Math.floor(scrollTop / this.itemHeight);
    const endIndex = Math.min(startIndex + 10, this.totalItems);
    this.renderItems(startIndex, endIndex);
  }
  
  renderItems(start, end) {
    this.container.innerHTML = '';
    for (let i = start; i < end; i++) {
      const item = this.renderItem(i);
      item.style.position = 'absolute';
      item.style.top = `${i * this.itemHeight}px`;
      this.container.appendChild(item);
    }
  }
}

B.10.2 后端性能优化

数据库优化:

技术描述
索引优化在查询条件列创建索引
查询优化使用 JOIN 替代 N+1 查询
缓存使用 Redis 缓存热点数据
读写分离主库写,从库读
分库分表处理大数据量

API 优化:

技术描述
批量请求合并多个请求
分页限制返回数据量
缓存使用 HTTP 缓存头
压缩响应数据压缩

代码示例:

// Redis 缓存示例
const redis = require('redis');
const client = redis.createClient();

async function getUser(id) {
  // 先从缓存获取
  const cached = await client.get(`user:${id}`);
  if (cached) {
    return JSON.parse(cached);
  }
  
  // 从数据库获取
  const user = await db.users.findOne({ id });
  
  // 存入缓存,设置过期时间
  await client.setEx(`user:${id}`, 3600, JSON.stringify(user));
  
  return user;
}

// 批量处理
async function getUsers(ids) {
  // 先获取缓存中的用户
  const cachedUsers = await Promise.all(
    ids.map(id => client.get(`user:${id}`))
  );
  
  // 找出需要从数据库获取的 ID
  const missingIds = ids.filter((_, index) => !cachedUsers[index]);
  
  // 从数据库获取
  const dbUsers = await db.users.find({ id: { $in: missingIds } });
  
  // 合并结果并更新缓存
  const result = {};
  ids.forEach((id, index) => {
    if (cachedUsers[index]) {
      result[id] = JSON.parse(cachedUsers[index]);
    } else {
      const user = dbUsers.find(u => u.id === id);
      result[id] = user;
      client.setEx(`user:${id}`, 3600, JSON.stringify(user));
    }
  });
  
  return result;
}

B.11 操作系统进阶

B.11.1 内存管理深入

内存分页机制:

物理内存被划分为固定大小的页(通常 4KB 或 2MB)
虚拟地址空间同样被划分为页
页表记录虚拟页到物理页的映射

页面置换算法:

算法描述特点
FIFO先进先出简单但可能置换掉常用页面
LRU最近最少使用效果好,实现稍复杂
LFU最不经常使用考虑使用频率
OPT最优置换理论最优,不可实现

内存泄漏检测:

# Linux 内存泄漏检测
valgrind --leak-check=full ./program

# Node.js 内存分析
node --inspect --expose-gc app.js
# 在 Chrome 开发者工具中分析内存快照

# Python 内存分析
import tracemalloc
tracemalloc.start()

# 代码执行
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

print("[ Top 10 memory usage ]")
for stat in top_stats[:10]:
    print(stat)

内存优化策略:

// 对象池模式(减少 GC 压力)
class ObjectPool<T> {
  private pool: T[] = [];
  private factory: () => T;
  
  constructor(factory: () => T) {
    this.factory = factory;
  }
  
  acquire(): T {
    return this.pool.pop() || this.factory();
  }
  
  release(obj: T): void {
    this.pool.push(obj);
  }
}

// 使用对象池
const pool = new ObjectPool(() => ({ x: 0, y: 0 }));
const obj = pool.acquire();
// 使用对象
pool.release(obj);

B.11.2 文件系统深入

文件系统层级:

/ (根目录)
├── bin/        # 系统命令
├── etc/        # 配置文件
├── home/       # 用户目录
├── lib/        # 系统库
├── tmp/        # 临时文件(重启后清空)
├── usr/        # 用户程序
├── var/        # 可变数据(日志、缓存)
└── proc/       # 进程信息(虚拟文件系统)

文件权限详解:

# 权限表示
# r = 4 (读), w = 2 (写), x = 1 (执行)
# 用户 组 其他
# 755 = rwxr-xr-x

# 修改权限
chmod 755 script.sh  # rwxr-xr-x
chmod 644 file.txt   # rw-r--r--
chmod 700 secret/    # rwx------

# 修改所有者
chown user:group file.txt

# 特殊权限
chmod u+s program    # 设置 SUID(以所有者身份运行)
chmod g+s directory  # 设置 SGID(新建文件继承组)
chmod o+t directory  # 设置 sticky bit(只有所有者可删除)

文件系统性能优化:

# 查看磁盘 I/O
iostat -x 1 10

# 查看文件系统挂载信息
df -h

# 挂载优化选项
mount -o noatime,nodiratime /dev/sda1 /mnt/data

# 查看磁盘使用情况(按大小排序)
du -sh * | sort -rh

# 查找大文件
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null

B.11.3 进程调度

调度算法:

算法描述适用场景
FCFS先来先服务简单,适合批处理
SJF短作业优先平均等待时间最短
RR时间片轮转交互式系统
Priority优先级调度实时系统
MLFQ多级反馈队列通用系统

进程状态转换:

新进程 → 就绪队列 → 运行中 ↔ 阻塞(等待I/O) → 终止
                         ↓
                      就绪队列

进程优先级:

# 查看进程优先级
ps -eo pid,ppid,ni,cmd

# 调整进程优先级(nice 值:-20 到 19)
nice -n 5 ./program        # 启动时设置
renice -n 10 -p <PID>      # 运行时调整

# 实时优先级
chrt -f -p 99 <PID>        # 设置实时优先级

B.12 网络进阶

B.12.1 TCP 协议深入

TCP 状态机:

LISTEN → SYN_SENT → SYN_RCVD → ESTABLISHED
                              ↓
                         FIN_WAIT_1 → FIN_WAIT_2 → TIME_WAIT → CLOSED
                                   ↓
                              CLOSE_WAIT → LAST_ACK → CLOSED

TCP 滑动窗口:

发送方维护发送窗口(已发送未确认的数据)
接收方维护接收窗口(可用缓冲区大小)
通过滑动窗口实现流量控制

TCP 拥塞控制:

算法描述特点
Reno慢启动 + 拥塞避免经典算法
Cubic基于窗口增长的立方函数Linux 默认
BBR基于带宽和延迟的模型Google 提出

TCP 连接问题排查:

# 查看 TCP 连接状态
ss -tlnp

# 查看连接详情
netstat -antp

# 抓包分析
tcpdump -i eth0 port 80 -w capture.pcap

# 分析延迟
mtr --report google.com

# 测试带宽
iperf3 -c server_ip

B.12.2 HTTP/2 特性

多路复用:

头部压缩:

服务器推送:

HTTP/2 配置示例(Nginx):

server {
    listen 443 ssl http2;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    # 启用 HTTP/2 推送
    http2_push_preload on;
    
    # 配置推送资源
    location = /index.html {
        http2_push /styles.css;
        http2_push /script.js;
    }
}

B.12.3 CDN 进阶配置

缓存策略:

// 设置缓存头
app.use((req, res, next) => {
  // 静态资源缓存 1 年
  if (req.path.match(/\.(js|css|png|jpg|svg)$/)) {
    res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
  }
  // HTML 不缓存或短时间缓存
  else {
    res.setHeader('Cache-Control', 'no-cache');
  }
  next();
});

缓存失效策略:

策略描述适用场景
版本哈希文件名包含哈希值静态资源
时间戳URL 添加时间戳参数动态内容
CDN 刷新主动清除 CDN 缓存紧急更新

CDN 回源配置:

// Cloudflare Worker 回源示例
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request));
});

async function handleRequest(request) {
  const cache = caches.default;
  const url = new URL(request.url);
  
  // 检查缓存
  let response = await cache.match(request);
  
  if (!response) {
    // 回源请求
    response = await fetch(request);
    
    // 缓存响应
    if (response.ok) {
      event.waitUntil(cache.put(request, response.clone()));
    }
  }
  
  return response;
}

B.13 安全进阶

B.13.1 密码学基础

哈希函数特性:

常见哈希算法:

算法输出长度安全性用途
MD5128 位已破解校验和
SHA-1160 位不安全历史系统
SHA-256256 位安全区块链、证书
SHA-3可变长度安全新兴标准

对称加密 vs 非对称加密:

特性对称加密非对称加密
密钥单密钥公钥+私钥
速度
用途加密数据密钥交换、签名
算法AES, DESRSA, ECC

TLS 证书类型:

类型验证级别适用场景
DV域名验证个人网站
OV组织验证企业网站
EV扩展验证金融机构

证书链:

用户浏览器
    ↓
服务器证书(由中间 CA 签发)
    ↓
中间 CA 证书(由根 CA 签发)
    ↓
根 CA 证书(自签名,内置在浏览器中)

B.13.2 身份认证进阶

JWT 结构:

Header.Payload.Signature

Header: {"alg": "HS256", "typ": "JWT"}
Payload: {"sub": "user123", "exp": 1717171200, "role": "admin"}
Signature: HMACSHA256(base64Url(header) + "." + base64Url(payload), secret)

JWT 使用示例:

import jwt from 'jsonwebtoken';

// 生成 Token
const token = jwt.sign(
  { userId: '123', role: 'user' },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

// 验证 Token
try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  console.log('User ID:', decoded.userId);
} catch (err) {
  console.error('Invalid token:', err);
}

// 刷新 Token
function refreshToken(oldToken: string) {
  try {
    const decoded = jwt.verify(oldToken, process.env.JWT_SECRET, { ignoreExpiration: true });
    return jwt.sign(
      { userId: decoded.userId, role: decoded.role },
      process.env.JWT_SECRET,
      { expiresIn: '1h' }
    );
  } catch (err) {
    throw new Error('Invalid refresh token');
  }
}

OAuth 2.0 流程:

1. 用户授权:GET /authorize?client_id=xxx&redirect_uri=xxx&response_type=code&scope=openid
2. 获取授权码:回调返回 code
3. 获取令牌:POST /token 交换 code 获得 access_token 和 refresh_token
4. 访问资源:使用 access_token 访问 API
5. 刷新令牌:使用 refresh_token 获取新的 access_token

OAuth 2.0 授权类型:

类型适用场景
Authorization CodeWeb 应用
Implicit纯前端应用
Password信任的客户端
Client Credentials服务间通信

OpenID Connect:

B.13.3 安全审计工具

# 代码安全扫描
npm install -g snyk
snyk test
snyk monitor

# 依赖漏洞检查
npm audit
pip check

# SQL 注入检测
sqlmap -u "http://example.com/login" --data "username=admin&password=test"

# XSS 检测
nmap --script http-xssed target.com

# SSL/TLS 检测
openssl s_client -connect example.com:443
ssllabs-scan example.com

# 密码强度检测
python3 -c "import zxcvbn; print(zxcvbn.zxcvbn('password123'))"

B.14 性能监控进阶

B.14.1 指标监控

RED 指标:

指标描述计算公式
Rate请求速率请求数 / 时间
Error错误率错误数 / 请求数
Duration响应时间P50, P90, P95, P99

USE 方法:

资源指标
CPU使用率、饱和度、错误
内存使用率、饱和度、错误
磁盘使用率、饱和度、错误
网络使用率、饱和度、错误

自定义指标(Prometheus):

import { Registry, Counter, Histogram } from 'prom-client';

const registry = new Registry();

// 计数器
const requestsCounter = new Counter({
  name: 'http_requests_total',
  help: 'Total HTTP requests',
  labelNames: ['method', 'endpoint', 'status']
});

// 直方图
const responseTimeHistogram = new Histogram({
  name: 'http_response_time_seconds',
  help: 'HTTP response time in seconds',
  labelNames: ['endpoint'],
  buckets: [0.1, 0.5, 1, 2, 5]
});

registry.registerMetric(requestsCounter);
registry.registerMetric(responseTimeHistogram);

// 使用中间件收集指标
app.use((req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;
    requestsCounter.inc({ 
      method: req.method, 
      endpoint: req.path, 
      status: res.statusCode 
    });
    responseTimeHistogram.observe({ endpoint: req.path }, duration);
  });
  
  next();
});

// 暴露指标端点
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', registry.contentType);
  res.send(await registry.metrics());
});

B.14.2 日志管理

日志级别详解:

级别使用场景示例
DEBUG详细调试信息函数调用参数、变量值
INFO正常业务流程用户登录、订单创建
WARN潜在问题缓存未命中、重试操作
ERROR可恢复错误数据库连接失败、API 调用失败
FATAL致命错误服务无法启动、数据丢失

结构化日志格式:

{
  "timestamp": "2024-01-15T10:30:00Z",
  "level": "INFO",
  "service": "user-service",
  "trace_id": "abc123",
  "span_id": "def456",
  "message": "User logged in",
  "context": {
    "user_id": "12345",
    "ip_address": "192.168.1.1",
    "user_agent": "Mozilla/5.0..."
  }
}

日志聚合示例(ELK Stack):

# filebeat.yml 配置
filebeat.inputs:
  - type: log
    paths:
      - /var/log/myapp/*.log

output.elasticsearch:
  hosts: ["elasticsearch:9200"]

setup.kibana:
  host: "kibana:5601"

# Logstash 过滤器
filter {
  grok {
    match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}" }
  }
  date {
    match => [ "timestamp", "ISO8601" ]
  }
}

B.14.3 分布式追踪

追踪上下文传播:

import { trace, context } from '@opentelemetry/api';

// 创建追踪器
const tracer = trace.getTracer('my-service');

// 创建 span
async function handleRequest(req) {
  return tracer.startActiveSpan('handle-request', async (span) => {
    try {
      span.setAttribute('request.method', req.method);
      span.setAttribute('request.path', req.path);
      
      const result = await processRequest(req);
      span.setStatus({ code: SpanStatusCode.OK });
      return result;
    } catch (error) {
      span.setStatus({ 
        code: SpanStatusCode.ERROR, 
        message: error.message 
      });
      throw error;
    } finally {
      span.end();
    }
  });
}

// 跨服务传播
async function callServiceB(data) {
  const span = trace.getSpan(context.active());
  const headers = {};
  
  // 注入追踪上下文到请求头
  trace.getTracerProvider().getTracer('my-service')
    .getActiveSpanProcessor()
    .inject(context.active(), headers);
  
  return fetch('http://service-b/api', {
    method: 'POST',
    headers: { ...headers, 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
  });
}

追踪工具对比:

工具特点适用场景
Jaeger开源、轻量中小型系统
Zipkin简单易用微服务架构
OpenTelemetry标准化 API多云环境
Datadog APM全链路追踪企业级

B.15 容器进阶

B.15.1 Docker 网络

网络模式详解:

模式描述隔离性
bridge默认模式,虚拟网桥容器间可通信
host共享宿主机网络无隔离
none无网络连接完全隔离
container共享另一个容器网络与目标容器共享
overlay跨主机网络Swarm 集群

自定义网络:

# 创建自定义网络
docker network create --driver bridge my-network

# 连接容器到网络
docker run --network my-network --name app1 myapp
docker run --network my-network --name app2 myapp

# 容器间通信
docker exec app1 ping app2  # 使用容器名解析

# 查看网络详情
docker network inspect my-network

Docker Compose 网络:

version: '3.8'
services:
  web:
    build: .
    networks:
      - frontend
      - backend
  
  api:
    build: ./api
    networks:
      - backend
  
  db:
    image: postgres
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # 不对外暴露

B.15.2 Docker 存储

存储驱动对比:

驱动特点适用场景
overlay2高效、分层推荐默认
aufs成熟、兼容性好旧系统
btrfs快照支持特定场景
zfs高级特性企业存储

卷挂载类型:

version: '3.8'
services:
  app:
    image: myapp
    volumes:
      # 命名卷(推荐)
      - data:/app/data
      
      # 绑定挂载(开发用)
      - ./src:/app/src
      
      # tmpfs(临时存储)
      - type: tmpfs
        target: /tmp
      
      # 只读挂载
      - ./config:/app/config:ro

volumes:
  data:
    driver: local

卷备份与恢复:

# 备份卷
docker run --rm -v my-volume:/data -v $(pwd):/backup busybox \
  tar cvf /backup/backup.tar /data

# 恢复卷
docker run --rm -v my-volume:/data -v $(pwd):/backup busybox \
  tar xvf /backup/backup.tar -C /data

B.15.3 Kubernetes 进阶

Pod 生命周期:

Pending → Running → Succeeded/Failed/Unknown

重启策略:Always / OnFailure / Never

探针配置:

apiVersion: v1
kind: Pod
spec:
  containers:
    - name: app
      image: myapp
      ports:
        - containerPort: 3000
      
      # 存活探针
      livenessProbe:
        httpGet:
          path: /health
          port: 3000
        initialDelaySeconds: 10
        periodSeconds: 5
        failureThreshold: 3
      
      # 就绪探针
      readinessProbe:
        tcpSocket:
          port: 3000
        initialDelaySeconds: 5
        periodSeconds: 3
      
      # 启动探针
      startupProbe:
        exec:
          command: ["node", "-e", "require('./server').start()"]
        failureThreshold: 30
        periodSeconds: 10

资源限制:

apiVersion: v1
kind: Pod
spec:
  containers:
    - name: app
      image: myapp
      resources:
        requests:
          memory: "128Mi"
          cpu: "100m"
        limits:
          memory: "256Mi"
          cpu: "200m"

ConfigMap 与 Secret:

# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  NODE_ENV: production
  API_URL: https://api.example.com

# Secret(base64 编码)
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DATABASE_PASSWORD: cGFzc3dvcmQ=
  API_KEY: dGVzdC1rZXk=

B.16 故障排查方法论

B.16.1 系统化排查流程

1. 定义问题:明确现象、范围、频率
2. 收集信息:日志、指标、配置
3. 形成假设:基于信息提出可能原因
4. 验证假设:设计测试验证
5. 实施修复:应用解决方案
6. 验证修复:确认问题解决
7. 记录总结:文档化问题和解决方案

B.16.2 常见问题排查

高 CPU 使用率:

# 查找高 CPU 进程
top -o %CPU
htop

# 分析进程线程
ps -T -p <PID>

# 分析 Java 线程
jstack <PID> | grep -A 10 "RUNNABLE"

# 分析 Node.js
node --inspect --inspect-brk app.js

内存泄漏:

# 监控内存使用
free -h
vmstat 1 10

# 分析内存快照(Node.js)
node --expose-gc app.js
# 在 Chrome DevTools 中分析

# Python 内存分析
pip install memory_profiler
@profile
def my_function():
    # 代码
    pass

网络问题:

# 检查网络连通性
ping google.com
traceroute google.com
mtr google.com

# 检查端口
nc -zv localhost 3000
ss -tlnp | grep 3000

# 抓包分析
tcpdump -i eth0 port 80 -w capture.pcap
wireshark capture.pcap

# DNS 问题
dig example.com
nslookup example.com

数据库慢查询:

-- PostgreSQL 慢查询日志
SET log_min_duration_statement = 100; -- 记录超过 100ms 的查询

-- 查看正在运行的查询
SELECT pid, query, now() - query_start as duration
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC;

-- 分析查询计划
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;

-- MySQL 慢查询日志
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

B.16.3 应急响应流程

事故响应步骤:

1. 检测:监控告警、用户反馈
2. 确认:验证问题确实存在
3. 评估:影响范围、严重程度
4. 通知:相关人员、用户
5. 缓解:临时解决方案
6. 修复:根本原因修复
7. 验证:确认服务恢复
8. 复盘:总结经验教训

严重程度分级:

级别描述响应时间
P0系统完全不可用立即
P1核心功能故障15 分钟内
P2次要功能故障1 小时内
P3轻微问题24 小时内

B.17 测试策略

B.17.1 测试金字塔

         ╱╲
        ╱  ╲         E2E 测试(少)
       ╱    ╲
      ╱──────╲
     ╱        ╲      集成测试(中)
    ╱          ╲
   ╱────────────╲
  ╱              ╲   单元测试(多)
 ╱────────────────╲

各层测试的特点:

层级速度成本维护难度覆盖范围
单元测试快(毫秒级)单个函数/类
集成测试中(秒级)模块间交互
E2E 测试慢(分钟级)完整用户流程

黄金比例(实践经验):

B.17.2 单元测试

// Jest 测试框架示例
// math.js
export function add(a, b) {
  return a + b;
}

export function divide(a, b) {
  if (b === 0) {
    throw new Error('Division by zero');
  }
  return a / b;
}

// math.test.js
import { add, divide } from './math';

describe('Math functions', () => {
  describe('add', () => {
    it('should add two positive numbers', () => {
      expect(add(2, 3)).toBe(5);
    });
    
    it('should handle negative numbers', () => {
      expect(add(-1, 1)).toBe(0);
      expect(add(-1, -1)).toBe(-2);
    });
    
    it('should handle decimal numbers', () => {
      expect(add(0.1, 0.2)).toBeCloseTo(0.3);
    });
  });
  
  describe('divide', () => {
    it('should divide two numbers', () => {
      expect(divide(10, 2)).toBe(5);
    });
    
    it('should throw when dividing by zero', () => {
      expect(() => divide(10, 0)).toThrow('Division by zero');
    });
  });
});
# pytest 测试框架示例
# test_math.py
import pytest

def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0

def test_divide():
    assert divide(10, 2) == 5

def test_divide_by_zero():
    with pytest.raises(ValueError):
        divide(10, 0)

@pytest.mark.parametrize("a,b,expected", [
    (2, 3, 5),
    (-1, 1, 0),
    (0, 0, 0),
    (0.1, 0.2, 0.3),
])
def test_add_parametrized(a, b, expected):
    assert add(a, b) == expected

# Fixture 示例
@pytest.fixture
def test_db():
    # 设置测试数据库
    db = create_test_database()
    yield db
    # 清理
    drop_test_database(db)

def test_user_creation(test_db):
    user = test_db.create_user("Alice", "alice@example.com")
    assert user.name == "Alice"

B.17.3 集成测试

// API 集成测试(Supertest)
import request from 'supertest';
import app from '../app';

describe('User API', () => {
  describe('POST /api/users', () => {
    it('should create a new user', async () => {
      const response = await request(app)
        .post('/api/users')
        .send({
          name: 'Alice',
          email: 'alice@example.com',
          age: 30,
        })
        .expect(201);
      
      expect(response.body.data).toHaveProperty('id');
      expect(response.body.data.name).toBe('Alice');
    });
    
    it('should return 400 for invalid input', async () => {
      const response = await request(app)
        .post('/api/users')
        .send({ name: '' })
        .expect(400);
      
      expect(response.body.error).toBeDefined();
    });
  });
  
  describe('GET /api/users/:id', () => {
    it('should return a user by id', async () => {
      const user = await createTestUser();
      
      const response = await request(app)
        .get(`/api/users/${user.id}`)
        .expect(200);
      
      expect(response.body.data.name).toBe(user.name);
    });
    
    it('should return 404 for non-existent user', async () => {
      await request(app)
        .get('/api/users/99999')
        .expect(404);
    });
  });
});
# FastAPI 集成测试
from fastapi.testclient import TestClient
from app import app

client = TestClient(app)

def test_create_user():
    response = client.post("/api/users", json={
        "name": "Alice",
        "email": "alice@example.com",
    })
    assert response.status_code == 201
    data = response.json()["data"]
    assert data["name"] == "Alice"
    assert "id" in data

def test_get_user():
    # 先创建用户
    create_response = client.post("/api/users", json={
        "name": "Bob",
        "email": "bob@example.com",
    })
    user_id = create_response.json()["data"]["id"]
    
    # 查询用户
    response = client.get(f"/api/users/{user_id}")
    assert response.status_code == 200
    assert response.json()["data"]["name"] == "Bob"

B.17.4 E2E 测试

// Cypress E2E 测试
describe('User Login Flow', () => {
  beforeEach(() => {
    cy.visit('/login');
  });
  
  it('should login successfully with valid credentials', () => {
    cy.get('[data-testid="email-input"]').type('alice@example.com');
    cy.get('[data-testid="password-input"]').type('correct-password');
    cy.get('[data-testid="login-button"]').click();
    
    cy.url().should('include', '/dashboard');
    cy.get('[data-testid="welcome-message"]').should('contain', 'Welcome, Alice');
  });
  
  it('should show error with invalid credentials', () => {
    cy.get('[data-testid="email-input"]').type('alice@example.com');
    cy.get('[data-testid="password-input"]').type('wrong-password');
    cy.get('[data-testid="login-button"]').click();
    
    cy.get('[data-testid="error-message"]')
      .should('be.visible')
      .and('contain', 'Invalid credentials');
  });
  
  it('should validate email format', () => {
    cy.get('[data-testid="email-input"]').type('invalid-email');
    cy.get('[data-testid="password-input"]').type('password123');
    cy.get('[data-testid="login-button"]').click();
    
    cy.get('[data-testid="email-error"]')
      .should('be.visible')
      .and('contain', 'Please enter a valid email');
  });
});

B.17.5 Mock 与 Stub

// Mock 外部依赖
jest.mock('../services/email');
import { sendEmail } from '../services/email';
import { signup } from './auth';

describe('User Signup', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });
  
  it('should send welcome email after signup', async () => {
    sendEmail.mockResolvedValue({ success: true });
    
    const user = await signup({
      name: 'Alice',
      email: 'alice@example.com',
    });
    
    expect(sendEmail).toHaveBeenCalledWith({
      to: 'alice@example.com',
      template: 'welcome',
      data: { name: 'Alice' },
    });
  });
  
  it('should still create user when email fails', async () => {
    sendEmail.mockRejectedValue(new Error('Email service down'));
    
    const user = await signup({
      name: 'Bob',
      email: 'bob@example.com',
    });
    
    expect(user).toBeDefined();
    expect(user.name).toBe('Bob');
  });
});

B.17.6 测试最佳实践

原则说明示例
FIRST 原则Fast, Independent, Repeatable, Self-validating, Timely
单一断言每个测试只验证一个行为一个 it/assert 只测一个功能点
避免测试实现细节测试行为而非实现测试输出而非内部调用顺序
使用测试工厂复用测试数据构建使用 factory_boy/faker 生成数据
测试边界条件空值、边界值、异常值空数组、最大最小值、null
维护测试可读性测试即文档描述清晰的测试名称和结构

测试命名规范:

// 命名模式:[unit/function] should [expected behavior] when [condition]
describe('ShoppingCart', () => {
  it('should calculate total correctly when adding multiple items', () => {
    // ...
  });
  
  it('should apply discount when coupon code is valid', () => {
    // ...
  });
  
  it('should throw error when adding out-of-stock item', () => {
    // ...
  });
});

B.17.7 测试覆盖率

覆盖率类型定义目标值
行覆盖率代码行被执行的比例80%+
分支覆盖率条件分支被覆盖的比例70%+
函数覆盖率函数被调用的比例90%+
语句覆盖率语句被执行的比例80%+
// 运行覆盖率报告
// npm test -- --coverage
// npx jest --coverage

// 覆盖率配置(jest.config.js)
module.exports = {
  collectCoverage: true,
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80,
    },
    './src/components/': {
      lines: 90,
    },
  },
  coveragePathIgnorePatterns: [
    '/node_modules/',
    '/__tests__/',
    '/types/',
  ],
};

B.18 API 设计模式

B.18.1 RESTful API 设计原则

原则说明示例
资源导向用名词命名资源,而非动词/users 而非 /getUsers
HTTP 方法语义GET 查、POST 增、PUT 改、DELETE 删GET /users/:id
状态码规范使用标准 HTTP 状态码200 成功、201 创建、404 未找到
版本管理通过 URL 或请求头管理版本/api/v1/users
分页标准统一的分页响应格式{ data: [...], page: 1, total: 50 }
错误格式统一的错误响应格式{ error: { code, message } }

API 端点命名规范:

# 资源列表
GET    /api/users                    # 获取用户列表
POST   /api/users                    # 创建用户

# 单个资源
GET    /api/users/:id                # 获取单个用户
PUT    /api/users/:id                # 更新用户(全量)
PATCH  /api/users/:id                # 更新用户(部分)
DELETE /api/users/:id                # 删除用户

# 资源关系
GET    /api/users/:id/posts          # 获取用户的帖子
POST   /api/users/:id/posts          # 创建用户的帖子
GET    /api/posts/:id/comments       # 获取帖子的评论

# 操作(动词在最后)
POST   /api/users/:id/activate       # 激活用户
POST   /api/orders/:id/cancel        # 取消订单
POST   /api/payments/:id/refund      # 退款

B.18.2 API 错误处理规范

// 统一错误格式
interface ApiError {
  code: string;
  message: string;
  details?: Record<string, string[]>;
  requestId?: string;
  timestamp?: string;
}

// 错误码规范
const ErrorCodes = {
  // 4xx 客户端错误
  VALIDATION_ERROR: 'VALIDATION_ERROR',
  UNAUTHORIZED: 'UNAUTHORIZED',
  FORBIDDEN: 'FORBIDDEN',
  NOT_FOUND: 'NOT_FOUND',
  RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
  CONFLICT: 'CONFLICT',
  
  // 5xx 服务器错误
  INTERNAL_ERROR: 'INTERNAL_ERROR',
  SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
  DATABASE_ERROR: 'DATABASE_ERROR',
  EXTERNAL_SERVICE_ERROR: 'EXTERNAL_SERVICE_ERROR',
} as const;

// 错误处理示例
app.post('/api/orders', async (req, res) => {
  try {
    const order = await createOrder(req.body);
    res.status(201).json({ data: order });
  } catch (error) {
    if (error instanceof ValidationError) {
      return res.status(400).json({
        code: 'VALIDATION_ERROR',
        message: 'Invalid order data',
        details: error.errors,
      });
    }
    
    if (error instanceof ConflictError) {
      return res.status(409).json({
        code: 'CONFLICT',
        message: 'Order already exists',
      });
    }
    
    // 未知错误
    console.error('Unexpected error creating order:', error);
    res.status(500).json({
      code: 'INTERNAL_ERROR',
      message: 'An unexpected error occurred',
      requestId: req.id,
    });
  }
});

B.18.3 分页与过滤

// 分页查询参数
interface PaginationParams {
  page?: number;        // 页码,从1开始
  limit?: number;       // 每页数量,默认20
  sort?: string;        // 排序字段
  order?: 'asc' | 'desc';  // 排序方向
  search?: string;      // 搜索关键词
  filters?: Record<string, any>;  // 过滤条件
}

// 分页响应
interface PaginatedResponse<T> {
  data: T[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
    hasNext: boolean;
    hasPrev: boolean;
  };
}

// 游标分页(适合实时数据)
interface CursorPagination {
  data: T[];
  cursor: {
    next: string | null;
    prev: string | null;
    hasMore: boolean;
  };
}

// 实现示例
async function listUsers(req, res) {
  const { page = 1, limit = 20, sort = 'created_at', order = 'desc', search } = req.query;
  
  const where = search
    ? { OR: [{ name: { contains: search } }, { email: { contains: search } }] }
    : {};
  
  const [users, total] = await Promise.all([
    db.users.findMany({
      where,
      skip: (Number(page) - 1) * Number(limit),
      take: Number(limit),
      orderBy: { [sort]: order },
    }),
    db.users.count({ where }),
  ]);
  
  res.json({
    data: users,
    pagination: {
      page: Number(page),
      limit: Number(limit),
      total,
      totalPages: Math.ceil(total / Number(limit)),
      hasNext: Number(page) * Number(limit) < total,
      hasPrev: Number(page) > 1,
    },
  });
}

B.18.4 API 安全

// 速率限制(Rate Limiting)
import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,    // 15分钟窗口
  max: 100,                      // 每个 IP 最多100个请求
  standardHeaders: true,
  message: {
    code: 'RATE_LIMIT_EXCEEDED',
    message: 'Too many requests, please try again later.',
  },
});

app.use('/api/', limiter);

// API 认证中间件链
app.use('/api/admin', authenticate);           // 先认证
app.use('/api/admin', authorize('admin'));     // 再授权
app.use('/api/admin', auditLog);               // 审计日志

// 请求大小限制
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));

// CORS 白名单
const allowedOrigins = [
  'https://example.com',
  'https://admin.example.com',
];

app.use(cors({
  origin: (origin, callback) => {
    if (!origin || allowedOrigins.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,
}));

B.18.5 API 文档

// Swagger/OpenAPI 配置示例
const swaggerOptions = {
  openapi: '3.0.0',
  info: {
    title: 'User Management API',
    version: '1.0.0',
    description: 'API for managing users and their posts',
  },
  servers: [
    { url: 'https://api.example.com/v1', description: 'Production' },
    { url: 'https://staging-api.example.com/v1', description: 'Staging' },
  ],
  components: {
    securitySchemes: {
      bearerAuth: {
        type: 'http',
        scheme: 'bearer',
        bearerFormat: 'JWT',
      },
    },
  },
  paths: {
    '/users': {
      get: {
        summary: 'Get users list',
        security: [{ bearerAuth: [] }],
        parameters: [
          { name: 'page', in: 'query', schema: { type: 'integer' } },
          { name: 'limit', in: 'query', schema: { type: 'integer' } },
          { name: 'search', in: 'query', schema: { type: 'string' } },
        ],
        responses: {
          '200': {
            description: 'Successful response',
            content: {
              'application/json': {
                schema: {
                  type: 'object',
                  properties: {
                    data: { type: 'array', items: { $ref: '#/components/schemas/User' } },
                    pagination: { $ref: '#/components/schemas/Pagination' },
                  },
                },
              },
            },
          },
        },
      },
    },
  },
};

B.19 设计模式

B.19.1 创建型模式

// 单例模式(Singleton)
class DatabaseConnection {
  private static instance: DatabaseConnection;
  private connection: any;
  
  private constructor() {
    this.connection = this.createConnection();
  }
  
  static getInstance(): DatabaseConnection {
    if (!DatabaseConnection.instance) {
      DatabaseConnection.instance = new DatabaseConnection();
    }
    return DatabaseConnection.instance;
  }
  
  async query(sql: string): Promise<any> {
    return this.connection.query(sql);
  }
  
  private createConnection() {
    console.log('Creating database connection...');
    return { query: async (sql: string) => console.log(`Executing: ${sql}`) };
  }
}

// 使用
const db1 = DatabaseConnection.getInstance();
const db2 = DatabaseConnection.getInstance();
console.log(db1 === db2); // true

// 工厂模式(Factory)
interface Logger {
  log(message: string): void;
}

class ConsoleLogger implements Logger {
  log(message: string): void {
    console.log(`[Console] ${message}`);
  }
}

class FileLogger implements Logger {
  constructor(private filePath: string) {}
  log(message: string): void {
    console.log(`[File] Writing to ${this.filePath}: ${message}`);
  }
}

class CloudLogger implements Logger {
  log(message: string): void {
    console.log(`[Cloud] Sending to cloud: ${message}`);
  }
}

class LoggerFactory {
  static createLogger(type: string, options?: any): Logger {
    switch (type) {
      case 'console':
        return new ConsoleLogger();
      case 'file':
        return new FileLogger(options?.filePath || './logs/app.log');
      case 'cloud':
        return new CloudLogger();
      default:
        throw new Error(`Unknown logger type: ${type}`);
    }
  }
}

// 使用
const logger = LoggerFactory.createLogger('console');
logger.log('Application started');

// 建造者模式(Builder)
class QueryBuilder {
  private table: string = '';
  private conditions: string[] = [];
  private orderByField: string = '';
  private orderDirection: string = 'ASC';
  private limitValue: number = 0;
  private offset: number = 0;
  
  from(table: string): this {
    this.table = table;
    return this;
  }
  
  where(field: string, operator: string, value: any): this {
    this.conditions.push(`${field} ${operator} ${typeof value === 'string' ? `'${value}'` : value}`);
    return this;
  }
  
  orderBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): this {
    this.orderByField = field;
    this.orderDirection = direction;
    return this;
  }
  
  limit(n: number): this {
    this.limitValue = n;
    return this;
  }
  
  build(): string {
    let query = `SELECT * FROM ${this.table}`;
    
    if (this.conditions.length > 0) {
      query += ` WHERE ${this.conditions.join(' AND ')}`;
    }
    
    if (this.orderByField) {
      query += ` ORDER BY ${this.orderByField} ${this.orderDirection}`;
    }
    
    if (this.limitValue > 0) {
      query += ` LIMIT ${this.limitValue}`;
    }
    
    if (this.offset > 0) {
      query += ` OFFSET ${this.offset}`;
    }
    
    return query;
  }
}

// 使用
const query = new QueryBuilder()
  .from('users')
  .where('age', '>', 18)
  .where('status', '=', 'active')
  .orderBy('name', 'ASC')
  .limit(10)
  .build();

console.log(query);
// SELECT * FROM users WHERE age > 18 AND status = 'active' ORDER BY name ASC LIMIT 10

B.19.2 结构型模式

// 适配器模式(Adapter)
// 场景:第三方支付库与我们的系统接口不同

// 我们系统的统一支付接口
interface PaymentProcessor {
  processPayment(amount: number, currency: string): Promise<PaymentResult>;
  refundPayment(transactionId: string): Promise<RefundResult>;
}

interface PaymentResult {
  success: boolean;
  transactionId: string;
  message: string;
}

interface RefundResult {
  success: boolean;
  refundId: string;
}

// 第三方 Stripe 支付(不同接口)
class StripeSDK {
  async charge(amountInCents: number, currencyCode: string): Promise<any> {
    // Stripe 原生接口
    return { id: 'stripe_123', status: 'succeeded' };
  }
  
  async refund(chargeId: string): Promise<any> {
    return { id: 'refund_456', status: 'succeeded' };
  }
}

// 适配器
class StripeAdapter implements PaymentProcessor {
  private stripe: StripeSDK;
  
  constructor(stripe: StripeSDK) {
    this.stripe = stripe;
  }
  
  async processPayment(amount: number, currency: string): Promise<PaymentResult> {
    const result = await this.stripe.charge(amount * 100, currency);
    return {
      success: result.status === 'succeeded',
      transactionId: result.id,
      message: 'Payment successful',
    };
  }
  
  async refundPayment(transactionId: string): Promise<RefundResult> {
    const result = await this.stripe.refund(transactionId);
    return {
      success: result.status === 'succeeded',
      refundId: result.id,
    };
  }
}

// 装饰器模式(Decorator)
interface Coffee {
  cost(): number;
  description(): string;
}

class SimpleCoffee implements Coffee {
  cost(): number { return 10; }
  description(): string { return 'Simple coffee'; }
}

class MilkDecorator implements Coffee {
  constructor(private coffee: Coffee) {}
  
  cost(): number { return this.coffee.cost() + 3; }
  description(): string { return this.coffee.description() + ', milk'; }
}

class SugarDecorator implements Coffee {
  constructor(private coffee: Coffee) {}
  
  cost(): number { return this.coffee.cost() + 1; }
  description(): string { return this.coffee.description() + ', sugar'; }
}

class WhippedCreamDecorator implements Coffee {
  constructor(private coffee: Coffee) {}
  
  cost(): number { return this.coffee.cost() + 5; }
  description(): string { return this.coffee.description() + ', whipped cream'; }
}

// 使用
let coffee: Coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
coffee = new WhippedCreamDecorator(coffee);

console.log(coffee.description());  // "Simple coffee, milk, sugar, whipped cream"
console.log(coffee.cost());          // 19

B.19.3 行为型模式

// 观察者模式(Observer)
interface Observer {
  update(event: string, data: any): void;
}

class EventBus {
  private observers: Map<string, Set<Observer>> = new Map();
  
  subscribe(event: string, observer: Observer): void {
    if (!this.observers.has(event)) {
      this.observers.set(event, new Set());
    }
    this.observers.get(event)!.add(observer);
  }
  
  unsubscribe(event: string, observer: Observer): void {
    this.observers.get(event)?.delete(observer);
  }
  
  publish(event: string, data: any): void {
    this.observers.get(event)?.forEach(observer => {
      observer.update(event, data);
    });
  }
}

// 具体观察者
class EmailService implements Observer {
  update(event: string, data: any): void {
    if (event === 'user.created') {
      console.log(`Sending welcome email to ${data.email}`);
    }
  }
}

class AuditService implements Observer {
  update(event: string, data: any): void {
    console.log(`Audit log: ${event} - ${JSON.stringify(data)}`);
  }
}

class NotificationService implements Observer {
  update(event: string, data: any): void {
    if (event === 'order.shipped') {
      console.log(`Sending notification: Order ${data.orderId} shipped`);
    }
  }
}

// 使用
const eventBus = new EventBus();
const emailService = new EmailService();
const auditService = new AuditService();

eventBus.subscribe('user.created', emailService);
eventBus.subscribe('user.created', auditService);
eventBus.subscribe('order.shipped', new NotificationService());

eventBus.publish('user.created', { id: 1, email: 'alice@example.com' });
eventBus.publish('order.shipped', { orderId: 'ORD-123' });

// 策略模式(Strategy)
interface SortStrategy {
  sort<T>(items: T[]): T[];
}

class QuickSortStrategy implements SortStrategy {
  sort<T>(items: T[]): T[] {
    if (items.length <= 1) return items;
    const pivot = items[Math.floor(items.length / 2)];
    const left = items.filter(x => x < pivot);
    const right = items.filter(x => x > pivot);
    const equal = items.filter(x => x === pivot);
    return [...this.sort(left), ...equal, ...this.sort(right)];
  }
}

class MergeSortStrategy implements SortStrategy {
  sort<T>(items: T[]): T[] {
    if (items.length <= 1) return items;
    const mid = Math.floor(items.length / 2);
    const left = this.sort(items.slice(0, mid));
    const right = this.sort(items.slice(mid));
    return this.merge(left, right);
  }
  
  private merge<T>(left: T[], right: T[]): T[] {
    const result: T[] = [];
    let i = 0, j = 0;
    
    while (i < left.length && j < right.length) {
      if (left[i] < right[j]) {
        result.push(left[i++]);
      } else {
        result.push(right[j++]);
      }
    }
    
    return [...result, ...left.slice(i), ...right.slice(j)];
  }
}

class Sorter {
  private strategy: SortStrategy;
  
  constructor(strategy: SortStrategy) {
    this.strategy = strategy;
  }
  
  setStrategy(strategy: SortStrategy) {
    this.strategy = strategy;
  }
  
  sort<T>(items: T[]): T[] {
    return this.strategy.sort(items);
  }
}

// 使用
const sorter = new Sorter(new QuickSortStrategy());
const numbers = [5, 2, 8, 1, 9, 3];
console.log(sorter.sort(numbers)); // [1, 2, 3, 5, 8, 9]

// 切换策略
sorter.setStrategy(new MergeSortStrategy());
console.log(sorter.sort(numbers));

B.19.4 设计模式选择指南

模式类型解决的问题适用场景
单例创建型确保全局只有一个实例数据库连接、配置管理
工厂创建型封装对象创建逻辑复杂对象创建、切换实现
建造者创建型分步构建复杂对象SQL 构建器、配置对象
适配器结构型接口不兼容第三方库集成
装饰器结构型动态添加功能中间件、日志、缓存
代理结构型控制对象访问懒加载、权限控制
观察者行为型一对多通知事件系统、消息队列
策略行为型算法可切换排序、支付、验证
命令行为型请求封装撤销、事务、队列
模板方法行为型算法框架固定数据处理流程

B.20 云服务基础

B.20.1 云服务模型

模型描述用户管理提供商管理示例
IaaS基础设施即服务应用、数据、运行时、部分安全虚拟化、服务器、存储、网络AWS EC2, GCP Compute
PaaS平台即服务应用、数据运行时、中间件、OS、基础设施Vercel, Railway
SaaS软件即服务数据、配置全部底层Gmail, Notion
FaaS函数即服务函数代码全部底层AWS Lambda, Cloudflare Workers

B.20.2 主流云服务商

服务商优势适合场景主要产品
AWS生态最全、功能最多企业级、复杂架构EC2、S3、Lambda、RDS
Google Cloud数据/AI 能力强数据分析、机器学习Cloud Run、BigQuery
Azure.NET 集成好微软生态客户Azure Functions、SQL
Vercel前端部署最佳Next.js、前端项目Edge Functions、Serverless
Cloudflare全球 CDN、安全边缘计算、静态站点Workers、Pages、R2
Railway部署最简单全栈小项目一键部署、数据库
Fly.io全球部署需要全球覆盖的应用Fly Machines、Postgres
DigitalOcean价格透明中小型项目Droplets、App Platform

B.20.3 服务器部署流程

# 1. 服务器初始设置
ssh root@your-server-ip

# 系统更新
apt update && apt upgrade -y

# 创建普通用户
adduser deploy
usermod -aG sudo deploy

# 配置 SSH 密钥
mkdir -p /home/deploy/.ssh
echo "your-public-key" >> /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

# 2. 安装基础软件
apt install -y nginx postgresql redis-server certbot python3-certbot-nginx

# 3. 安装 Node.js
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install -y nodejs

# 4. 安装 Docker
curl -fsSL https://get.docker.com | sh
usermod -aG docker deploy

# 5. 配置 Nginx 反向代理
cat > /etc/nginx/sites-available/myapp << 'EOF'
server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}
EOF

ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx

# 6. 配置 HTTPS
certbot --nginx -d example.com

# 7. 配置防火墙
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

B.20.4 数据库托管服务

服务类型免费额度适合场景
SupabasePostgreSQL500MB全栈项目,含实时功能
PlanetScaleMySQL1GB无服务器 MySQL
NeonPostgreSQL500MBServerless PostgreSQL
MongoDB AtlasMongoDB512MB文档数据库
Redis CloudRedis30MB缓存、消息队列
TursoSQLite500MB边缘数据库

B.20.5 云成本优化

// 成本优化检查清单
const costOptimization = {
  compute: [
    '使用预留实例/承诺使用折扣',
    '自动扩展策略(按需扩容)',
    '使用 Spot/Preemptible 实例',
    '清理未使用的资源(闲置实例、未关联的存储卷)',
  ],
  storage: [
    '使用对象存储分层(热/冷/归档)',
    '启用生命周期管理自动迁移',
    '删除未使用的快照和备份',
    '压缩和优化存储数据',
  ],
  network: [
    '使用 CDN 减少源站流量',
    '启用数据压缩传输',
    '使用内网通信避免 NAT 费用',
    '合理配置负载均衡器',
  ],
  database: [
    '使用预留数据库实例',
    '启用自动暂停(无服务器数据库)',
    '定期清理历史数据',
    '使用只读副本分离读写',
  ],
};

B.21 构建工具与包管理器

B.21.1 包管理器对比

工具语言特点常用命令
npmJavaScriptNode.js 自带npm install, npm run
YarnJavaScript更快、确定性安装yarn add, yarn start
pnpmJavaScript磁盘效率高、严格pnpm add, pnpm dev
pipPythonPython 官方pip install, pip list
PoetryPython依赖管理+打包poetry add, poetry build
CargoRustRust 官方cargo add, cargo build
Go ModulesGoGo 官方go get, go mod tidy
MavenJavaJava 标准mvn install, mvn test
GradleKotlin DSL灵活构建gradle build

B.21.2 npm/pnpm 包管理最佳实践

// package.json 最佳实践
{
  "name": "@myorg/my-package",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=18.0.0",
    "pnpm": ">=8.0.0"
  },
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "test": "vitest run",
    "test:watch": "vitest",
    "lint": "eslint src/",
    "lint:fix": "eslint src/ --fix",
    "format": "prettier --write src/",
    "typecheck": "tsc --noEmit",
    "preview": "vite preview",
    "clean": "rm -rf dist/ .next/ node_modules/"
  },
  "dependencies": {
    "next": "^14.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "^18.2.0",
    "typescript": "^5.3.0",
    "eslint": "^8.50.0",
    "prettier": "^3.0.0",
    "vitest": "^1.0.0"
  },
  "packageManager": "pnpm@8.15.0"
}

包管理核心命令:

# npm
npm init -y                    # 初始化项目
npm install <package>          # 安装包(生产依赖)
npm install -D <package>       # 安装包(开发依赖)
npm uninstall <package>        # 卸载包
npm update                     # 更新所有包
npm audit                      # 安全审计
npm audit fix                  # 修复安全漏洞
npm outdated                   # 查看过期包
npm ci                         # 根据 lockfile 精确安装

# pnpm(推荐)
pnpm add <package>             # 安装包
pnpm add -D <package>          # 安装开发依赖
pnpm remove <package>          # 卸载包
pnpm update                    # 更新包
pnpm audit                     # 安全审计
pnpm ls                        # 查看依赖树
pnpm why <package>             # 查看为什么依赖

B.21.3 构建工具配置

// Vite 配置(现代前端构建)
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  server: {
    port: 3000,
    proxy: {
      '/api': {
        target: 'http://localhost:4000',
        changeOrigin: true,
      },
    },
  },
  build: {
    outDir: 'dist',
    sourcemap: true,
    minify: 'esbuild',
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
        },
      },
    },
  },
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/test/setup.ts',
  },
});
// Webpack 配置(传统)
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.tsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    clean: true,
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
};

B.21.4 Monorepo 管理

# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
  - 'shared/*'
项目结构:
my-monorepo/
├── pnpm-workspace.yaml
├── package.json
├── packages/
│   ├── shared-utils/      # 共享工具库
│   │   ├── package.json
│   │   └── src/
│   ├── shared-types/      # 共享类型定义
│   │   ├── package.json
│   │   └── src/
│   └── ui-components/     # 共享 UI 组件
│       ├── package.json
│       └── src/
├── apps/
│   ├── web/               # Web 应用
│   │   ├── package.json
│   │   └── src/
│   ├── api/               # API 服务
│   │   ├── package.json
│   │   └── src/
│   └── mobile/            # 移动端
│       ├── package.json
│       └── src/
└── shared/
    └── config/            # 共享配置
        ├── eslint-config/
        ├── tsconfig/
        └── prettier-config/

Turborepo 配置:

// turbo.json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "lint": {
      "outputs": []
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  },
  "globalDependencies": ["tsconfig.json"]
}

B.22 代码审查最佳实践

B.22.1 代码审查清单

检查维度检查项说明
正确性逻辑是否正确代码是否实现了预期的功能
正确性边界条件是否处理空值、异常、极端输入
安全输入是否验证SQL 注入、XSS、CSRF
安全敏感信息是否泄露API 密钥、密码、Token
性能是否有 N+1 查询数据库查询效率
性能是否有不必要的计算缓存、记忆化
可维护命名是否清晰变量、函数、类名
可维护函数是否过长单一职责原则
可测试是否容易测试依赖注入、接口抽象
一致性是否遵循项目规范代码风格、架构模式

B.22.2 有效的代码审查

## 代码审查注意事项

### 审查者(Reviewer)
1. **审查范围**:一次审查不超过 200-400 行代码
2. **审查顺序**:先理解整体设计,再看具体实现
3. **反馈方式**:问题式反馈而非命令式
   - ❌ "把这个函数拆开"
   - ✅ "这个函数似乎有多个职责,考虑是否应该拆分成更小的函数?"
4. **区分主次**:标注问题严重程度(blocker / major / minor / nit)
5. **肯定好的代码**:不要只提问题,也表扬好的设计

### 提交者(Author)
1. **PR 描述清晰**:说明改动原因、影响范围、测试情况
2. **PR 不要太**:一次 PR 解决一个问题
3. **回复所有评论**:表示接受或解释原因
4. **遇到分歧**:面对面讨论比评论更高效
5. **及时响应**:24小时内回复审查意见

PR 模板示例:

## 描述
[简要描述这次改动的目的和内容]

## 关联 Issue
Closes #123

## 改动类型
- [ ] Bug 修复
- [ ] 新功能
- [ ] 重构
- [ ] 文档更新

## 测试
- [ ] 单元测试通过
- [ ] 集成测试通过
- [ ] 手动测试完成

## 检查清单
- [ ] 代码遵循项目规范
- [ ] 没有引入新的安全风险
- [ ] 性能影响已评估
- [ ] 文档已更新(如需要)
- [ ] 添加了必要的测试

## 截图(如适用)
[UI 改动请附截图]

B.22.3 代码审查工具

工具用途特点
GitHub PR Review代码审查行内评论、审核流程
GitLab Merge Request代码审查CI 集成、审批规则
ESLint代码质量静态分析、自动修复
SonarQube代码质量平台复杂度、重复代码、安全漏洞
CodeRabbitAI 代码审查自动审查、智能建议
Reviewdog自动评论集成多种分析工具

B.23 版本控制策略

B.23.1 Git 工作流对比

工作流适用场景优点缺点
GitHub Flow小型团队、持续部署简单、快速迭代无发布分支
Git Flow大型项目、版本发布层次清晰、适合发布复杂、分支多
Trunk-BasedCI/CD 成熟团队极速迭代需要高测试覆盖
GitLab Flow环境分支管理灵活、环境映射清晰需要约定一致

GitHub Flow(推荐小型项目):

# 1. 从 main 创建功能分支
git checkout -b feature/user-auth

# 2. 多轮提交
git add .
git commit -m "feat: add login form component"
git commit -m "feat: implement auth API integration"
git commit -m "test: add login form tests"

# 3. 推送到远程
git push -u origin feature/user-auth

# 4. 创建 Pull Request
# 5. 代码审查 → 合并到 main

# 6. 删除分支
git checkout main
git branch -d feature/user-auth
git push origin --delete feature/user-auth

B.23.2 提交信息规范(Conventional Commits)

<type>(<scope>): <description>

[optional body]

[optional footer]
Type含义示例
feat新功能feat(auth): add OAuth login
fixBug 修复fix(api): handle empty response
docs文档docs(readme): update installation guide
refactor重构refactor(utils): extract validation logic
test测试test(cart): add checkout tests
chore杂务chore(deps): update dependencies
style样式style(button): fix padding
perf性能perf(db): add index for user queries
ciCI/CDci(actions): add deploy workflow

B.23.3 语义化版本(SemVer)

MAJOR.MINOR.PATCH

1.4.2
^    ^  ^
|    |  └── PATCH: Bug 修复(向下兼容)
|    └──── MINOR: 新功能(向下兼容)
└───────── MAJOR: 不兼容的 API 变更

版本号规则:

B.24 编程原则与哲学

B.24.1 SOLID 原则

原则名称描述违反示例正确做法
S单一职责一个类只有一个变更理由一个类既处理业务逻辑又处理序列化分离业务逻辑和序列化
O开闭原则对扩展开放,对修改关闭添加新类型需要修改 switch 语句使用策略模式或多态
L里氏替换子类可以替换父类正方形继承长方形(违反数学关系)使用接口代替继承
I接口隔离接口应该小而专一个"全能"接口拆分多个特定接口
D依赖倒置依赖抽象而非具体实现高层模块直接依赖低层模块通过接口依赖

B.24.2 其他重要原则

原则描述示例
DRY不要重复自己提取公共代码为函数/模块
KISS保持简单不要过度设计,最简单的方案往往最好
YAGNI你不会需要它只实现当前需要的功能,不要预测未来需求
Law of Demeter最少知识原则不要链式调用的太深(如 a.b.c.d)
Composition over Inheritance组合优于继承使用组合模式而非深层继承树

B.24.3 代码坏味道

坏味道问题解决方案
过长函数函数做了太多事拆分成小函数
过长参数列表参数太多封装为对象
重复代码多处相同逻辑提取公共函数
大型类类职责太多拆分成多个类
数据泥团固定数据组合创建值对象
过度耦合类之间太依赖引入接口解耦
注释太多代码不清晰重构使代码自文档化
Vibe 练习

对 Claude Code 说:

"我正在做一个 Web 项目,需要了解 API 密钥保护的最佳实践。请检查我的项目是否有敏感信息泄露风险,并告诉我还应该注意哪些安全问题。"

"帮我分析这段代码的性能瓶颈,并提供具体的优化建议。"

"帮我设计一个完整的监控方案,包括指标、日志和追踪,用于我的微服务架构。"

"帮我为这个函数编写单元测试,覆盖所有边界条件。"

"帮我审查这段代码,指出潜在的问题并提供改进建议。"

"解释一下这段代码使用了什么设计模式,并建议是否有更好的替代方案。"

"帮我设计一个可扩展的 API 架构,支持版本管理和向后兼容。"

"帮我分析这个项目的依赖关系,检查是否有安全漏洞需要更新。"