Skip to content

技术写作

技术写作是前端工程师最容易被低估却又最能拉开差距的核心能力。代码写得好的人很多,但能把技术讲清楚、写明白的人却很少。技术写作不仅仅是「写文档」,它贯穿了你的整个职业生涯——从日常的 Code Review 评论、技术方案设计,到对外的技术博客、开源项目文档,甚至是晋升答辩的 PPT,都是技术写作能力的体现。

本文将从 写作的重要性 → 技术文档 → 技术博客 → RFC → Markdown 进阶 → 技术分享 → 效率工具 → 面试高频题 八个维度全面拆解技术写作这一软技能。


一、技术写作的重要性

1.1 为什么技术写作是核心能力

很多工程师认为「代码就是最好的文档」,这是一个典型的误区。代码只能表达 how(怎么做),而技术写作能表达 why(为什么这么做)what(做了什么)

技术写作的核心价值体现在三个维度:

技术写作的三重价值:

┌─────────────────────────────────────────────────────────┐
│                                                         │
│   沟通效率          知识沉淀           个人影响力          │
│   ─────────        ─────────         ─────────          │
│                                                         │
│   减少重复沟通      避免知识流失        建立技术品牌        │
│   降低理解成本      加速新人上手        扩大影响范围        │
│   异步协作基础      形成团队资产        助力职业发展        │
│                                                         │
└─────────────────────────────────────────────────────────┘

沟通效率

一篇好的技术文档可以替代数十次重复的口头沟通。当你把一个技术方案写成文档分享出去,团队成员可以异步阅读、思考、评论,这比拉一个会效率高得多。特别是在远程协作越来越普遍的今天,写作能力直接决定了你的协作效率。

知识沉淀

人的记忆是不可靠的。三个月前排查的线上问题、半年前做的技术选型决策、一年前设计的架构方案——如果没有文档沉淀,这些宝贵的经验会随着时间逐渐遗忘。当团队成员离职、转岗时,没有文档的项目就会变成「黑盒」。

个人影响力

技术写作是建立个人技术品牌最有效的方式。一篇高质量的技术博客可以触达数万读者,一个文档完善的开源项目更容易获得社区关注。在大厂晋升体系中,「技术影响力」是重要的评估维度,而技术写作是最可量化的影响力输出方式。

1.2 技术写作的类型

类型目标读者核心目的典型场景
技术文档团队成员、使用者指导使用、记录决策API 文档、架构文档、Runbook
技术博客广泛的技术社区分享知识、建立影响力掘金、知乎、个人博客
RFC/ADR团队决策者推动技术决策架构改造、技术选型
周报/月报上级、协作方同步进展、暴露风险定期汇报
技术分享团队或社区传播知识、促进讨论内部分享会、技术大会
Code Review代码作者提升代码质量PR 评审
Commit Message未来的维护者记录变更意图每次代码提交

1.3 好的技术写作 vs 差的技术写作

维度好的技术写作差的技术写作
读者意识明确知道写给谁看,调整语言和深度自说自话,不考虑读者背景
结构逻辑清晰,层次分明,有导航想到哪写到哪,缺乏组织
准确性代码可运行,链接有效,版本明确代码报错,链接失效,信息过时
简洁性用最少的文字传达最多的信息冗长啰嗦,废话连篇
可维护性易于更新,有版本管理写完就扔,从不更新
示例贴近真实场景,循序渐进示例脱离实际,跳跃过大

二、技术文档写作

2.1 文档类型总览

技术文档类型矩阵:

              面向使用者                    面向开发者
         ┌──────────────────┐        ┌──────────────────┐
  入门   │   Quick Start    │        │   Contributing   │
         │   Tutorial       │        │   Guide          │
         └──────────────────┘        └──────────────────┘

         ┌──────────────────┐        ┌──────────────────┐
  日常   │   User Guide     │        │   API Reference  │
         │   FAQ            │        │   Architecture   │
         └──────────────────┘        └──────────────────┘

         ┌──────────────────┐        ┌──────────────────┐
  运维   │   Changelog      │        │   Runbook        │
         │   Migration      │        │   ADR            │
         └──────────────────┘        └──────────────────┘

各类型文档的定位:

文档类型目的更新频率维护负责人
API 文档描述接口的输入输出、参数说明随代码变更接口开发者
架构文档描述系统整体设计和模块关系架构变更时架构负责人
使用指南(User Guide)引导用户完成特定任务功能变更时产品/前端
Runbook线上问题排查和应急操作手册每次故障后SRE/值班人
ADR(Architecture Decision Record)记录架构决策的上下文和理由决策时一次性方案提出者
Changelog记录版本变更内容每次发版发版负责人
Contributing Guide指导外部贡献者参与项目流程变更时项目维护者

2.2 README 写作规范

README 是一个项目的「门面」,是大多数人接触项目的第一个文件。一个优秀的 README 应该在 30 秒内让读者明白这个项目是什么、为什么要用它、怎么开始使用。

README 的标准结构:

markdown
# 项目名称

一句话描述项目的核心价值。

[![Build Status](badge-url)](link)
[![npm version](badge-url)](link)
[![License](badge-url)](link)

## Features

- 特性一:简短描述
- 特性二:简短描述
- 特性三:简短描述

## Quick Start

### Prerequisites

- Node.js >= 18
- pnpm >= 8

### Installation

pnpm add your-package

### Basic Usage

import { something } from 'your-package'

## Documentation

详细文档请查看 [完整文档](link)

## Contributing

参见 [CONTRIBUTING.md](link)

## License

MIT License

README 写作的关键原则:

原则说明反面案例
价值先行开头就说清楚项目解决什么问题上来就是安装步骤
可复制运行代码示例直接复制就能跑示例缺少 import 或依赖说明
渐进式披露从简单到复杂,先 Quick Start 再完整 API一上来就是全量配置
保持更新README 和代码保持同步文档描述的 API 已经废弃
视觉友好使用徽章、表格、代码高亮纯文字墙

2.3 API 文档

API 文档是使用频率最高的技术文档类型。好的 API 文档应该做到:看完就能用,不用看源码。

JSDoc 示例

typescript
interface RequestConfig {
  url: string
  method: 'GET' | 'POST' | 'PUT' | 'DELETE'
  headers?: Record<string, string>
  body?: unknown
  timeout?: number
  retries?: number
}

interface Response<T> {
  data: T
  status: number
  headers: Record<string, string>
}

async function request<T>(config: RequestConfig): Promise<Response<T>> {
  const { url, method, headers, body, timeout = 10000, retries = 0 } = config

  const controller = new AbortController()
  const timeoutId = setTimeout(() => controller.abort(), timeout)

  try {
    const response = await fetch(url, {
      method,
      headers,
      body: body ? JSON.stringify(body) : undefined,
      signal: controller.signal,
    })

    const data = await response.json()

    return {
      data: data as T,
      status: response.status,
      headers: Object.fromEntries(response.headers.entries()),
    }
  } finally {
    clearTimeout(timeoutId)
  }
}

对应的 API 文档应该包含

markdown
### request<T>(config)

发起 HTTP 请求。

**参数**

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| config.url | string | 是 | - | 请求地址 |
| config.method | 'GET' \| 'POST' \| 'PUT' \| 'DELETE' | 是 | - | 请求方法 |
| config.headers | Record<string, string> | 否 | - | 请求头 |
| config.body | unknown | 否 | - | 请求体 |
| config.timeout | number | 否 | 10000 | 超时时间(ms) |
| config.retries | number | 否 | 0 | 重试次数 |

**返回值**

Promise<Response<T>>

| 字段 | 类型 | 说明 |
|------|------|------|
| data | T | 响应数据 |
| status | number | HTTP 状态码 |
| headers | Record<string, string> | 响应头 |

**示例**

const { data } = await request<User[]>({
  url: '/api/users',
  method: 'GET',
})

**异常**

| 错误类型 | 触发条件 | 处理建议 |
|---------|---------|---------|
| AbortError | 请求超时 | 增大 timeout 或检查网络 |
| TypeError | URL 格式错误 | 检查 url 参数 |

自动化文档工具对比

工具语言特点适用场景
JSDocJavaScript注释即文档,生态成熟JS 项目
TypeDocTypeScript从类型定义生成文档TS 项目
Swagger/OpenAPI语言无关REST API 标准规范后端 API
Storybook组件组件文档 + 交互演示UI 组件库
tsdocTypeScript微软推出的 TS 文档标准大型 TS 项目

2.4 架构文档

架构文档的核心是回答「为什么系统是这样设计的」。它不是代码的翻译,而是对设计意图的记录。

一个好的架构文档结构:

架构文档结构:

1. 概述
   ├── 系统目标
   ├── 核心约束
   └── 关键利益相关方

2. 架构全景图
   ├── 系统上下文图(C4 Level 1)
   ├── 容器图(C4 Level 2)
   └── 组件图(C4 Level 3)

3. 关键设计决策
   ├── 技术选型(附 ADR 链接)
   ├── 数据流设计
   └── 错误处理策略

4. 非功能性需求
   ├── 性能目标
   ├── 可用性目标
   └── 安全要求

5. 部署架构
   ├── 环境说明
   ├── 部署流程
   └── 监控告警

6. 附录
   ├── 术语表
   ├── 参考文档
   └── 变更历史

2.5 ADR(Architecture Decision Record)

ADR 是一种轻量级的决策记录方式,用于记录架构层面的重要决策。它的核心价值在于:让后来者理解「为什么是这样」。

ADR 模板

markdown
# ADR-001: 使用 React 作为前端框架

## 状态

已接受(2024-01-15)

## 上下文

我们需要为新的 B 端管理系统选择前端框架。团队有 8 名前端工程师,
其中 5 人有 React 经验,2 人有 Vue 经验,1 人是新人。
系统预计有 200+ 页面,需要支撑 3 年以上的迭代。

## 考虑的方案

### 方案一:React + Next.js
- 优势:团队熟悉度高,生态丰富,SSR 支持好
- 劣势:学习曲线陡峭(对新人),样板代码多

### 方案二:Vue 3 + Nuxt 3
- 优势:上手简单,模板语法直观,官方工具链完善
- 劣势:团队熟悉度低,需要学习成本

### 方案三:Angular
- 优势:大型项目架构完善,TypeScript 原生支持
- 劣势:团队无经验,学习成本最高

## 决定

选择 React + Next.js(方案一)。

## 理由

1. 团队 62.5% 的成员有 React 经验,切换成本最低
2. React 生态中有丰富的 B 端组件库(Ant Design、Arco Design)
3. Next.js 的 App Router 提供了良好的项目结构约束
4. 招聘市场 React 人才储备充足

## 后果

- 需要为 Vue 背景的同学提供 React 培训(预计 2 周)
- 需要制定 React 项目规范和最佳实践
- 状态管理需要额外选型(Redux Toolkit / Zustand / Jotai)

ADR 最佳实践

实践说明
编号管理使用递增编号,如 ADR-001、ADR-002
不可变性已接受的 ADR 不应修改,而是新建 ADR 来替代
关联性在 ADR 中引用相关的其他 ADR
状态流转提议 → 已接受 / 已拒绝 / 已替代 / 已废弃
存放位置跟代码放一起(如 docs/adr/),纳入版本管理

2.6 Runbook

Runbook 是线上问题排查的应急手册,在故障发生时需要快速定位和处理。好的 Runbook 应该做到:即使是第一次值班的人也能照着操作。

markdown
# Runbook: 前端页面白屏

## 影响范围
- 用户无法看到页面内容
- 影响所有用户 / 部分用户 / 特定浏览器

## 快速诊断

### Step 1: 确认问题范围
1. 检查是全量还是灰度:打开 [监控面板](link)
2. 检查是否特定地区:查看 CDN 监控
3. 检查是否特定版本:对比版本号

### Step 2: 查看错误日志
1. 打开 Sentry [链接]
2. 筛选时间范围和错误级别
3. 查看 Top 错误堆栈

### Step 3: 检查资源加载
1. 检查 CDN 状态:curl -I https://cdn.example.com/app.js
2. 检查 JS 文件是否正常返回
3. 检查是否有跨域错误

## 应急处理

### 如果是 JS 报错导致
1. 确认错误代码位置
2. 如果是最近发布引入:执行回滚
   回滚命令:kubectl rollout undo deployment/frontend
3. 通知相关开发者

### 如果是 CDN 故障
1. 切换到备用 CDN
2. 联系 CDN 供应商
3. 通知 SRE 团队

## 事后处理
- [ ] 编写故障复盘文档
- [ ] 更新监控告警规则
- [ ] 补充自动化检测

三、技术博客写作

3.1 文章结构

一篇优秀的技术博客应该具备完整的叙事结构。最经典的结构是「问题驱动型」:

技术博客的叙事结构:

  ┌──────────────────────────────────────┐
  │  标题:精准概括 + 吸引点击              │
  └──────────────┬───────────────────────┘

  ┌──────────────────────────────────────┐
  │  引言:提出问题/痛点(引起共鸣)        │
  │  "你是否遇到过这样的问题..."            │
  └──────────────┬───────────────────────┘

  ┌──────────────────────────────────────┐
  │  背景知识:必要的前置概念               │
  │  确保不同水平的读者都能跟上              │
  └──────────────┬───────────────────────┘

  ┌──────────────────────────────────────┐
  │  正文:原理分析 → 方案对比 → 实现细节   │
  │  这是文章的核心,要有深度和干货          │
  └──────────────┬───────────────────────┘

  ┌──────────────────────────────────────┐
  │  实战案例:贴近真实项目的完整示例        │
  │  让读者能直接复用                       │
  └──────────────┬───────────────────────┘

  ┌──────────────────────────────────────┐
  │  总结:核心观点回顾 + 最佳实践          │
  │  帮助读者快速回忆要点                   │
  └──────────────┬───────────────────────┘

  ┌──────────────────────────────────────┐
  │  参考资料:注明信息来源                  │
  │  体现严谨性,方便读者深入                │
  └──────────────────────────────────────┘

3.2 写作技巧

技巧一:先写大纲再写正文

大纲是文章的骨架。先把大纲写出来,确认逻辑链条是通顺的,再填充内容。这能避免写到一半发现逻辑不通,推倒重来。

大纲示例 —— 《React 状态管理方案选型指南》

1. 引言:状态管理是 React 开发中最常见的痛点
2. 状态分类:UI 状态 vs 服务端状态 vs 全局状态
3. 方案概览
   3.1 React 内置方案:useState / useReducer / useContext
   3.2 轻量方案:Zustand / Jotai / Valtio
   3.3 重量方案:Redux Toolkit / MobX
   3.4 服务端状态:TanStack Query / SWR
4. 方案对比(从 7 个维度)
5. 选型决策树
6. 实战:用 Zustand 重构一个中型项目
7. 总结 + 选型建议

技巧二:用简单语言解释复杂概念

技术写作的目标不是炫技,而是让读者理解。用类比、图示和循序渐进的方式来降低理解门槛。

不好的写法:

Virtual DOM 是一种以 JavaScript 对象为基础的轻量级 DOM 抽象层,
通过 diff 算法计算最小化的 DOM 变更集合,
批量应用到真实 DOM 上以优化渲染性能。

更好的写法:

想象你要装修房子。

直接改装修(操作真实 DOM):每改一个地方就要动工一次,
工人来来回回很浪费时间。

Virtual DOM 的做法:先在图纸(JS 对象)上规划好所有改动,
对比新旧图纸找出差异,然后让工人一次性施工完毕。

这就是 Virtual DOM 的核心思想 —— 用 JS 对象描述 UI 结构,
通过 diff 对比找出最少的改动,最后批量更新真实 DOM。

技巧三:代码示例要可运行

读者最反感的就是代码跑不通。确保你的代码示例:

要求说明
完整性包含必要的 import 语句
可运行性复制到项目中能直接运行
渐进性从简单到复杂,逐步构建
标注版本说明依赖的版本号
错误处理包含基本的错误处理逻辑

技巧四:图示辅助理解

数据流、架构关系、状态变化等抽象概念,用图比用文字有效得多。

常用图示类型:

┌──────────────┬──────────────────────────┬─────────────────┐
│  图示类型     │  适用场景                 │  推荐工具        │
├──────────────┼──────────────────────────┼─────────────────┤
│  流程图       │  业务流程、算法步骤        │  Mermaid         │
│  架构图       │  系统架构、模块关系        │  Excalidraw      │
│  时序图       │  接口调用、消息传递        │  Mermaid         │
│  状态机       │  组件状态变化             │  XState Viz      │
│  对比表格     │  方案对比、特性对比        │  Markdown Table  │
│  思维导图     │  知识体系、技术全景        │  Markmap         │
└──────────────┴──────────────────────────┴─────────────────┘

3.3 标题的艺术

标题决定了文章能不能被点开。好的标题需要在「吸引点击」和「准确描述」之间找到平衡。

类型示例分析
问题式「为什么你的 React 应用越来越慢?」引发好奇心,读者想知道答案
方案式「从 Webpack 迁移到 Vite:完整实战指南」明确告诉读者能获得什么
数字式「5 个让你的 TypeScript 代码更优雅的技巧」数字给人具体感,降低阅读决策成本
对比式「Zustand vs Jotai:2024 年该选哪个?」精准命中有选型困惑的读者
深度式「深入理解 React Fiber 架构」吸引想要深入学习的读者

标题的反面案例:

反面案例问题
「React 学习笔记」太泛,没有吸引力
「震惊!这个 JS 特性 99% 的人不知道」标题党,损害信誉
「浅谈前端工程化」「浅谈」暗示内容不深入
「关于 Vue 3 的一些思考」模糊,不知道能获得什么

3.4 SEO 基础

如果你的文章发布在个人博客上,基本的 SEO 知识能让文章被更多人发现。

SEO 核心要素:

┌─────────────────────────────────────────────────────┐
│                                                     │
│  1. 关键词策略                                       │
│     ├── 确定目标关键词(如 "React 状态管理")          │
│     ├── 关键词出现在标题、首段、小标题中               │
│     └── 避免关键词堆砌,保持自然                      │
│                                                     │
│  2. 结构化内容                                       │
│     ├── 使用 H1 ~ H3 构建层次                        │
│     ├── 每个 H2 下有实质内容                          │
│     └── 使用列表和表格提高可读性                      │
│                                                     │
│  3. Meta 信息                                        │
│     ├── title:包含关键词,50-60 字符                 │
│     ├── description:概括内容,150-160 字符           │
│     └── og:image:社交分享图片                        │
│                                                     │
│  4. 技术优化                                         │
│     ├── 页面加载速度                                  │
│     ├── 移动端适配                                    │
│     ├── HTTPS                                        │
│     └── 结构化数据(Schema.org)                     │
│                                                     │
└─────────────────────────────────────────────────────┘

在前端博客框架中实现 SEO:

typescript
import { defineConfig } from 'vitepress'

export default defineConfig({
  head: [
    ['meta', { name: 'description', content: '前端工程师技术博客' }],
    ['meta', { property: 'og:title', content: '页面标题' }],
    ['meta', { property: 'og:description', content: '页面描述' }],
    ['meta', { property: 'og:image', content: 'https://example.com/og.png' }],
    ['meta', { name: 'twitter:card', content: 'summary_large_image' }],
  ],
  transformHead({ pageData }) {
    const head = []
    head.push([
      'meta',
      { property: 'og:title', content: pageData.frontmatter.title },
    ])
    head.push([
      'meta',
      {
        property: 'og:description',
        content: pageData.frontmatter.description,
      },
    ])
    return head
  },
})

3.5 技术博客写作实战模板

以「性能优化」主题为例的完整文章骨架:

markdown
# React 长列表性能优化:从卡顿到丝滑的完整方案

## 问题背景

在我们的管理后台中,有一个需要展示 10000+ 条数据的列表页面。
用户反馈页面滚动卡顿严重,Chrome Performance 面板显示
每帧渲染耗时超过 100ms,远超 16.6ms 的目标。

## 问题分析

### 为什么会卡顿?

(配图:Performance 面板截图,标注长任务)

核心原因是 DOM 节点过多。10000 条数据意味着 10000 个 DOM 节点,
浏览器在布局(Layout)和绘制(Paint)阶段需要处理大量节点。

### 量化分析

| 指标 | 优化前 | 目标值 |
|------|-------|--------|
| DOM 节点数 | 30000+ | < 500 |
| 首屏渲染时间 | 3.2s | < 500ms |
| 滚动帧率 | 15fps | 60fps |
| 内存占用 | 280MB | < 80MB |

## 解决方案

### 方案一:虚拟滚动

(详细介绍原理、代码实现、效果对比)

### 方案二:分页加载

(适用场景、实现方式、优劣对比)

### 方案三:无限滚动 + 回收

(结合方案一和方案二的混合方案)

## 方案对比

| 维度 | 虚拟滚动 | 分页加载 | 无限滚动 |
|------|---------|---------|---------|
| 用户体验 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 实现复杂度 | 高 | 低 | 中 |
| 内存占用 | 低 | 低 | 递增 |
| SEO 友好 | 差 | 好 | 差 |

## 最终实现

(完整的代码实现 + 效果截图 + 性能数据对比)

## 总结

(核心观点 + 适用场景建议)

## 参考资料

- [React Virtualized](link)
- [Web Performance Fundamentals](link)

四、RFC(Request for Comments)

4.1 RFC 在工程团队中的作用

RFC 是工程团队中推动技术决策的核心机制。它不是简单的「我想做什么」,而是通过结构化的文档,让团队成员充分了解背景、方案和权衡,从而做出更好的集体决策。

RFC 的核心价值:

┌────────────────────────────────────────────────────┐
│                                                    │
│  1. 减少决策偏差                                    │
│     一个人的想法可能有盲区,                          │
│     RFC 让更多人参与思考,暴露潜在问题                 │
│                                                    │
│  2. 异步决策                                        │
│     不需要拉会议,每个人可以在自己方便的时间            │
│     仔细阅读和评论                                   │
│                                                    │
│  3. 决策留痕                                        │
│     半年后可以回溯当初为什么这样决定,                  │
│     避免重复讨论                                     │
│                                                    │
│  4. 知识传播                                        │
│     RFC 讨论过程本身就是一次深度的技术交流              │
│                                                    │
└────────────────────────────────────────────────────┘

什么时候需要写 RFC:

场景是否需要 RFC说明
引入新的技术栈✅ 需要影响范围大,需要充分讨论
大型架构重构✅ 需要涉及多个模块,需要对齐理解
修复一个 Bug❌ 不需要直接修复即可
新增一个工具函数❌ 不需要影响范围小,Code Review 足够
更换构建工具✅ 需要影响整个开发流程
制定新的编码规范✅ 需要影响所有开发者的日常工作
调整 API 设计⚠️ 视情况如果是破坏性变更则需要

4.2 RFC 模板

markdown
# RFC-2024-003: 从 Redux 迁移到 Zustand

## 元信息
- 作者:张三
- 状态:讨论中
- 创建日期:2024-03-15
- 最后更新:2024-03-20
- 相关人员:前端团队全员

## 动机(Motivation)

当前项目使用 Redux + Redux Saga 作为状态管理方案,存在以下问题:

1. **样板代码过多**:新增一个 store 需要创建 action、reducer、
   saga、selector 四个文件,开发效率低
2. **包体积大**:redux + redux-saga + react-redux 合计约 45KB
   (gzipped)
3. **学习成本高**:新人平均需要 2 周才能熟练使用 Redux Saga
4. **TypeScript 支持差**:类型推导需要大量手动标注

## 提案(Proposal)

将状态管理方案从 Redux + Redux Saga 迁移到 Zustand + TanStack Query。

- Zustand:管理客户端状态(UI 状态、全局状态)
- TanStack Query:管理服务端状态(API 数据、缓存)

## 详细设计(Detailed Design)

### 迁移策略

采用渐进式迁移,新旧方案并存:

Phase 1(第 1-2 周):
  新模块使用 Zustand,旧模块保持 Redux
  建立 Zustand 使用规范和最佳实践

Phase 2(第 3-6 周):
  逐步将旧模块的服务端状态迁移到 TanStack Query
  优先迁移使用频率最高的模块

Phase 3(第 7-8 周):
  迁移剩余的客户端状态到 Zustand
  移除 Redux 相关依赖

### 代码对比

Redux 写法:

const SET_USER = 'SET_USER'
const FETCH_USER = 'FETCH_USER'

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case SET_USER:
      return { ...state, user: action.payload }
    default:
      return state
  }
}

function* fetchUserSaga(action) {
  try {
    const user = yield call(api.getUser, action.payload)
    yield put({ type: SET_USER, payload: user })
  } catch (e) {
    yield put({ type: 'FETCH_USER_FAILED', payload: e.message })
  }
}

Zustand + TanStack Query 写法:

import { create } from 'zustand'
import { useQuery } from '@tanstack/react-query'

const useUserStore = create((set) => ({
  theme: 'light',
  toggleTheme: () =>
    set((state) => ({
      theme: state.theme === 'light' ? 'dark' : 'light',
    })),
}))

function useUser(userId: string) {
  return useQuery({
    queryKey: ['user', userId],
    queryFn: () => api.getUser(userId),
  })
}

### 包体积对比

| 方案 | 包大小(gzipped) | 减少 |
|------|------------------|------|
| Redux + Redux Saga + React Redux | ~45KB | - |
| Zustand + TanStack Query | ~15KB | -67% |

## 替代方案(Alternatives)

### 方案二:Jotai + TanStack Query

优势:原子化状态管理,更细粒度的重渲染控制
劣势:原子化思维对团队来说学习成本更高

### 方案三:继续使用 Redux,升级到 Redux Toolkit

优势:迁移成本最低
劣势:不能根本解决样板代码问题,包体积优化有限

### 方案对比

| 维度 | Zustand | Jotai | Redux Toolkit |
|------|---------|-------|---------------|
| 包体积 | 1.1KB | 2.4KB | 11KB |
| 学习成本 | 低 | 中 | 中 |
| DevTools | ✅ | ✅ | ✅ |
| 迁移成本 | 中 | 高 | 低 |
| 团队接受度 | 高 | 中 | 高 |

## 未解决问题(Unresolved Questions)

1. 迁移期间如何保证新旧状态管理方案的数据一致性?
2. 是否需要封装统一的状态管理抽象层,以便将来再次切换?
3. Zustand 的 middleware 生态是否能覆盖我们所有的需求?

## 风险评估

| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| 迁移引入 Bug | 中 | 高 | 完善的测试覆盖 + 灰度发布 |
| 进度延期 | 中 | 中 | 预留 buffer,分 Phase 执行 |
| 团队不适应 | 低 | 低 | 提前培训 + pair programming |

4.3 RFC 流程

RFC 生命周期:

  ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
  │  起草    │────▶│  讨论    │────▶│  修改    │────▶│  决议    │
  │  Draft   │     │  Review  │     │  Revise  │     │  Final   │
  └─────────┘     └─────────┘     └─────────┘     └─────────┘
       │               │               │               │
       ▼               ▼               ▼               ▼
  作者撰写        团队成员评论     根据反馈修改      接受/拒绝/搁置
  初始提案        提出问题和建议   更新方案细节      记录最终决定

RFC 讨论中的常见问题及应对:

常见问题应对策略
讨论陷入细节把细节问题标记为「未解决问题」,先聚焦大方向
无人回复主动 @相关人,设置 deadline
意见分歧用数据说话,安排小规模 POC 验证
范围蔓延严格限定本次 RFC 的范围,把其他问题拆成新的 RFC
久议不决设定决策 deadline,由 Tech Lead 拍板

五、Markdown 进阶

5.1 Markdown 基础语法回顾

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

**粗体** *斜体* ~~删除线~~ `行内代码`

- 无序列表项
- 无序列表项

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

> 引用文本

[链接文本](url)
![图片描述](image-url)

水平分隔线:
---

5.2 高级语法

表格

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

脚注

markdown
这是一段文字[^1]。

[^1]: 这是脚注的内容。

任务列表

markdown
- [x] 已完成的任务
- [ ] 未完成的任务
- [ ] 另一个未完成的任务

折叠内容

html
<details>
<summary>点击展开详情</summary>

这里是被折叠的内容。
可以包含代码块、表格等任何 Markdown 内容。

</details>

5.3 Mermaid 图表

Mermaid 是一种基于文本的图表语法,可以在 Markdown 中直接渲染图表。

流程图

graph TD
    A[开始] --> B{条件判断}
    B -->|是| C[执行操作 A]
    B -->|否| D[执行操作 B]
    C --> E[结束]
    D --> E

时序图

sequenceDiagram
    participant Browser
    participant Server
    participant Database

    Browser->>Server: GET /api/users
    Server->>Database: SELECT * FROM users
    Database-->>Server: 返回数据
    Server-->>Browser: JSON Response

甘特图

gantt
    title 项目开发计划
    dateFormat YYYY-MM-DD

    section 设计阶段
    需求分析      :a1, 2024-01-01, 7d
    技术方案设计   :a2, after a1, 5d

    section 开发阶段
    核心功能开发   :b1, after a2, 14d
    联调测试      :b2, after b1, 7d

    section 发布阶段
    灰度发布      :c1, after b2, 3d
    全量发布      :c2, after c1, 1d

状态图

stateDiagram-v2
    [*] --> Idle
    Idle --> Loading : fetch()
    Loading --> Success : resolve
    Loading --> Error : reject
    Success --> Idle : reset
    Error --> Loading : retry
    Error --> Idle : reset

5.4 MDX:在 Markdown 中使用 React 组件

MDX 让你可以在 Markdown 中直接使用 JSX,这对于交互式文档非常有用。

tsx
import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  )
}

在 MDX 文件中使用:

mdx
import { Counter } from './Counter'

# 交互式文档示例

这是一个可交互的计数器:

<Counter />

你可以直接在文档中操作它。

MDX 的典型应用场景:

场景说明
组件库文档在文档中直接展示组件的交互效果
教程让读者在文档中直接尝试代码
数据可视化在文档中嵌入图表组件
设计系统展示设计 Token 和组件变体

5.5 文档站工具对比

工具框架特点适用场景
VitePressVue极快的冷启动,Vue 生态Vue 项目文档、博客
DocusaurusReactFacebook 出品,功能全面大型开源项目文档
NextraReact基于 Next.js,轻量简洁个人博客、小型项目
Astro多框架零 JS 默认,性能极致内容网站、博客
RspressReact字节出品,Rspack 构建,极速大型文档站
MintlifyReact美观的 API 文档模板API 文档
Storybook多框架组件驱动开发UI 组件文档

各工具的配置示例:

VitePress

typescript
import { defineConfig } from 'vitepress'

export default defineConfig({
  title: 'My Project',
  description: 'A VitePress Site',
  themeConfig: {
    nav: [
      { text: 'Guide', link: '/guide/' },
      { text: 'API', link: '/api/' },
    ],
    sidebar: {
      '/guide/': [
        {
          text: 'Getting Started',
          items: [
            { text: 'Introduction', link: '/guide/introduction' },
            { text: 'Quick Start', link: '/guide/quick-start' },
          ],
        },
      ],
    },
  },
})

Docusaurus

javascript
const config = {
  title: 'My Project',
  tagline: 'A Docusaurus Site',
  url: 'https://example.com',
  baseUrl: '/',
  presets: [
    [
      'classic',
      {
        docs: {
          sidebarPath: './sidebars.js',
          editUrl: 'https://github.com/org/repo/tree/main/',
        },
        blog: {
          showReadingTime: true,
        },
      },
    ],
  ],
}

module.exports = config

六、技术分享与演讲

6.1 幻灯片设计原则

幻灯片设计的四大原则:

┌──────────────────────────────────────────────────┐
│                                                  │
│  1. 一页一个核心观点                               │
│     不要在一页中塞入太多信息                        │
│     每页幻灯片只传达一个关键信息                     │
│                                                  │
│  2. 文字精简,图示为主                              │
│     能用图说明的不用文字                            │
│     代码控制在 15 行以内                            │
│     使用大字号(24pt+)                            │
│                                                  │
│  3. 视觉一致性                                     │
│     统一的配色方案(2-3 种主色)                     │
│     统一的字体和字号层级                            │
│     统一的代码高亮主题                              │
│                                                  │
│  4. 渐进式披露                                     │
│     使用动画逐步展示内容                            │
│     复杂图表分步呈现                               │
│     先给结论,再解释过程                            │
│                                                  │
└──────────────────────────────────────────────────┘

技术演讲中幻灯片的常见类型:

幻灯片类型设计要点使用场景
标题页标题 + 姓名 + 日期,简洁有力开场
议程页列出 3-5 个大纲点开头和过渡
概念解释一个核心图 + 简短文字讲解原理
代码展示高亮关键行,字号不小于 18pt代码讲解
对比页左右对比或表格对比方案选型
数据页柱状图/折线图,标注关键数据性能对比
总结页3-5 个核心 takeaway结尾
Q&A 页联系方式 + 资源链接结尾互动

6.2 如何准备技术分享

技术分享准备流程(建议时间线):

  分享前 2 周          分享前 1 周          分享前 3 天          当天
  ──────────          ──────────          ──────────          ────
  确定主题             完成幻灯片          内部试讲             正式分享
  列出大纲             准备 Demo           收集反馈
  收集素材             写演讲稿            修改优化
  确认受众                                 准备 Q&A

分享准备清单

阶段任务注意事项
选题确定主题和受众选自己最熟悉的领域,别选「刚学完的」
大纲列出核心要点30 分钟的分享控制在 3-5 个要点
素材收集代码、数据、图片代码示例要精简,数据要真实可靠
制作制作幻灯片 + Demo先完成内容,再优化设计
试讲找同事试讲一遍控制时间,收集反馈
演练熟悉全流程检查 Demo 环境、投影效果

控制分享时间的技巧

30 分钟分享的时间分配:

┌────────────────────────────────────────────────┐
│  开场(2 min)   │  自我介绍 + 今天要讲什么       │
├──────────────────┼─────────────────────────────┤
│  背景(3 min)   │  为什么要讲这个话题             │
├──────────────────┼─────────────────────────────┤
│  核心(18 min)  │  主体内容(3-4 个 section)    │
├──────────────────┼─────────────────────────────┤
│  总结(2 min)   │  核心 takeaway                │
├──────────────────┼─────────────────────────────┤
│  Q&A(5 min)    │  回答问题                     │
└────────────────────────────────────────────────┘

6.3 Demo 驱动的分享方式

Demo 驱动分享(Demo-Driven Presentation)是技术分享中最有效的方式之一。相比纯幻灯片,现场演示更具说服力和感染力。

Demo 准备原则

原则说明
离线优先所有 Demo 都要确保离线可运行
简化依赖减少外部服务依赖,使用 mock 数据
准备截图如果 Demo 出问题,用截图兜底
分步展示用 git stash / branch 切换不同阶段
字体放大IDE 字体调到 18pt+,终端也要放大

Demo 的组织方式

Demo 分步展示策略:

方式一:Git Branch 切换
  main ──── step-1 ──── step-2 ──── step-3 ──── final
  基础代码   添加功能A   添加功能B   优化性能     最终效果

方式二:Git Stash 层层揭示
  stash@{3}: 最终效果
  stash@{2}: 优化后
  stash@{1}: 基础实现
  stash@{0}: 初始代码

方式三:文件夹分版本
  demo/
  ├── v1-basic/
  ├── v2-feature/
  ├── v3-optimized/
  └── v4-final/

6.4 技术幻灯片工具

工具特点适用场景
SlidevMarkdown 编写,Vue 驱动,对开发者友好技术分享首选
reveal.jsHTML/Markdown,功能强大需要高度自定义
MarpMarkdown 编写,极简快速制作
Google Slides协作方便,设计灵活团队协作
KeynoteMac 原生,动画效果好正式场合

Slidev 示例:

markdown
---
theme: seriph
background: https://cover.sli.dev
title: React 性能优化实战
---

# React 性能优化实战

从原理到落地的完整方案

---

## 为什么你的 React 应用很慢?

<v-clicks>

- 不必要的重渲染
- 大量 DOM 节点
- 频繁的状态更新
- 未优化的 Bundle Size

</v-clicks>

---

## 性能分析工具

| 工具 | 用途 |
|------|------|
| React DevTools Profiler | 组件渲染分析 |
| Chrome Performance | 运行时性能 |
| Lighthouse | 综合评分 |
| Bundle Analyzer | 包体积分析 |

七、写作效率工具

7.1 写作工具对比

工具类型优势劣势适合场景
Notion在线协作团队协作强、模板丰富离线体验差、导出格式有限团队文档
Obsidian本地笔记双向链接、插件生态强大协作不便个人知识库
Typora本地编辑所见即所得、简洁优雅功能单一快速写作
VS Code代码编辑器插件丰富、Git 集成非专业写作工具技术文档
HackMD在线协作实时协作、Markdown 原生功能相对少小团队协作
Logseq本地笔记大纲式笔记、双向链接学习曲线陡碎片化记录

7.2 写作辅助工具

文字校对与润色

工具语言功能推荐场景
Grammarly英文语法、拼写、风格检查英文技术博客
LanguageTool多语言开源语法检查中英文混合文档
写作猫中文中文语病、标点检查中文技术文档
Vale多语言可配置的文风检查(CLI)CI 集成文档检查

Vale 在 CI 中集成的示例:

yaml
name: Docs Lint
on:
  pull_request:
    paths:
      - 'docs/**'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: errata-ai/vale-action@v2
        with:
          files: docs/
          reporter: github-pr-check

7.3 绘图工具

绘图工具选择指南:

┌──────────────┬────────────────────────┬──────────────────┐
│  工具         │  特点                   │  最佳用途         │
├──────────────┼────────────────────────┼──────────────────┤
│  Excalidraw  │  手绘风格、协作方便       │  架构图、草图      │
│  draw.io     │  功能全面、免费           │  正式流程图        │
│  Mermaid     │  文本生成、Git 友好       │  流程图、时序图    │
│  PlantUML    │  文本生成、UML 专业       │  UML 类图         │
│  Figma       │  设计工具、精致美观       │  正式的示意图      │
│  tldraw      │  开源、轻量、可嵌入       │  白板草图          │
│  D2          │  声明式、自动布局         │  架构图、网络图    │
└──────────────┴────────────────────────┴──────────────────┘

Excalidraw 的优势

Excalidraw 是目前技术写作中最流行的绘图工具之一,原因如下:

优势说明
手绘风格自动生成的手绘风格让图表更亲切,避免过于正式
实时协作支持多人同时编辑
导出灵活支持 PNG、SVG、JSON
Git 友好JSON 格式可以纳入版本管理
组件库社区有大量现成的技术图标库
嵌入集成可以嵌入到 Notion、Obsidian 等工具中

Mermaid 的实用技巧

在技术文档中使用 Mermaid 的最佳实践:

graph LR
    A[选择图表类型] --> B{数据类型}
    B -->|流程| C[flowchart]
    B -->|时序| D[sequenceDiagram]
    B -->|状态| E[stateDiagram]
    B -->|甘特| F[gantt]
    B -->|类图| G[classDiagram]
    B -->|饼图| H[pie]

Mermaid 的优势在于文本即图表,可以和代码一样纳入 Git 版本管理,在 Code Review 中可以直接看到图表的变更。


八、面试高频问题

8.1 你是怎么做技术沉淀的?

回答思路

这道题考察的是候选人的技术积累意识和总结能力。

回答框架:

1. 日常层面
   ├── Code Review 中记录好的 Pattern 和踩坑
   ├── 每次排查线上问题后写复盘文档
   └── 新技术调研形成对比报告

2. 项目层面
   ├── 项目启动时写技术方案(RFC)
   ├── 重要技术决策写 ADR
   └── 项目结束写技术总结

3. 分享层面
   ├── 团队内部技术分享(月度)
   ├── 技术博客输出(季度)
   └── 公司级技术分享 / 外部会议(年度)

4. 工具支撑
   ├── 用 Obsidian 管理个人知识库
   ├── 建立标签系统和双向链接
   └── 定期回顾和整理

8.2 你写过什么技术文档?

回答思路

不要泛泛而谈,要给出具体的文档类型和产出的效果。

文档类型示例回答
架构文档「我负责的 XX 系统从 0 到 1,我写了完整的架构文档,包括系统上下文、容器图和关键的数据流设计。这个文档后来成为新人上手的必读材料,新人从之前的 2 周上手缩短到 3 天。」
RFC「我主导了从 Webpack 迁移到 Vite 的 RFC,在文档中详细对比了两者的构建速度、生态兼容性和迁移成本,最终获得团队一致通过,构建速度提升了 10 倍。」
Runbook「我建立了前端项目的 Runbook 体系,涵盖白屏、接口超时、CDN 故障等 10+ 个场景,在一次线上故障中,值班同学按照 Runbook 在 5 分钟内完成了回滚。」

8.3 如何保证文档的时效性?

回答思路

保证文档时效性的四个层面:

┌─────────────────────────────────────────────────┐
│                                                 │
│  流程层面                                        │
│  ├── 代码变更时强制更新对应文档(PR 检查清单)       │
│  ├── 定期文档 Review(如每月一次)                 │
│  └── 文档添加「最后更新时间」和「负责人」            │
│                                                 │
│  工具层面                                        │
│  ├── 使用 CI 检查文档中的死链                      │
│  ├── 代码生成的文档(TypeDoc、Swagger)自动更新     │
│  └── 使用 linter 检查文档格式                     │
│                                                 │
│  文化层面                                        │
│  ├── 把文档质量纳入 Code Review 标准               │
│  ├── 鼓励「发现过时文档就更新」的文化               │
│  └── 在团队周会中回顾文档更新情况                   │
│                                                 │
│  架构层面                                        │
│  ├── 文档和代码放在同一个仓库(Docs as Code)       │
│  ├── 使用版本号标记文档适用的版本                   │
│  └── 废弃的文档明确标记而非直接删除                 │
│                                                 │
└─────────────────────────────────────────────────┘

8.4 如何给不同水平的人讲清楚一个技术概念?

回答思路

这道题考察的是沟通能力和读者意识。

核心方法论:

策略说明示例
分层讲解先给结论,再讲原理,最后讲细节「Virtual DOM 就是用 JS 对象模拟 DOM 树」 → 讲 diff 算法 → 讲 Fiber 架构
类比法用生活中的事物类比技术概念「DNS 就像电话簿,把名字翻译成号码」
可视化用图表替代文字描述画数据流图代替口头描述
互动确认分段确认对方是否理解「到这里有没有不清楚的地方?」
适当省略对非技术受众省略实现细节给产品经理讲性能优化时,只讲效果和影响

8.5 你如何看待「代码即文档」这个观点?

回答思路

观点拆解:

「代码即文档」是有条件成立的:

✅ 代码能表达的:
   ├── how:具体的实现逻辑
   ├── what:代码做了什么操作
   └── 结合 TypeScript:接口的类型约束

❌ 代码不能表达的:
   ├── why:为什么选择这种实现而非另一种
   ├── context:业务背景和约束条件
   ├── trade-off:做了哪些权衡
   └── intent:设计意图和未来规划

结论:
  好的代码可以减少文档量,但不能替代文档。
  代码负责 how,文档负责 why。
  两者互补,缺一不可。

8.6 写技术博客对你职业发展有什么帮助?

回答思路

维度帮助具体例子
深度学习教是最好的学,写文章倒逼深入理解写 React Fiber 文章时不得不读源码
技术影响力文章被社区认可,建立个人品牌掘金文章获得 1000+ 收藏
面试加分面试官看到高质量博客会加分简历附上博客链接
工作机会被猎头/团队通过博客找到通过技术文章收到内推
回顾复盘半年后回看自己的技术成长轨迹对比前后文章的深度变化

8.7 你如何推动团队建立文档文化?

回答思路

推动文档文化的四步法:

Step 1: 以身作则(最重要)
  自己先写高质量的文档
  让别人看到文档的价值

Step 2: 降低门槛
  提供文档模板(RFC、ADR、Runbook)
  建立文档站,统一存放位置
  写文档的工具和流程要简单

Step 3: 建立机制
  Code Review 中检查文档更新
  新功能 PR 必须包含文档变更
  技术方案必须写 RFC

Step 4: 正向激励
  在团队中表扬好的文档
  将文档贡献纳入绩效评估
  定期评选「最佳文档」

8.8 你是怎么写技术方案的?

回答思路

技术方案是日常工作中最常写的文档之一,好的回答应该展现出结构化思维。

技术方案写作框架:

1. 背景与目标
   ├── 业务背景:解决什么业务问题
   ├── 技术目标:达成什么技术指标
   └── 范围界定:做什么,不做什么

2. 方案设计
   ├── 整体架构:系统全景图
   ├── 核心模块:每个模块的职责和接口
   ├── 数据模型:关键数据结构
   ├── 接口设计:API 协议
   └── 异常处理:兜底和降级策略

3. 方案对比(如果有多个方案)
   ├── 方案 A 的优劣势
   ├── 方案 B 的优劣势
   └── 选择理由

4. 实施计划
   ├── 任务拆分
   ├── 里程碑
   └── 风险评估

5. 验证方案
   ├── 测试策略
   ├── 灰度方案
   └── 监控告警

九、延伸阅读

推荐书籍

书名作者推荐理由
《The Art of Readable Code》Dustin Boswell提升代码可读性,与技术写作相辅相成
《Docs for Developers》Jared Bhatti 等专门讲开发者文档写作,非常实用
《On Writing Well》William Zinsser非虚构写作经典,适用于技术写作
《中文技术文档写作规范》阮一峰中文技术文档的格式和排版规范
《Style: Lessons in Clarity and Grace》Joseph Williams提升英文写作的清晰度和优雅度

推荐资源

资源类型链接/说明
Google Technical Writing Course在线课程Google 官方技术写作教程,免费
Write the Docs社区全球最大的技术写作社区
中文文案排版指北规范中文排版的最佳实践
Conventional Commits规范Git Commit Message 的标准规范
ADR GitHub Organization模板ADR 的各种模板和工具

写作习惯养成

技术写作能力提升路径:

初级(0-6 个月)
├── 养成写 Commit Message 的好习惯
├── 为自己的项目写 README
├── 记录工作中的踩坑和解决方案
└── 目标:每周输出 1 篇内部文档

中级(6-18 个月)
├── 开始写技术博客
├── 主导团队的 RFC 撰写
├── 建立个人知识管理体系
└── 目标:每月输出 1 篇技术博客

高级(18 个月+)
├── 参与或组织技术分享
├── 为开源项目贡献文档
├── 建立团队文档体系
└── 目标:每季度 1 次技术分享 + 持续博客输出

技术写作不是天赋,而是一种可以通过刻意练习不断提升的技能。从今天开始,从写好每一条 Commit Message 做起,逐步建立起自己的技术写作体系。写得越多,写得越好。

用心学习,用代码说话 💻