技术规格书撰写指南(以 Joplin 开源项目为例)
2026/9/14 14:58:28 网站建设 项目流程

技术规格书撰写指南(以 Joplin 开源项目为例)

【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin

导读:本文面向 Joplin 的开发者、贡献者与 GSoC(Google Summer of Code)参与者,系统讲解如何为 Joplin 项目撰写一份高质量的技术规格书(Technical Spec)。文章完整继承 readme/dev/technical_spec.md 的核心模板——Overview、Problem description、Solution(UX 与技术方案)、Testing plan,并结合仓库中真实落地的规格文档(如 sync.md、e2ee/index.md)与测试基础设施源码,说明每一步该如何写、写到什么深度,帮助你在动手写代码之前先想清楚问题,也让评审者与导师能快速评估你的方案。

什么是技术规格书?

Joplin 开发文档 technical_spec.md 开篇引用了 StackOverflow 博客文章的定义:

A technical specification document outlines how you're going to address a technical problem by designing and building a solution for it. (技术规格书阐述的是:你将如何针对一个技术问题,通过设计和构建解决方案来应对它。)

这份文档本身源自 StackOverflow 的《A practical guide to writing technical specs》一文,但 Joplin 项目认为原模板过于冗长,因此在仓库中提供了一份精简、面向本项目实际需求的定制模板,也就是 readme/dev/technical_spec.md 全文所呈现的内容。凡是想为 Joplin 提出功能改动或修复的贡献者,都被鼓励先按此模板写出规格书,再进入编码阶段。

值得注意的是,Joplin 文档体系中"规格"有清晰的落点:readme/dev/spec/目录下存放着已经完成的各类技术规格文档,例如 sync.md(同步机制)、e2ee/index.md(端到端加密)、editor_commands.md(编辑器命令)、search_sorting.md(搜索引擎排序)等。这些文档正是按本文介绍的模板精神写就的成品范例,后面会反复引用它们作为参考。

为什么写技术规格书很重要?

对工程师的好处

By writing a technical spec, engineers are forced to examine a problem before going straight into code, where they may overlook some aspect of the solution. (通过撰写技术规格书,工程师被迫在直接进入编码之前先审视问题,否则可能会忽视解决方案的某个方面。)

这份"先思考、后编码"的纪律在 Joplin 的贡献流程中被制度化:根据 readme/dev/index.md 的"Contribution scope"一节,项目只接受解决一个具体、已被认可的问题的 Pull Request,且要求遵循"识别问题 → 讨论并被维护者接受 → 问题被打上标签 → PR 针对已认可的方案"的流程。换句话说,规格书正是"讨论并被接受"这一环节的载体;没有清晰的规格,PR 往往会被直接关闭。

对项目的好处

Investing in a technical spec ultimately results in a superior product. Since the team is aligned and in agreement on what needs to be done through the spec, big projects can progress faster. (在技术规格书上的投入最终会带来更优质的产品。因为团队通过规格书对齐并达成共识,大型项目可以进展得更快。)

Joplin 是一个横跨桌面(Electron + React)、移动端(React Native)、CLI(terminal-kit)与服务端(Node.js + PostgreSQL)的多端项目,各应用共享同一套后端逻辑(数据库、同步、设置、模型)。在这样的代码库中,一次改动往往牵动多个应用,规格书带来的"团队对齐"价值尤为突出——这一点在 readme/dev/spec/architecture.md 的架构描述中可以得到印证:任何对后端(packages/lib)的改动都需要保证在桌面、移动、CLI 各端仍然可用,而规格书正是确保这种跨端共识的工具。

技术规格书模板(Joplin 定制版)

以下是 technical_spec.md 提供的完整模板,共四个小节。下文将对每个小节进行逐项展开,并配合 Joplin 仓库中的真实文档、源码与测试作为示范。

1. Overview(总览)

要求

  • 用户视角出发(永远如此):用户面临的具体问题是什么?
  • 尽可能提供上下文,并附上相关论坛帖或 GitHub issue 的链接。
  • 然后概述你打算如何解决该问题。此阶段不要进入技术细节(不写代码、不写文件名)。

写作要点与仓库示例

以 readme/dev/spec/sync.md 为例,它一开篇就用一段朴素语言描述了用户场景:"Joplin 应用是离线优先的(offline first)——数据保存在本地设备上。为了让用户所有设备上的数据一致,我们使用同步流程。简而言之,每台设备把笔记、笔记本、标签等上传到服务器,同时下载自己缺失或最近变更的数据。"这就是典型的 Overview 写法:先说清楚用户在多个设备间保持数据一致的问题,再给出"同步流程"这一解决思路,全程没有涉及具体类名与代码。

在 Joplin 的实践中,"附上论坛/Issue 链接"尤其重要,因为项目的功能请求必须在论坛讨论并被接受后才会进入 GitHub tracker(见 readme/dev/index.md 的 "Feature requests" 一节)。因此你的 Overview 中引用的链接,应该优先指向已经被社区讨论过的论坛主题。

2. Problem description(问题描述)

要求

  • 提供需要解决问题的更多细节,可以给出用户故事(user stories),或引用论坛帖中的原话。
  • 这一节的目标还包括:解释为什么这个问题值得解决

写作要点

这一节是 Overview 的深化。Overview 是"电梯陈述",Problem description 则是"完整案情"。你要把问题的表象、影响范围、受影响用户群讲透,并说明不解决它会带来什么代价。

例如在 readme/dev/spec/sync.md 的"Vocabulary"(术语表)部分,它先把"客户端(Clients)""同步目标(Sync targets)""条目(Items)"三个核心概念定义清楚——这本身就是问题描述的基础:如果没有统一的术语,评审者与实现者之间的讨论会陷入混乱。术语澄清、范围界定、用户故事,都是让"问题值得解决"变得有说服力的材料。

3. Solution(解决方案)

3.1 User experience(用户体验)

要求(再次强调:永远从用户视角出发):

  • 用户界面看起来会是什么样?
  • 用户要执行哪些操作来使用这个功能?
  • 尽可能详细:新增的 UI 元素(按钮、列表等)会放在哪里?
  • 按钮或工具提示(tooltip)如何命名?
  • 如果要增加键盘快捷键,用户应该按下哪些按键?

为什么这些细节如此重要:文档原话指出——

All these details are very important because they give a clear picture of what you are going to do, and it helps reviewers assess the implementation. (这些细节非常重要,因为它们能清晰描绘你将要做什么,并帮助评审者评估实现方案。)

It's also an easy way for everybody, even non-technical people, to get involved and help you refine your spec. (这也是让所有人——甚至非技术人员——都能参与进来、帮助你完善规格书的便捷途径。)

如果可能,请附上一份 UI 线框图(UI mockup)。

仓库范例:readme/dev/spec/editor_commands.md 对桌面与移动端编辑器命令的"用户操作"层面做了细致区分:移动端有"编辑器命令"与"笔记屏幕命令"两类,运行于不同的上下文;桌面端则由各编辑器类型注册自己的命令处理器。即便是一篇偏底层的规格,它依然先交代清楚"命令由谁触发、在什么上下文运行",这正是 UX 思考在技术规格中的体现。

3.2 Technical solution(技术方案)

要求

  • 从技术层面概括说明你将如何解决这个问题。
  • 描述你的改动会带来的影响与风险。例如:如果只是添加一个改变文本格式的按钮,很可能影响较低;如果是修改同步算法,则影响很高——因为存在数据丢失的可能。
  • 说明你需要修改哪些服务或应用部件,以及如何修改。
  • 本小节可以提及代码和文件名,但尽量不要写太深的技术细节——这些细节往往很快就过时,不像规格书的其余部分那样持久。

仓库范例与源码佐证

Joplin 的规格文档在"技术方案"上有着清晰的分层叙述传统。以 readme/dev/spec/sync.md 的 "Code architecture" 一节为例,它精确地指出同步涉及的文件层级:

  • packages/lib/Synchronizer.ts:负责同步主流程,下载、上传、应用删除,并通过接收SyncTarget对象处理目标特有操作,E2EE 开启时还负责加解密条目;
  • packages/lib/SyncTarget*.ts:各同步目标的入口,暴露名称、描述、支持选项等元数据,主要职责是初始化FileApi实例;
  • packages/lib/file-api-driver-*.ts:文件 API,实现通用的创建、更新、删除、列出等文件操作;
  • packages/lib/*Api.ts:底层 API 封装(如 JoplinServerApi.ts 用于连接 Joplin Server);
  • packages/lib/BaseModel.tsBaseItem:数据库对象的模型抽象与同步工具类;
  • sync_items数据库表:保存sync_timesync_disabledsync_target等同步状态属性。

这就是"技术方案"小节的理想形态:在文件与模块的粒度上说明改动范围与调用关系,而不是粘贴大段实现代码。文档自己也提醒:过细的实现细节会迅速过时,保留在模块/接口层面的描述才具有长期价值。

另一份典范是 readme/dev/spec/e2ee/index.md,它在"Encryption workflow"中说明"条目仅在同步序列化时(BaseItem.serializeForSync)被加密,解密由后台的 DecryptionWorker 完成"——一句话就划清了加解密在同步链路中的位置,以及它给用户带来的行为(加密条目对用户基本只读、可删除)。这就是"影响与风险"的具象化表述。

4. Testing plan(测试计划)

要求

  • 你计划如何测试你的改动?
  • 尽可能提供单元测试(unit tests)。
  • 如果是GSoC 项目,单元测试是强制要求——没有单元测试的 PR 不会被接受。
  • 关于如何编写单元测试,参见 readme/dev/index.md 的"Automated Tests"一节。

仓库中的测试基础设施(深化佐证)

Joplin 使用Jest作为测试框架。根据 readme/dev/index.md,测试的组织与运行方式如下:

  • 在仓库根目录运行yarn test可执行全部单元测试;也可以进入某个包目录(如packages/lib)后运行yarn test只测该包;
  • 运行单个测试文件:yarn test markdownUtils(匹配文件名);
  • 运行文件中的单个用例:yarn test markdownUtils --filter="should handle conflict"
  • 新增测试文件的约定:在源码同目录下创建以.test.ts结尾的文件,例如为example.ts创建example.test.ts;文件已存在则直接追加用例。仓库中可以看到大量范例,如 packages/lib/markdownUtils.test.ts、packages/lib/Synchronizer 配套的同步测试 等;
  • 需要数据库与同步器支持的测试,可以使用@joplin/lib/testing/test-utils包提供的工具(参考 packages/lib/models/Note.test.ts);只测纯函数的简单用例则无需这些额外装配;
  • 测试 React Hooks 时使用@testing-library/react-hooks(参考 useLayoutItemSizes.test.ts)。

如果确实无法写单元测试怎么办?文档给出的建议非常务实:绝大多数情况下其实是可以写测试的——把代码重构一下,将某些功能抽成无依赖的纯函数,就能轻松为它添加单元测试。如果单元测试仍不足够,请提供一份手动测试计划(manual testing plan),要求包括:

  • 如何验证你的功能正常工作:至少包含 5 个测试用例,并考虑各种可能的输入边界——如果是列表,0 个元素、1 个、10 个、100000 个分别如何工作;如果是文本输入,空字符串、超长字符串如何处理。不要只写一个"最佳路径"的用例。
  • 如何验证相关应用部件未被破坏:例如你改了笔记加载逻辑,就要检查工具栏仍正常工作、切换笔记仍然正常、笔记列表标题仍然同步更新等。

评审者应当能够用你的改动运行应用,然后按照上述步骤逐一验证。

同步测试的专项说明:对于像同步这类高风险模块,readme/dev/spec/sync.md 的 "Testing" 一节提供了更具体的测试方法——默认情况下,测试单元使用内存同步目标(in-memory sync target),速度快且足以验证大部分行为;如果需要针对文件系统、Nextcloud、Joplin Server 等特定同步目标测试,可以修改 packages/lib/testing/test-utils.ts 中的setSyncTargetName(),并可能需要维护~/joplin-credentials/*下的凭据文件。这为规格书中的 Testing plan 提供了"项目认可"的测试方式参考。

在 GSoC 语境下的规格书

这份模板在 Joplin 的 GSoC 项目中扮演着关键角色。从 readme/dev/gsoc/gsoc2024/index.md 可以看到:

  • 候选人被要求必须先在论坛提出想法、获得讨论,提案应明确问题、目标、实现方案、时间线与个人介绍;
  • 技术规格书质量直接关系到 PR 能否被接受:文档明确指出,如果一个 issue"需要一个非常清晰的技术规格",而 PR 里还要讨论"它应该如何工作、应该做什么",就说明该功能没有共识,PR 很可能被关闭;
  • 单元测试在 GSoC 期间是强制要求,且"写作单元测试和代码文档不能拖到最后几周",应贯穿编码全程——这与 technical_spec.md 中 Testing plan 小节的立场完全一致。

因此,把本文介绍的模板用扎实,等于同时满足了"给维护者的规格文档"与"GSoC 提案的 Implementation 部分"两份交付物的质量要求。

写在最后:模板使用的原则

综合 technical_spec.md 全文,可以提炼出三条贯穿始终的原则:

  1. 永远从用户视角出发——Overview 与 UX 小节都反复强调这一点,它是评审者理解方案的最短路径,也是非技术参与者介入讨论的入口;
  2. 在合适的小节放合适深度的细节——Overview 不提技术,Problem description 讲清价值,UX 小节写全交互细节,Technical solution 停在模块与文件层面、着重讲影响与风险,避免会迅速过时的实现级细节;
  3. 测试计划是规格的正式组成部分——尤其是 GSoC 场景下,单元测试是硬性门槛;写规格时就把测试策略规划进去,而不是等代码完成后再补。

当你准备为 Joplin 提交新功能或修复时,可以参考 readme/dev/spec/ 目录下的既有规格文档(同步、E2EE、编辑器命令、搜索排序、无障碍焦点管理等)作为范文,再对照本文介绍的模板逐节填写,即可产出一份让维护者、导师与同行评审都能快速理解并给出反馈的高质量技术规格书。

【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询