15

上一章

如何构造 SSOT 九层金字塔模型:一套可复用的 SSOT 原则

一套不依赖具体业务的 SSOT 构造方法:从使命、战略、承诺一路落到 Flow、contract、实现和 evidence。

Cover Image for 如何构造 SSOT 九层金字塔模型:一套可复用的 SSOT 原则

不要从“要建几个目录”开始设计 SSOT 九层金字塔模型。先问一个更尖锐的问题:当战略、产品、代码、测试和发布证据发生冲突时,团队用什么规则判断谁才是当前事实?

如果这个规则说不清,目录越多,事实越分裂;文档越勤奋,AI 和人越容易读出多个互相矛盾的系统。

这篇文章只讲构造方法。它不依赖某个具体产品,也不要求你照搬我的目录结构。它要解决的是一个更通用的问题:

一个复杂软件团队,如何构造自己的 SSOT 九层金字塔模型?

如果你想先理解为什么我认为所有软件工程原则最后都在谈 SSOT,可以先读上一篇:

SSOT:为什么所有软件工程原则最终都在谈同一件事

下面只讲方法:根目标是什么,九层分别是什么,团队怎么自顶向下阅读、自底向上更新,以及如何避免文档、代码、测试、日志、发布证据在不同历史阶段里互相打架。

根目标

SSOT 九层金字塔模型不是一张新的系统组件图。

它要把产品目标、当前战略、对外承诺、体验流程、领域模型、系统边界、接口契约、代码实现和证据闭环放进同一个可追踪模型里。

它关心的不是“系统有哪些模块”,而是这些问题:

  • 这个产品为什么存在?
  • 当前阶段优先赢什么?
  • 团队对用户和自己承诺什么?
  • 真实任务如何完成?
  • 稳定概念和不变量是什么?
  • 系统边界在哪里?
  • 可执行 contract 是什么?
  • 代码如何实现?
  • 什么 evidence 证明这些事实成立?

一句话概括:

SSOT 九层金字塔模型是团队业务、产品、技术决策的 up-to-date snapshot。

它的作用,是让人和 AI 给所有进入思考范围的事务和概念定位。

它也给非开发同事一张共同地图:当前战略是什么,哪些能力可以承诺,真实 workflow 如何运转,哪些 evidence 能证明它们。这样大家不用从会议、旧计划和某个工程师的即时回答里拼当前事实。

九层定义

层级核心问题典型 SSOT
L1 使命产品为什么存在?长期要成为什么?使命文档、公司级产品叙事
L2 战略当前阶段优先赢什么?资源如何分配?当前优先级、资源竞争、路线图
L3 承诺对用户和团队承诺支持什么?对外文案、支持边界、发布声明
L4 Flow所有利益相关方如何完成真实任务?用户流程、AI agent 流程、产运研流程、发布流程、客服/支持流程
L5 领域模型稳定概念、状态、权限、计费和不变量是什么?领域对象、状态归属、权限、计费规则
L6 系统边界入口、能力、runtime、云端产品面、外部服务如何分工?架构边界图、调用方向、职责约束
L7 Contract接口、数据库、环境变量、权限、发布流程的合同是什么?API、数据库、环境变量、权限、发布合同
L8 实现代码、脚本、迁移、组件、自动化如何落地?代码、脚本、迁移、自动化、配置
L9 Evidence测试、日志、检查、发布证据如何证明前面八层成立?测试、日志、状态检查、发布证据、线上事实

越往上,越接近“为什么”和“对外承诺”;越稳定,越少变,改变时越需要谨慎。

越往下,越接近“怎么实现”和“怎么证明”;越具体,越多变,越依赖自动化和 evidence。

唯一顶层模型

团队需要一个顶层模型。否则每个人都会自然带着自己的模型进来。

在我的做法里,这个顶层模型就是 SSOT 九层金字塔。

专题文档当然可以存在,比如架构文档、工作计划、运维文档、设计文档、测试文档。但它们不能各自长成一套平行的事实系统。每个专题文档都要声明自己主要属于哪一层、服务哪些层、记录的是稳定事实还是当前工作、由什么 evidence 证明。

否则,一个团队很快就会拥有多套互相竞争的解释框架:

  • 架构文档说一套。
  • 产品路线图说一套。
  • 测试文档说一套。
  • 发布文档说一套。
  • 会议纪要又说一套。

人会读混,AI 会把它们综合成一个看起来合理、实际错误的结论。

阅读必须自顶向下

任何人或 AI 理解一个问题时,都先自顶向下走:

  1. 先确认使命。
  2. 再确认当前战略。
  3. 再确认对外承诺。
  4. 再确认真实 Flow。
  5. 再确认领域模型。
  6. 再确认系统边界。
  7. 再确认 contract。
  8. 最后才进入实现和 evidence。

这条规则防止团队用代码细节反向定义产品,也防止 AI 读到某个局部文件后误以为它代表全局。

对产品、运营、销售、客服/支持同事来说,这条规则也能防止旧方案、过期发布说明或 legacy 排查路径被误当成当前战略或当前承诺。

举个判断方式:

  • 如果一个页面还在,不能说明它仍是当前战略。
  • 如果一个接口还在,不能说明它仍是用户承诺。
  • 如果一个测试还在跑,不能说明它仍保护当前主线。
  • 如果一个 POC 能跑,不能说明它已经是产品能力。

任何局部事实,都先回到金字塔里定位。

更新必须自底向上

改动落地时,顺序反过来,自底向上走:

  1. 先更新代码、脚本、数据库、配置、自动化。
  2. 再更新测试、日志、状态检查、发布证据。
  3. 如果实现变化改变了可执行 contract,再更新 contract 层。
  4. 如果 contract 改变了组件分工、状态归属或跨边界调用,再更新系统边界和领域模型。
  5. 如果领域或边界变化改变了用户、AI agent、发布 operator、客服/支持、销售或开发者可以依赖的能力,再更新 Flow 和承诺。
  6. 如果承诺变化改变了资源选择或长期产品身份,再更新战略和使命。

只有底层变化真的改变了上层语义,才修改上层文档。

这条规则能挡住一种很常见的冲动:因为一个小脚本、一次 demo、一个临时客户需求,就把 POC 过早提升成战略。

Read top-down, update bottom-up

反例和正确做法

下面这些不是罕见事故。复杂团队每天都会遇到类似的事实分裂。

场景错误做法九层落点正确做法
AI agent 读到旧 README让 agent 从最近文件开始,自行综合旧战略、新代码和旧测试L2 战略:当前核心能力;L4 Flow:agent 阅读顺序;L8/L9:旧 README 和旧测试是否仍属于当前实现/evidence先更新 L2 和 L4,让 agent 明确从九层入口开始;再把旧 README 和旧测试在 L8/L9 标成 legacy、改成链接,或删除
POC 被写进 BP 或官网只要 demo 能跑,就把能力写成“已支持”L3 承诺:是否可对外承诺;L7 Contract:输入、状态、失败语义;L9 Evidence:发布证据;必要时 L2 战略:是否成为资源优先级只有 L3 写清支持边界、L7 有可执行 contract、L9 有 release evidence 后,才允许进入 BP、官网、demo 和销售话术
skill 已升级为 workflow,但命名没变继续保留旧字段、旧日志、旧测试名,靠口头解释新语义L5 领域模型:workflow 是否是一等概念;L7 Contract:字段/API 语义;L8 实现:符号、schema、日志名;L9 Evidence:测试断言先在 L5 改领域中心,再同步 L7-L9 的命名、contract、日志和测试;不能只靠口头说明新语义
内部 API 被多个入口依赖仍按内部实现随意改字段L6 系统边界:谁拥有 API、谁调用;L7 Contract:schema、调用方、变更规则;L9 Evidence:contract test 或调用证据;必要时 L4 Flow:agent/operator 是否依赖它把 API 从 L8 实现提升到 L7 contract,并补 L6 调用边界和 L9 证据;字段变更必须按 contract 变更处理
测试入口越来越多testcheckverifyci 都存在,但没人知道谁证明发布L9 Evidence:每个入口证明什么事实;L8 实现:根命令和 CICD 配置;L4 Flow:发布前谁运行;L3 承诺:哪些检查支撑公开承诺收敛测试入口,在 L9 写清证据类型,在 L8 保留少数命令,在 L4 写入发布流程;只有支撑 L3 承诺的检查进入 release gate
日志和错误文案停留在旧概念新主线是 workflow,日志仍写 skill failedL5 领域模型:错误属于 workflow 还是 skill;L8 实现:日志、错误文案、事件名;L9 Evidence:可观测性证据;L4 Flow:客服/支持和 agent 的排查路径先在 L5 定义当前故障语义,再更新 L8 日志和错误文案、L9 查询证据、L4 排查流程,保证所有角色查同一类事实
迁移计划完成后还留在 current-work三个月后读者以为迁移仍未完成Current work:删除或压缩计划;L5/L7:稳定领域和 contract 结论;L8:最终实现位置;L9:关闭证据迁移完成后,把稳定结论提升到 L5/L7/L8/L9,current-work 只保留关闭记录或直接删除,不让计划继续当事实入口
临时 adapter / fallback 变成事实来源为快速发布保留兼容层,后来新功能反而依赖它L6 系统边界:adapter 是否是正式边界;L7 Contract:兼容 contract 是否存在;L8 实现:临时代码 owner 和退出条件;L9 Evidence:删除或失败证据;必要时 L3:是否影响承诺如果需要临时层,必须在 L6-L9 写清 owner、退出条件、删除时间和验证方式;不需要兼容时 fast fail,避免 fallback 成为新事实源

这些例子的共同点是:局部事实没有回到金字塔定位。

解决它们不能只靠“大家多沟通”。每次都要回答三个问题:应该更新哪一层,那一层里的哪类事实变化了,有什么 evidence 证明变化完成。

No layer bypass: climb one layer at a time

上层约束下层,下层证明上层

上层不能写成愿望清单,下层也不能随意实现。

使命约束战略,战略约束承诺,承诺约束 Flow,Flow 约束领域模型,领域模型约束系统边界,系统边界约束 contract,contract 约束实现,实现必须被 evidence 证明。

反过来,下层不能只“存在”。实现细节要通过测试、日志、状态检查、发布证据支撑 contract;contract 和 evidence 要共同支撑边界、领域、Flow、承诺和战略。

公开承诺如果找不到 evidence,就还只是愿望。

每一层必须有自己的入口

每一层都应该有自己的目录或文档入口。不要把所有正文继续堆进单篇总览文档。

总览文档只负责解释层级关系和阅读入口,不承载每一层的完整正文。否则总览会变成第二套事实来源。

一个可行的最小结构是:

docs/
  README.md
  L1-mission/
  L2-strategy/
  L3-promise/
  L4-flow/
  L5-domain-model/
  L6-system-boundary/
  L7-contract/
  L8-implementation/
  L9-evidence/
  working-plan/
  architecture/
  operations/
  testing/

这个目录结构不用照搬,但每个团队都应该有等价的事实归属。

当前工作和稳定事实必须分开

稳定事实进入对应层,或进入由某一层拥有的专题文档。

当前计划、临时调查、待关闭事项,放进 current-work 区域。它们要说明当前问题、负责人、下一步关闭动作和删除条件。

计划完成并通过 evidence 闭环后,只把稳定结论提升到对应层。计划文件删除或压缩,不要继续占据主视野。

不要让已完成计划、历史流水账和过期 checklist 长期留在主视野里。

专题文档族必须声明归属

复杂团队一定会有专题文档,比如:

  • 架构文档:系统结构、runtime、适配器、边界。
  • 工作计划:当前优先级、负责人、资源竞争。
  • 运维文档:发布证据、外部平台事实、巡检和风险。
  • UI 文档:体验、界面、设计实现参考。
  • 测试文档:测试入口、证据等级、触发边界。
  • 客服/支持文档:用户问题、日志证据、修复路径。

这些专题文档可以保留自己的组织结构,但要声明:

  • Layer owner:主要归属哪一层。
  • Feeds / Affects:向哪些层提供事实或影响哪些层。
  • Stability:稳定事实、当前工作、evidence,还是设计参考。
  • Exit / Promotion:如果是计划或临时材料,完成后提升到哪里。

专题文档本身不是问题。没有归属的专题文档,才会慢慢变成另一套顶层事实系统。

如果文档冲突,先找 SSOT

如果两份文档冲突,先找明确 SSOT。

如果没有明确 SSOT,可以临时参考更新时间更晚、且更靠近事实源的文档。但这只是临时判断,不是长期制度。长期做法是补上 SSOT,并把冲突文档改成链接、引用或删除。

尤其要警惕这些词:

  • 当前重点。
  • 当前优先级。
  • 核心能力。
  • 已支持。
  • 已发布。
  • 主线。
  • 暂停。
  • 候选。
  • legacy。

这些词只要分散在多份文档里,就会天然制造脑分裂。

Many doors converge into one entry per layer

入口、路径和概念默认收敛

模块、工作流、命令、文档和治理入口都要默认收敛。不要让它们自然增长成多套并行路径。

新增入口、路径或概念前,先回答:

  • 为什么现有 SSOT 不能承载?
  • 谁负责触发?
  • 由什么 evidence 证明?
  • 是否能由 CICD 或 AI 自动执行?

同一类工作只保留少数名实相符的入口。旧入口、别名、临时路径和过期概念,删除或重命名。不要为了“以防有人记得”长期保留兼容层。

人只应该处理真正需要人的事

人应该关注目标、范围、业务审批、权限授权、真实成本决策和最终判断。

流程执行、验证选择、证据收集、发布推进、常规治理检查,默认交给 CICD 或 AI。

AI agent 不只是执行者,也应该主动发现认知负担、重复入口、手工步骤和自动化缺口,并提出如何让人更少主动告知。

但流程优化会改变团队默认行为,要先得到明确审批。审批通过后,再同步修改 contract、实现、文档和 evidence。

所有事实都要降低认知负担

一个事实是否值得进入长期文档,要看它是否降低未来读者和 AI 的认知负担。

长期文档写当前事实,不复述无用历史过程。历史过程放在明确的日志、发布证据、审计记录或 current-work 计划里。

好的文档应该让第一次阅读的人尽快理解最新现状,而不是逼读者先读完整演化史。

Evidence 不是文档

文档可以说明事实,但文档本身不是 evidence。

能证明事实的是:

  • 测试。
  • 日志。
  • 状态命令。
  • 线上只读检查。
  • 发布清单。
  • 批准记录。
  • 发布 evidence。
  • 真实 provider 或真实用户路径的验收。

公开承诺找不到 evidence,就还只是愿望。

仓库覆盖从底层事实开始

构造 SSOT 九层金字塔模型时,不要把每个文件内容复制进九层文档。

更好的做法是先从底层盘点:

  1. 代码、脚本、workflow、schema、子模块、本地配置、vendor reference、临时资产分别是什么。
  2. 这些事实有什么 evidence:测试、smoke、发布证据、状态命令、外部服务健康检查,还是仅仅 inventory。
  3. 哪些事实改变了 contract。
  4. 哪些 contract 改变了边界或领域模型。
  5. 哪些领域或边界改变了 Flow 或承诺。
  6. 哪些承诺改变了战略或使命。

SSOT 九层金字塔模型追求的不是“文档覆盖所有细节”。它要保证每个重要 surface 都有明确归属和提升路径。

SSOT 九层金字塔模型的自底向上提升路径

图:不是所有底层事实都会升级。只有当 evidence、contract、边界、领域、Flow 或承诺真的改变时,才逐级提升到上层。

每次任务结束都要检查文档是否需要更新

每次完成开发、发布、排查或文档任务,都要检查:

  • 是否有稳定事实变化?
  • 是否有当前计划完成?
  • 是否有承诺被扩大或缩小?
  • 是否有 Flow、领域、边界、contract、实现或 evidence 变化?
  • 是否有旧文档需要删除、压缩或改成链接?

文档要持续反映当前事实。否则它很快就会从 SSOT 变成噪音。

一份最小落地清单

如果你想给自己的团队落地 SSOT 九层金字塔模型,可以从这个最小清单开始:

  1. 建立九层入口,不需要一开始写很长,但每层必须有 owner。
  2. 建立一个 current-work SSOT,只放当前仍未关闭的问题。
  3. 把“当前优先级”“当前重点”“核心能力”从其他文档里删掉或改成链接。
  4. 给每个专题文档补上 Layer ownerFeeds / AffectsStabilityExit / Promotion
  5. 定义证据等级:inventory、contract read、static evidence、runtime evidence、release evidence。
  6. 把测试入口、发布入口、运维入口全部收敛成少数命令。
  7. 给产品、运营、销售、客服/支持一条进入当前承诺、Flow 和 evidence 的路径。
  8. 给 AI agent 写清楚阅读顺序:先九层,再专题文档,再代码。
  9. 给 AI agent 写清楚更新顺序:先实现和 evidence,再判断是否提升上层。
  10. 每次完成任务时,检查是否有文档需要删除、压缩、提升或改名。
  11. 定期清理历史计划,避免 current-work 区域变成历史档案馆。

和 SSOT 主文的关系

上一篇文章解释了为什么所有软件工程原则最后都在谈 SSOT,以及为什么复杂团队会因为事实分裂而失控:

SSOT:为什么所有软件工程原则最终都在谈同一件事

本文则给出金字塔本身的可复用构造方法。

一个团队可以先读上一篇理解动机,再用本文搭建自己的金字塔。目录名字不是重点。重点是团队要持续拥有一个最新、唯一、可验证的业务、产品和技术事实模型。