README 是你这辈子会写的回报最高的一份项目文档,而我们大多数人把它当成出门顺手做一下的形式主义。这就反了。README 是新同事、未来的你、或者互联网上某个陌生人读到的第一样东西,它只有一个任务:尽快把人从「这是什么」带到「它跑起来了」。任何没有让这段旅程变短的句子,都是在跟你的开发者体验作对。快速上手不是一个章节——它就是 README 本身,其余一切都是支撑材料。
我写过很多份,也亲眼看着人们被我自己写砸的那些劝退。一份会被读到底的 README,和一份被扫两眼就关掉的 README,差别很少在文笔上,而在顺序,以及愿不愿意删。
README 的任务:从「这是什么」到「它跑起来了」
README 是一个只有一个转化目标的漏斗:有人带着模糊的疑问进来,带着一个跑起来的东西离开。不是理解了,是跑起来了。理解是更靠后得多的阶段,不该花掉 README 的预算。
换这个视角,你就知道该写什么了。营销式描述(「极速、云原生、下一代……」)不会把人推过漏斗。五百字的设计理由也不会。一条能跑的命令会,而且是立刻。用一个问题去衡量每一段:它有没有让从 clone 到跑起来的路变短? 如果没有,那它要么该放到底部,要么该挪进 docs/,留给已经在跑它的人去找。
真正重要的章节,以及它们的顺序
七个章节,就按这个顺序。顺序就是全部诀窍——它按紧迫程度递减排列,而不是按重要性排列。
- 一句话说明它是什么。 名称,然后一句话:它是什么、给谁用。
- 它为什么存在。 两三行,讲促使你动手的那个问题、以及它替代了什么。这里是回答「我到底该不该用它」的地方——这是读者会最先问的是非题。
- 能真正跑起来的快速上手。 唯一一个你不许造假的章节。后面细说。
- 配置。 所有旋钮、它们默认值、哪些是必填的。用表格,不用散文。
- 架构草图。 几行字或者一张小图:有哪些活动部件,数据怎么在它们之间流动。够给一次改动定个方位就行。
- 坑。 已知限制、暗礁、「暂时别用在生产」。这里的坦诚能替你省下好几个小时。
- 许可证。 一行加一个链接。永远别把它埋起来;人们是拿它当筛选条件的,几秒钟就扫过去。
如果你有这七节、别的什么都没有,你已经有一份好 README 了。大多数 README 失败,不是因为章节太少,而是因为这七节顺序错了,快速上手被埋到了第九十行。
在第一屏里放一条真命令
最常见的失败:第一屏是徽章、logo、功能列表,没有命令。读者往下滚,找不到任何能执行的东西,关掉标签页。
把一条真实的、可复制的命令放到首屏之上。 不是片段,不是 <your-token> 这种占位符,也不是「见 wiki」的链接。要一条能被人粘进终端、眼看着它做点什么的命令。哪怕只有三行,它也证明了项目是活的、你尊重读者的时间。读者用来决策的一切放首屏之上;用来操作的一切放下面的。
一份真能跑起来的快速上手
大多数 README 就是在这里悄悄撒谎的。这是坏版本,我自己写过不止一次:
# 坏 —— 读起来像快速上手,跑起来像寻宝游戏
# 1. 为你的平台安装依赖。
# 2. 配置你的数据库连接。
# 3. 设置必需的环境变量。
# 4. 启动服务并打开浏览器。
# 详见 wiki。
每一行都是一个脚注。「你的平台」是一个我没替你做的决定。「必需的环境变量」是一张你没给我的清单。读者得先去读另外四份文档,第一条命令才会做任何事——也就是说,这一节谁也没转化。
现在看好版本——就是我在提交前,会在干净机器上真测一遍的那份:
# 好 —— 全新 clone 到跑起来的服务,复制粘贴,无需编辑
git clone https://github.com/acme/widgets.git
cd widgets
cp .env.example .env # 仓库里带的默认值在本地开发时就能用
docker compose up --build # 首次构建慢(约 90 秒);之后启动只要几秒
# → 打开 http://localhost:8080/health,应返回 {"ok":true}
四行,没有需要你做的决定,还写明了预期输出。没错,docker compose 是一个选择——但它是替读者做的选择,不是丢给他们的。如果你有多种安装路径,挑一个当默认,其余塞进折叠区。一份给出三个同等权重的选项的快速上手,是一份谁都跑不起来的快速上手。
好版本的门槛很简单,就是下一节。
标准是「在全新 clone 上能跑」
在你说 README 写完之前,把自己仓库 clone 到一个全新目录,用干净的 shell,照着你自己写的快速上手,出声地跑一遍。不能有残留的 .env,不能有两年前全局装好的工具,不能有你忘了的 node_modules。就这一套仪式,几乎能抓到所有快速上手的坑:
- README 假设存在、却根本没提交的
.env.example。 - 装在你笔记本上、却没写进「依赖要求」的工具。
- 一个你自动就会做、于是忘了写下来的步骤。
如果它在全新 clone 上跑不起来,那它就是跑不起来——而每个读者都会撞上你刚撞上的那堵墙,还没有你爬过去的上下文。这和读一个代码库是同一种精神:诚实的检验是跑,不是读。
配置:把旋钮列清楚
配置属于表格,不属于段落。每个旋钮都要有名字、默认值,和一行说明。必填的值标成必填。这是读者会反复回来查的章节,所以要为扫读优化,而不是为阅读:
| 变量 | 默认值 | 含义 |
| --- | --- | --- |
| `PORT` | `8080` | HTTP 监听端口 |
| `DATABASE_URL` | —(必填) | Postgres 连接串 |
| `LOG_LEVEL` | `info` | 设为 `debug` 输出详细日志 |
如果某个值是必填的,就直说,并给个例子。如果有默认值,就把默认值写出来。没有什么比一份只列了变量名、却不告诉你留空会怎样的配置说明更浪费时间了。
一份架构草图,而不是架构图
你不需要完整的 C4 图。你需要在十秒内给陌生人定方位:三到五个活动部件,以及数据怎么在它们之间流动。带箭头的散文常常就够了——「web 处理 HTTP,把任务推进队列,worker 把队列排进 Postgres」——而当部件超过四个时,一张小方框加箭头图就值回票价。细节指向 docs/;README 里的草图是通往代码的地图,不是代码的清单。
坑:把锋利的边角写下来
README 里最值钱的几行,往往是告诉你它在哪里坏掉的几行。已知限制、不明显的暗礁、「X 场景下还别上生产」、「首次运行会做数据库迁移,所以别同时跑两个实例」。这些每一条,都是一个你以后永远不用收到的 bug 报告。把它们写下来不是示弱;它是给你自己的项目做「防新人杀手」,更重要的是,它决定了读者是相信文档的其余部分,还是在凌晨两点在生产里撞上那个锋利的边角。
该删掉什么
跟放进去什么同样重要。以下默认砍掉:
- 没人点的徽章。 构建状态、覆盖率、「用爱打造」。它们是首屏上的视觉噪音,还把命令往下推。留一个贡献者真会据此行动的,其余全删。
- 代码截图。 终端截图搜不到、复制不了,而且拍完第二天就过期。把文本贴上来。
- 一整面功能墙。 README 不是落地页。十条能力清单,就是在快速上手之前给自己十次失去读者的机会。一句是什么,顶多再加三条为什么。
- 完整的 API 参考。 那属于自动生成的文档,不属于 README。链过去,别内联。
- 「即将推出」。 它设定了一个没有交付日期的期待。要么它有,要么它没有。
写给未来的自己
最难写的读者,是六个月后、在新机器上、把一切都忘光了的你。那个人才是真正的受众,而他没有你现在的心智模型——只有摆在面前的那个文件。这就是为什么「全新 clone」检验连单人项目也要做:凌晨三点硬盘挂了之后,去 clone 它的正是你自己。README 是你这辈子会上线的最便宜的一套上手流程,而它的第一个受益人就是写它的那个人。从这个意义上说,它是版本控制卫生的近亲——单人开发者的 git 习惯和一份好 README 是同一种本能:给下个版本的你留够面包屑,让你能走回能跑的代码。
一份可直接复制的 README 模板
从这里起步,不适用的就删。忍住别加章节。
# project-name
一句话:它是什么、给谁用。
两三行讲它为什么存在——它解决什么问题、替代了什么。
## Quickstart
要求:Docker 24+,或 Python 3.11+ 配一个 Postgres 15 的连接串。
git clone https://github.com/acme/project.git
cd project
cp .env.example .env
docker compose up --build
打开 http://localhost:8080 —— 你应该看到登录页。
## Configuration
| 变量 | 默认值 | 含义 |
| --- | --- | --- |
| `PORT` | `8080` | HTTP 监听端口 |
| `DATABASE_URL` | —(必填) | Postgres 连接串 |
| `LOG_LEVEL` | `info` | 设为 `debug` 输出详细日志 |
## Architecture
三个进程:`web`(HTTP)、`worker`(队列)、`db`(Postgres)。
数据流:web → 队列 → worker → db。详见 `docs/architecture.md`。
## Gotchas
- 启动时会跑迁移;别拿两个实例连同一个数据库。
- `send-email` 任务不是幂等的——重试可能重复发送。
## License
MIT —— 见 `LICENSE`。
复制它,填上内容,然后做那件让它成真的事:开一个全新终端,clone 自己的仓库,照着自己的快速上手跑,直到它跑起来。项目文档不是做完一次就完事的苦差。它是你的项目和所有会碰它的人(包括你自己)之间的接口——而一份能让人在一屏之内从「这是什么」走到「它跑起来了」的 README,已经把开发者体验里被记功的大部分活儿都干完了。