模块拆合五十年共识
方法论道层 · context-infra 处理逻辑
模块拆合五十年共识
viewtype=张力图 · 答:模块拆与合是同一判据哪两面 · 不答:具体代码重构步骤
拆与合是同一判据的两面
真源路径:contexts/methodology/se_module_split_merge_history_20260703_manual.md · 图型:张力图 · 域:context-infra 处理逻辑
真源正文
报告元数据(frontmatter)
name: se_module_split_merge_history_20260703_manual
description: 50 年软工模块拆合理论横向综合
domain: cross
consumption:
surface: none
trigger: ""
consumer: orchestrator
status: library
promoted_to: rules/skills/drafts/workflow_idea_to_production.md软工史对「模块拆分 / 合并 / 粒度控制 / 高层聚合」的处理经验
调研日期:2026-07-03 | 类型:manual survey | 喂给:i2p 系统模块化道层设计(拆分/合并双向 mindset + 高层成簇聚合)
锚定裁定(张乐轩逐字):「模块化不一定只是单纯的拆分,它也可以是反过来的合并……不是要把东西分得很细碎,也不一定非要无限制地拆分下去……为了保证功能的完整性,在更高层级上需要有一种"成簇"的聚合处理。」
用户语境:单人 + AI agent 协作;产品形态族 = {Web App, CLI 工具, skill/workflow, agent 系统, 基础设施}。
1. 直接回答
软件工程史对这个问题有一条五十年未变的核心共识:模块的边界应该切在"会变化的设计决策/知识(secret)"处,而不是切在执行顺序或格式上;而"拆"和"合"从来就是同一条判据的两面——高内聚(该合的合在一起)与低耦合(该分的分开)——不是先拆再补一个合的动作。 拆分本身不是目的,它有真实且大体固定的成本(接口面、认知负荷、分布式税),所以拆分不可无限;拆到底之后必须在更高层级把强相关的一簇重新绑成"一致性/完整性边界"(DDD 的 aggregate、Simon 的稳定子装配、Martin 的 cohesive package)。用户的"拆分↔合并辩证 + 成簇聚合"不是对经典理论的补充,而正是经典理论本来的形状。至于"用贪心算法自动划边界"——学界试了 25 年(Bunch/MQ/SBSE),诚实结论是:它是个有用的视角(把内聚/耦合当成可优化标量),但从未落地成能替代人的领域判断的自动驾驶。
2. 共性提炼(报告主体:跨来源反复出现的共同原则)
C1 — 模块化本就是双向的:拆与合是同一判据的两面。
Parnas 的"切在会变的决策处"既是拆规则(不同 secret 分开)也是合规则(共享一个 secret 的全归一处);Constantine 的 functional/sequential cohesion 直接说"保持在一起=合",coincidental/logical 说"拆";Martin 明确把这叫 tension triangle——REP+CCP 把包拉大(合)、CRP 把包拉小(拆),是不可消解的张力,没有唯一正确点。POSD 有一条专门的 combine-or-separate-decision-rule。
佐证:Parnas 1972(acolyer 摘要 blog.acolyer.org/2016/09/05);Constantine coupling/cohesion(en.wikipedia.org/wiki/Cohesion_(computer_science));Martin DesignPrinciples PDF(staff.cs.utu.fi/~jounsmed/doos_06/material/DesignPrinciplesAndPatterns.pdf);POSD opus_v6/skills/combine-or-separate-decision-rule。
C2 — 判据是"变化 / 知识 / 秘密",不是执行顺序或格式。
Parnas 反对按 flowchart 步骤分(KWIC 例子:按处理步骤分,共享数据结构一变全崩;按信息隐藏分,变化被关在一个模块里)。POSD AX_19_decompose-by-knowledge-not-time 独立复述同一条。Martin CCP:为同一原因、同一时刻变化的类归一起。DDD bounded context:围绕"模型在其内保持一致"划界。
—— 这条与用户仓库自身的准则「按交互目的而非格式放」同构。
佐证:Parnas 1972;POSD opus_v6/axioms/AX_19;Martin CCP;Fowler BoundedContext(martinfowler.com/bliki/BoundedContext.html)。
C3 — 高内聚低耦合是可操作的双向判据,且可被形式化为一个标量。
Constantine/Myers 给出 coupling 谱(content>common>external>control>stamp>data,越靠后越好)与 cohesion 谱(coincidental…→functional,越靠后越好)。Myers 进一步主张两者近乎反相关(是一个设计质量的两个视角)。Bunch 的 MQ metric 把它写成一个可最大化的标量:MF = 内部边权 /(内部边权 + ½·跨簇边权)——即"高内聚低耦合"的算法化操作定义。
佐证:coupling/cohesion(mrpicky.dev/a-brief-history-of-coupling-and-cohesion);MQ(Mancoridis et al. IWPC 1998, cs.drexel.edu/~bmitchell/pubs/iwpc98.pdf)。
C4 — 拆到底后必须"成簇"再聚合;簇是一致性/完整性边界,不是文件夹。(用户诉求的正中心)
DDD Aggregate:把领域拆成细粒度 entity/value object 后,必须把强不变量耦合的一簇重新收到"一个 aggregate root"之下,事务边界 = 一次提交至多一个 aggregate,外部只能按 identity 引用——这才让簇是"完整性"而非装饰性分组。DDD Bounded Context 是更高一层的簇。Simon near-decomposability:复杂系统天然是"簇内强、簇间弱但非零",Hora/Tempus 寓言证明有稳定子装配的系统才扛得住中断。Pattern Language:大整体分解为可辨识子部分,每个有自己的尺度/中心/边界,且构成"linked multiscale network"。
佐证:Vernon "Effective Aggregate Design"(dddcommunity.org/library/vernon_2011);Simon 1962(faculty.sites.iastate.edu/tesfatsi/archive/tesfatsi/ArchitectureOfComplexity.HSimon1962.pdf);sciences_of_the_artificial opus_v6/axioms/AX_10、AX_08;pattern_language codex_v6/axioms/AX_02、AX_49。
C5 — 过度拆分有真实成本,拆分不可无限。(用户"不要细碎"的最强实证)
微服务钟摆案例给出量级证据(见 §4):Prime Video 合并省 90% 成本;Segment 140+ 服务把运维拖垮。POSD 命名 classitis(小类病)、shallow module、premature method splitting,并主张"complexity 守恒、要 pull complexity downward"。Team Topologies:cognitive load 是所有权硬上限,超了不是加人能解决。out_of_the_tar_pit:复杂度自我强化(看不清已有的就重复造,复杂度再涨)。
佐证:Prime Video / Segment(见 §4 URL);POSD opus_v6/axioms/AX_10、AX_51 + skills/shallow-module-trap、premature-method-splitting;team_topologies codex_v6/axioms/AX_12;out_of_the_tar_pit kimi_v6/skills/complexity-self-reinforcing。
C6 — 深模块优于浅模块:每次拆分都增加接口面,只有当拆分真的隐藏了信息才划算。
POSD:depth = 功能 ÷ 接口复杂度;Unix I/O(5 个 syscall 藏几十万行)是典范深模块。Parnas 同源:"接口应尽量少暴露内部"。POSD 的 combine 规则:"能隐藏信息就合并;只有当通用与专用代码纠缠时才分开。"
佐证:POSD opus_v6/axioms/AX_09、AX_10;Parnas 1972。
C7 — 粒度随上下文与成熟度变化,不是固定值:一般先粗后细(或按需拆)。
Martin:项目早期偏向 CCP 而非 REP("developability 比 reuse 重要",因为还没人复用),成熟后才为独立发布而拆。Fowler MonolithFirst / microservice premium:几乎所有成功的微服务都是从长大的单体拆出来的;绿地直接上微服务多数翻车。Sam Newman:微服务是"最后手段"。
佐证:Martin 组件成熟度论述(同 C1 PDF);Fowler(martinfowler.com/bliki/MonolithFirst.html、MicroservicePremium.html)。
C8 — 算法能优化"结构"却抓不住"意义":自动划边界从未替代人的领域判断。(回答用户"贪心算法")
Bunch 把模块聚类当图划分优化,用 hill-climbing(即贪心:每步取使 MQ 增益最大的局部动作)+ 遗传算法逃局部最优。但 25 年下来它停在学界:Wu et al. 2005 实测六种聚类算法结论是"need significant improvement";"authoritativeness problem"——根本没有稳定的"标准答案"decomposition 可比对;活下来有工业牵引的工具(Structure101、CodeScene、IBM Mono2Micro)全部退回到决策支持(让人声明架构、做一致性检查/可视化/建议),而非决策制定。
佐证:Bunch ICSM 1999(cs.drexel.edu/~bmitchell/pubs/icsm99.pdf);Wu/Hassan/Holt ICSM 2005(dblp.uni-trier.de/rec/conf/icsm/WuHH05);survey arXiv:2012.01057;Mono2Micro arXiv:2107.09698。
3. 特异性映射(对"单人 + agent、产品含 skill/工具/基础设施"的适用性)
强适用(几乎原样成立):
- Parnas 切在会变处 + 按知识而非顺序拆:对 skill/prompt 尤其重要——一个 skill 的"secret"就是它封装的那个易变设计决策。适用。
- Simon near-decomposability + Hora/Tempus 稳定子装配:agent workflow 天然会被中断(context 上限、故障),稳定中间件=可恢复的 checkpoint/产物。这与仓库已有的 phase/trace/断点恢复机制同构。强适用。
- DDD aggregate 作为一致性边界:仓库自己的「skill 跟工作走」(skill + 其工具 + 其 trace 一起派发)本质就是一个 aggregate——一簇必须一起满足不变量的东西收在一个根下。适用。
- Cognitive load 天花板(Team Topologies):把"team"读作"一个协调心智 + 有界 agents",则认知负荷才是真正的粒度约束,而非技术优雅。这是 solo+agent 语境下最该抬到首位的判据。(注:把"team"改读为"协调心智+agents"是我的推理映射,非文献直接结论。)
需要翻译后适用(机制不同,教训相同):
- 微服务 distribution tax:字面的网络/部署税对单进程 CLI/工具大多 N/A,但同构的税真实存在——每次 agent handoff = 序列化税(context 丢失)、每个 sub-agent = 编排税、每个独立 skill 文件 = "路由到正确那个"的税。所以"过度拆分有协调成本"这条教训跨界成立,只是载体从"网络"换成"handoff/context"。(类比为我的推理。)
- POSD classitis 警告 vs 用户自己的"many small files"编码规范:POSD 自己的 caveat 说 classitis 标签在 functional/小单元组合范式里不干净——而 skill/工具正是小可组合单元,小单元成本接近零。结论:对 skill/tool,"多个小文件"没问题,前提是每个都隐藏了某个 secret;一旦某个小文件不隐藏信息、要来回翻才懂,就是 classitis,该合回(POSD premature-method-splitting 的判据直接可用)。
- Team Topologies 三种交互模式(Collaboration / X-as-a-Service / Facilitating):字面团队结构 N/A,但可映射到 agent 角色——worker(协作)/ 工具提供者(X-as-a-Service)/ regulator(facilitating)。
弱适用 / 打折扣:
- Martin 包耦合原则 REP/ADP/SDP:版本化(REP)对 skill/tool 适用(仓库已在给 skill 打版本);但 acyclic dependency(ADP)更贴代码而非 prompt。
- 自动化 remodularization:贪心合并 / MQ 直觉可作"给一堆 skill/tool 文件做首轮分组"的视角;但"人的领域判断更准"这条对 solo 场景加倍成立——用户本人就是领域专家,不该把边界决策外包给聚类算法。
4. 成熟案例
案例 1 — Amazon Prime Video(2023,拆过头回摆)。
背景:音视频质量监控服务 V1 用 Step Functions 编排 + 每个检测器一个 Lambda,帧经 S3 中转。动作:塌缩成单进程(检测器进程内跑、帧走内存引用,去掉 Step Functions 和 S3 中转),扩展靠整体克隆。结果:基础设施成本降 >90%,扩到数千路流。教训 + 诚实边界:Adrian Cockcroft(前 Netflix)明确指出这是单团队单个非面客服务按"Serverless-First"正确演进(原型用 serverless,热路径固化成专用服务),不是"微服务已死"。→ 关键是"按工作负载选对粒度",不是架构意识形态。
来源:primevideotech.com(原帖);adrianco.medium.com/so-many-bad-takes(nuance)。
案例 2 — Segment "Goodbye Microservices"(2018,最清晰的"过度拆分→合并")。
背景:原本一条共享队列,慢的 destination 造成 head-of-line blocking,于是为故障隔离拆成"每 destination 一个微服务+一条队列"(合理的拆分动机)。破在哪:destination 每月 +3,运维线性膨胀——2017 年初 140+ 服务/仓库、120 个依赖版本漂移、负载极不均导致自动扩缩"更像艺术"、on-call 被打爆。动作:建 Centrifuge 单路由服务替代 140+ 队列,代码合回单仓单依赖集,建 Traffic Recorder 让测试从小时级降到毫秒级。接受的取舍:失去 per-destination 故障隔离,换来共享库改进发布频率 +44%(32→46/年)。教训:故障隔离是真拆分理由,但当 N 增长而平台投入没跟上,其运维成本(N 仓 × N 流水线 × N 依赖图)会超过收益。
来源:twilio.com/en-us/blog/developers/best-practices/goodbye-microservices。
案例 3 — Shopify "Majestic Monolith"(正面:模块化单体也能扛规模)。
背景/动作:Shopify Core 是单个 Rails 代码库(~2.8M LOC),保持单一可部署单元,但内部拆成模块并用静态分析工具强制边界(checkout 不能伸手进 billing 内部);规模靠按 shop_id 把数据库分片成独立 Pod。结果:全球最高流量电商之一跑在一个部署单元上。教训:规模不必然要求拆成分布式;"单部署 + 纪律化内部模块 + 数据层分片"胜过划错边界的微服务(distributed monolith)——边界质量比部署拓扑重要。
来源:shopify.engineering/shopify-monolith、shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity。
案例 4 — Bunch / MQ(1998–2006,"算法没能替代判断")。
背景/动作:把模块聚类形式化为最大化 MQ 的图划分,用贪心 hill-climbing + 遗传算法求解。结果:停留学界;Wu et al. 2005 实测判定"需重大改进","authoritativeness problem"指出连可比对的标准答案都不稳定存在。教训:贪心/聚类是理解边界的有用 lens,但自动划边界 25 年未成为工程师信任的自动驾驶;每个活下来的商业后代都退回"人做最终裁定"的支持工具。
来源:cs.drexel.edu/~bmitchell/pubs/icsm99.pdf;dblp WuHH05;arXiv:2107.09698(Mono2Micro,同谱系,仍是"给人建议")。
5. 对 i2p 模块化道层设计的建议输入(判据清单)
强度标注:[实证] 有真实工程案例支撑 | [经验] 经典工程原则、广泛共识 | [理论] 学术模型、落地有限 | [未落地] 学界试过但未成工程默认。
拆的判据(何时该分)
- 存在两个独立的、会各自变化的设计决策/secret → 各自成模块。[经验] Parnas / POSD AX_19
- 候选边界一侧只是 coincidental/logical/temporal 内聚(凑一起的) → 拆。[经验] Constantine
- 消费者被迫依赖它用不到的东西(CRP 违反) → 拆。[经验] Martin
- 拆分能隐藏信息、降低某个接口读者/协调心智的复杂度 → 拆。[经验] POSD deep module
- 认知负荷超过"一个协调心智 + 有界 agents"能持有的量 → 拆。[经验,对 solo 特别相关] Team Topologies
合的判据(何时该并回)
- functional/sequential 内聚(一个任务、一个变化理由) → 合。[经验] Constantine / Martin CCP
- 拆开后必须靠 content/common/control coupling 才能重连 → 拆错了,合回。[经验] Constantine
- "化妆式拆分"(要来回翻才懂、无复用、无信息隐藏) → 合回/内联。[经验] POSD premature-method-splitting
- 一簇对象需要一起满足不变量/事务一致性 → 收成一个 aggregate root。[经验] DDD
- 项目/skill 尚早,developability > reuse → 先粗粒度,别急着拆。[实证+经验] Martin / Fowler MonolithFirst
停的判据(拆到哪儿打住——不无限拆)
- 某次拆分的接口成本 > 它隐藏的复杂度收益 → 停。[经验] POSD deep module
- 拆分不减少任何人(接口读者或协调心智)的认知负荷 → 停。[经验] Team Topologies / POSD
- 已达 near-decomposable(簇内强、簇间弱但非零) → 就停在这一层。[理论] Simon
- 出现 distribution tax / distributed monolith 征兆(拆了部署/handoff 却仍紧耦合、要协同才能改) → 停并合回。[实证] Segment / Prime Video
- 度量说"再拆 MQ 更高"但领域语义上不成立 → 以人的领域判断为准,别让算法划边界。[未落地] remodularization
成簇聚合的判据(更高层的功能完整性——用户诉求核心)
- 一致性边界:一簇要一起满足不变量的东西 → 一个 aggregate root,外部按 identity 引用不直接穿透。[经验] DDD
- 稳定中间件:能独立完成、被中断也不全丢的子装配 → 立为一个簇(对 agent workflow = 可恢复 checkpoint/产物)。[理论] Simon Hora/Tempus
- 上下文边界:模型在其内保持一致的范围 → 一个 bounded context;跨簇用显式契约/翻译层(anticorruption layer),不做全局大统一模型。[经验] DDD
- 多尺度可辨识:每个子部分有自己的尺度/中心/边界,且各尺度构成 linked network(改一个尺度要顾及上下尺度) → 不要只优化单一尺度。[经验] Pattern Language
6. 诚实边界
- 原文核对缺口:Parnas 1972 与 Myers 两本书的原文 PDF 未取到(ACM 付费墙 403 / 仅借阅扫描);其论点由 4+ 独立二手来源三角验证、彼此一致,但未逐字核对原著。
- "高内聚低耦合"有争议:2025 年 arXiv:2507.09596 批评"高内聚低耦合=好设计"相关性并不完美——但该批评点名反驳本身证明这条 50 年后仍是参照系。
- 微服务案例是"错粒度"不是"微服务坏":Prime Video 是单团队单服务、非面客组件,Cockcroft 明确它不代表行业反转;引用时不可扩大为"微服务已死"。
- 自动化 remodularization 是"学框架、没落地":贪心/聚类/MQ 是 lens 不是 autopilot,作为 i2p 判据只能进"视角"而非"自动决策"。
- Simon near-decomposability 的局限:真实依赖网络常是 scale-free / small-world(hub 主导),不是干净的 block-diagonal 层级——完美近可分解是理想化假设(蒸馏产物自身的 caveat 也点出这条)。
- 特异性映射多为我的推理:把"team"读作"协调心智+agents"、把"distribution tax"类比到"handoff/context tax",是把文献往 solo+agent 语境的迁移推理,非文献直接结论——落到道层前建议再 dogfood 验证一轮。
- Pattern Language 蒸馏范围:仓库蒸馏的是《A Pattern Language》的建筑内容,非后期《The Nature of Order》的 centers/wholeness 理论;不要借它过度声称"wholeness"形而上学。
- 团队规模断层:所有微服务/包/团队拓扑经验的原语境是"多团队大组织",用户是 solo+agent;跨规模迁移时"协调成本"的绝对量级不同,判据方向可迁移、阈值需自校准。
provenance:contexts/methodology/se_module_split_merge_history_20260703_manual.md data/methodology_dao.mjs