DRY 单一知识来源
§1摘要与结论
系统内每个知识点应有单一、无歧义、权威的表示,避免同一知识的多份副本各自漂移。它针对的是「知识重复」而非机械的代码重复,核心判据是:一处规则改变时,是否需要在多个位置同步修改。它衡量的是知识的归属是否清晰。
别名:DRY、Don't Repeat Yourself、single source of truth | 英文:DRY / Single Source of Knowledge | 类型:方法原则 / concept
§2局部关系图
§3原理 · 为什么
重复的知识意味着一次变更要同步修改多处,任何遗漏都会产生不一致与缺陷,而且随着副本增多,同步成本与认知负担成倍上升。把知识收敛为单一权威表示、让其余位置引用它,可以显著降低同步成本,是正交性与可维护性的基础。「知识」的范围很广:业务规则、常量、算法、数据模式、配置、甚至同一决策的文档表述都可算。判定重复要追问「它们表达的是不是同一个知识」——若两个片段只是当前恰好相似、未来可能朝不同方向演化,那它们并非同一知识,硬合并反而制造虚假耦合。因此 DRY 的实质是「同一变化原因只在一处体现」。经验表明,重复往往在系统边缘、多人协作处与快速迭代期悄然滋生,越晚收敛成本越高。因此,判断重复是否要消除,本质上是判断两处内容背后的知识是否共享同一变化原因;共享则合并,不共享则宁可保留两份,等待演化给出更清晰的信号。因此,团队需要一套判断「是否为同一知识」的共同标准,否则有人主张合并、有人坚持保留,就会在重复与错误抽象之间反复摇摆。
§4机制 · 如何运作
识别重复背后的同一知识,把它抽出为单一权威表示,其余位置改为引用、派生或生成,而不是复制。对可以由源头推导出的内容,优先用生成替代手工同步;对配置与阈值,集中到一处并让各方读取;对算法与规则,抽取为共享实现并明确其契约。判断是否合并,可用「变化方向」检验:把两个片段分别设想可能发生的需求变化,若它们会因同一原因、朝同一方向改变,就应合并;若变化方向不同,则保留两份重复更安全。Rule of Three 提供节奏——同类重复出现第三次以上再抽象,避免为偶发相似过早建立抽象。漂移的副本是最主要的危险信号:当同一知识的两份拷贝开始出现细微差异,就应立刻收敛,否则差异会沿各自方向继续扩大。在收敛过程中还要保留可追溯性:让引用者知道权威源在哪里、谁负责维护,避免单一来源因失去归属而成为无人负责的黑箱,反而比分散的副本更危险。在跨语言、跨服务的边界上,单一来源更应通过生成或接口同步来维持,而不是靠人工在两侧对齐,人工对齐在规模上是不可持续的。
§5工程 · 怎么落地
工程上把规则、常量、配置与数据模式的权威来源标出来,让引用者依赖它,禁止平行维护副本;能自动推导的用代码生成或构建期生成,减少人工同步。代码评审时识别重复坏味道——同一条件散落多处、同一映射表被复制、同一序列化逻辑反复出现——并区分「真知识重复」与「偶然相似」。对跨团队共享的知识,单一来源还应配合明确的拥有者与变更流程,否则收敛后反而形成瓶颈。抽象要配测试:共享实现的契约必须有测试守住,否则收敛带来的收益会被未覆盖的行为差异抵消。对无法合并的重复,至少要用一个显式注释说明为何保留两份,防止后人误合并;对必须跨边界共享的知识,应通过稳定的接口而非直接复制来传递。对生成的内容,应把生成脚本也纳入版本管理与评审,否则真相会分裂为「源数据」与「手工修补的产物」两份,重新形成更难发现的重复。评审时若两段相似代码的注释、命名或依赖不同,应优先假设它们并非同一知识,除非能证明改变其中一个必然要求改变另一个。
§6权衡卡
过度消除重复会制造错误抽象,把变化方向不同的概念绑在一起,使后续任何一方的演化都被迫迁就另一方,这种耦合往往比原来的重复更难拆除。
消除重复本身也有成本——抽取、生成、维护共享组件的开销,在只有两三处、且改动频率很低时可能高于重复的代价;过早收敛还会把尚未稳定的概念固化,阻碍后续分化。
结论是:DRY 是方向而非教条,先判断「是否为同一知识、是否同向变化」,再权衡抽象成本与同步收益,允许在证据不足时保留重复并等待变化方向清晰。
总之,DRY 服务于降低变更成本,一旦消除重复本身变成新的协调负担,就说明抽象下早了,应果断回退到更简单、可独立演化的重复。
- 因此存在一条重要原则:宁要重复,不要错误的抽象。
- 此外,单一权威来源若缺乏拥有者与变更机制,会变成所有改动都要排队的瓶颈,甚至因共享组件变更而牵连所有使用方。
- 实践上可以允许重复暂时存在并加注说明,待变化方向明确后再合并;关键是把「哪些是同一知识」的判断显式记录下来,而不是凭直觉一次性消除所有相似。
权衡原文仅按显式标记词归栏引用(收益 / 代价 / 反例),其余句子按原序列为「原文要点」;内容逐字引用未改写。
§7学习路径条
§8案例带
网申 v3 多模块解耦
一套面向高可扩展性的网申信息速查扩展架构:以 schema.js 为唯一数据驱动源,把数据模型、存储、纯函数与渲染组织为严格单向依赖的共享层,供 popup 与页面浮层双容器复用,并先立跨模块接口契约。
网申 v2 深度重构
一次由「改一处漏多处」症状触发的深度重构:定位到接口定义散落 12 个文件、存在 7 种接口形态的根因后,以单一契约源、dispatch 消息表与能力注册中心重建三层契约系统,恢复可审计与可校验性。
去中心化聊天架构逆向
对一个仅有 58 份设计文档、尚未实现的开源去中心化聊天项目做架构逆向:从设计文本提炼 18 个模块及其依赖关系,重建模块依赖 DAG 与三条核心数据流 DAG,并输出全景理解与深度需求分析。
网申填写扩展逆向架构
对 Chrome MV3 网申自动填写扩展的逆向架构分析:梳理 popup、content、background、options 四模块职责,解剖 12 个站点适配器、双通道消息协议与隐私脱敏机制,并评估其零依赖零构建选型。
preset 通道耦合分析
对 harness「委派工具层→续用管理器→preset 服务→MCP 服务器」这条通道做耦合分析:识别契约、服务定位、数据契约、组合语义、路径与装配一致性六类耦合点,定位「静默丢弃特化」与「装配漂移」两处实质缝隙。
dsh-manager 插件深度分析
以「编译依赖、运行时注入、组合装配」三硬依据加源码行号,对第三方插件做依赖、功能、需求溯源与设计问题裁决,并复用上游 DAG 知识库节点标识,使分析结果可与主图互查。
harness 源码架构解析
对 deepseek-harness 官方源码做分层解析:镜像官方架构文档,按九个层与九十余模块建立文档集群,产出跨层联动矩阵与七条关键路径,并钉住「模型可见即已记录」、能力缝三角等设计不变量。
dsh 插件依赖增量定位
以官方插件 DAG 为蓝本,对一个官方清单之外的全新社区插件做功能定位与依赖位置增量分析,产出可下钻交互依赖图与多形态文档的源码级架构逆向案例。
Hermes 七层架构总览
对八千余文件的工业级 AI Agent 项目做七层架构总览逆向,揭示其「越用越聪明」的自进化闭环如何在层间传导的控制型架构案例。
Claude Code 架构逆向
以社区逆向源码、系统提示词与官方文档三源交叉验证,还原一个商业 Agent 的查询引擎、子Agent、工具与权限体系的逆向分析案例。
Open Code Review 图谱
对阿里开源 AI 代码审查 CLI 做源码级解析并构建「知识 + 实践资产 + AI 索引」三合一知识图谱的工程案例。
§9信源与核验
核验结论:DRY 针对「知识/信息重复」;Sandi Metz 主张「prefer duplication over the wrong abstraction」,Rule of Three 作为抽象门槛 [BK-005]
§10原始关系清单
展开:本节点的全部原始关系边(4 条,含边 ID 与方向)
| 关系 | 方向 | 对端节点 | 说明 |
|---|---|---|---|
| 案例印证 | ← CAS-X-03 | 网申 v3 多模块解耦 E-944 | 印证:schema 作为字段知识的单一权威来源 |
| 案例印证 | ← CAS-X-04 | 网申 v2 深度重构 E-948 | 印证:单一契约源消除接口知识的多份副本 |
| 组合 | → ESS-H-02 | 内聚与耦合 E-12 | 单一知识源与高内聚同向协同 |
| 前置依赖 | ← ESS-G-01 | 关注点分离 E-08 | 关注点分离促成知识的单一归属 |
附对照资源 · 12factor 子库
| 12factor 节点 | 关系 | 对照说明 |
|---|---|---|
| 代码库 app-codebase | 跨体系对照 | 代码库作为版本控制下的单一权威来源,与母库『DRY/单一知识来源』同源 |
| 统一执行/业务状态 ag-state | 跨体系对照 | 执行状态与业务状态统一为单一事实源,等同母库单一知识来源 |
| 无状态 Reducer ag-reducer | 跨体系对照 | 无状态 reducer 以不可变演算(state,event)→state 保持单一事实源 |