context-infra 检查与复盘infra.guiming.net · 全内容自包含呈现 · 生成于 2026-07-21 16:28 UTC

模块拆合五十年共识

Z2 条目↑ Z1 版块 ↓ Z3 全文

方法论道层 · context-infra 处理逻辑

← 返回方法论区 · context-infra 处理逻辑 →

模块拆合五十年共识

viewtype=张力图 · 答:模块拆与合是同一判据哪两面 · 不答:具体代码重构步骤

核心判据边界切在会变的设计决策 secret 处拆的面低耦合:不同 secret 分开合的面高内聚:共享 secret 归一处拆分成本接口面 / 认知负荷 / 分布式税成簇聚合DDD aggregate / Simon 稳定子装配 = 一致性边界自动划界 25 年有用的视角 · 未替代人(退为决策支持)拆 ↔ 合是同一判据的两面(Martin tension triangle:REP+CCP 拉大、CRP 拉小,无唯一正确点)viewtype=张力图 · 答:模块拆与合是同一判据哪两面 · 不答:具体代码重构步骤部分落地概念
真源:contexts/methodology/se_module_split_merge_history_20260703_manual.md §2-3

拆与合是同一判据的两面

真源路径: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/工具/基础设施"的适用性)

强适用(几乎原样成立):

需要翻译后适用(机制不同,教训相同):

弱适用 / 打折扣:


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 模块化道层设计的建议输入(判据清单)

强度标注:[实证] 有真实工程案例支撑 | [经验] 经典工程原则、广泛共识 | [理论] 学术模型、落地有限 | [未落地] 学界试过但未成工程默认。

拆的判据(何时该分)

合的判据(何时该并回)

停的判据(拆到哪儿打住——不无限拆)

成簇聚合的判据(更高层的功能完整性——用户诉求核心)


6. 诚实边界


← 返回方法论区 · context-infra 处理逻辑 →

provenance:contexts/methodology/se_module_split_merge_history_20260703_manual.md data/methodology_dao.mjs