11 KiB
11 KiB
| name | description | category | tags | trigger_conditions | related_skills | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| module-partitioning | Use when 划分软件模块/确定模块边界/复核模块拆分/把功能清单归并成模块。八原则(A业务能力/B业务边界/C高内聚低耦合/D业务闭环/E生命周期独立/F唯一责任/G基础设施非业务模块/H稳定后再抽象)+四张图(业务对象/生命周期/数据所有权/业务依赖)判定边界,优先复用已有模块。 | software-development |
|
|
|
模块划分(八原则 + 四张图)
把「功能清单」归并成「模块清单」的判定方法。模块 = 一个可独立开发/复用/部署挂载的业务能力单元 (Host-Agnostic Python 包,见 module-development-spec;不独立部署,挂在应用伞下)。
铁律(用户强调):
- 模块划分面向概念聚合,禁止 1~2 张表就切一个模块——按业务能力聚合,不按表/页面/CRUD 机械切。
- 能用已有模块实现的功能,必须用已有模块,不重复造(基础模块 apppublic/sqlor/ahserver/ accounting/appbase/rbac,以及平台已有业务模块)。先查已有模块清单再划分。
- 模块划分是架构决策:requirement 阶段出初步划分(八原则+四张图),design 阶段复核+细化。
- 产出必须含:模块清单 + 每模块的业务能力/边界/唯一责任 + 模块间依赖 + 开发顺序(拓扑序)。
输入与输出
- 输入:功能清单(来自 function-point-counting 的功能明细表,或 propose_feature 落库的 sd_features)。
- 输出:
modules/{模块名}.md清单(功能/仓库/依赖/开发顺序/关联应用)+ architecture.md 的模块划分章节 (落点见 sdlc-repo-standard / project-directory-spec)。
工作流(六步,先画图后切块)
第 1 步:列功能清单并标注业务对象
逐条功能问「它操作/产生哪个核心业务对象」(如 订单、工单、发票、人员、世界快照)。 一个功能可能涉及多个对象,全列出。这是四张图的原料。
第 2 步:画四张图(判边界的唯一客观依据,详见 references/diagrams-guide.md)
产出形式(硬规定):四张图必须用 invoke_model 调 t2i/i2i 模型生成真实图片嵌入文档
();禁止 mermaid/ASCII/文本框线图代替。先按 diagrams-guide 的文字模板整理
对象/关系/状态/归属要点(= 边界信号分析底稿 + t2i 提示词素材),再逐张生成真图。
平台无图像模型(invoke_model FAIL)时按文字模板产出并如实标注「配图缺失」,不伪造。
| 图 | 画什么 | 读出什么边界信号 |
|---|---|---|
| ① 业务对象图 | 核心业务对象 + 对象间关系(1:1/1:N/聚合/引用) | 强聚合(组合/父子)的对象同模块;仅引用(外键/ID)的对象可分属不同模块 |
| ② 业务生命周期图 | 每个核心对象的状态机(状态+迁移+触发者) | 共享同一状态机/状态流转紧密耦合的功能同模块;生命周期各自独立的可拆 |
| ③ 数据所有权图 | 每张表/数据「谁创建、谁写、谁读、谁是权威源」 | 所有权一致(同一主体全权 CRUD)的数据归同模块;跨主体读写=耦合点,需接口而非共表 |
| ④ 业务依赖图 | 功能/对象间的调用与数据依赖(有向) | 依赖单向且稀疏=好边界;双向/环状依赖=切错了,需重新归并或抽接口 |
第 3 步:按四张图聚出候选模块
- 把「业务对象图里强聚合 + 生命周期共享 + 数据所有权一致」的功能聚成一个候选模块。
- 在「业务依赖图」上检查:候选模块之间应尽量单向依赖、无环。有环 → 合并环上模块或抽出共享接口。
第 4 步:八原则逐条校验每个候选模块(机械判定,见下)
第 5 步:复用判定——能用已有模块的,删掉候选、改为「引用已有模块」
对照平台已有模块清单(基础模块 + 已上线业务模块)。候选模块的能力若已有模块覆盖 → 不新建,在 architecture.md 写明「复用 {已有模块},通过 load_{module}() 挂载 / API 调用」。
第 6 步:定依赖与开发顺序
- 模块间依赖画成有向图,求拓扑序:被依赖的先开发。
- 基础模块/已复用模块不列为待开发。
- 一个模块 = 一个 develop 任务(PM 据此派发,见 task 技能)。
八原则(逐条机械判定,命中反例即重划)
A. 一个模块代表一个「业务能力」
- 判定:能否用一句「动词+业务宾语」概括模块职责(如「管理工单全生命周期」「计算并落账消费」)?
- 反例:职责描述需要「和/以及/还有」连接多个不相关能力 → 拆分。
- 反例:模块名是技术词(utils/common/base/helper)而非业务词 → 多半违反 G。
B. 明确的业务边界
- 判定:模块的输入/输出/触发场景能否清晰列举?边界外的事它一概不管?
- 反例:说不清「什么不属于这个模块」→ 边界模糊,重划。
C. 高内聚,低耦合
- 内聚判定:模块内功能是否都围绕同一业务能力/同一组核心对象(看业务对象图+数据所有权图)?
- 耦合判定:模块间依赖是否少而单向(看业务依赖图)?是否靠共享数据库表直接读写对方数据(强耦合,禁止)?
- 反例:模块内功能各干各的(低内聚);两模块互相直接读写对方的表(高耦合)→ 重划或抽接口。
D. 能独立完成一个业务闭环
- 判定:模块单独存在能否完成一个完整业务动作(输入→处理→产出/落库),不依赖另一个模块才能跑通主流程?
- 反例:A 模块的每个功能都必须先调 B 模块才能产生任何业务结果 → A、B 应合并。
- 注意:闭环≠孤立。允许通过接口依赖其他模块(如调记账模块落账),但主业务逻辑自洽。
E. 生命周期相对独立
- 判定:模块能否独立地新增/修改/废弃,而不强制牵动其他模块同步改?版本/演进节奏是否独立?
- 反例:改 A 必须同时改 B、C 才能编译/运行(非接口耦合)→ 生命周期绑死,应合并或解耦。
F. 明确的「唯一责任」
- 判定:每类业务数据/每个核心能力,是否有且仅有一个模块对其负责(创建+维护+权威源)?
- 反例:两个模块都能写同一张核心表 / 都声称负责「用户管理」→ 责任重叠,合并或明确分工。
- 与数据所有权图交叉验证:一份数据只有一个 owner 模块。
G. 不要把「基础设施」误认为业务模块
- 基础设施 = 与具体业务无关、被各业务模块共用的技术能力:数据库访问、HTTP 框架、认证鉴权、 日志、缓存、文件存储、ID 生成、加解密、消息队列。
- 判定:去掉具体业务场景,这个能力是否依然成立且被多方复用?是 → 基础设施,不是业务模块。
- 处置:基础设施用平台已有基础模块(apppublic/sqlor/ahserver/appbase/rbac/accounting), 不要为它新建业务模块,更不要把它和业务功能混进同一个业务模块。
- 反例:建一个「数据库模块」「工具模块」「公共模块」当业务模块开发 → 违反 G。
H. 共享能力要「稳定后」再抽象
- 判定:两个以上模块出现的相似逻辑,是否已稳定(接口/语义不再频繁变)?
- 稳定 → 抽象成共享能力(基础模块或独立共享模块)。
- 未稳定(还在快速变、各处需求不一致)→ 先各自实现,不要过早抽象(过早抽象=错误抽象, 日后改不动)。记录为「候选共享能力,待稳定后抽取」,不在本期强行合并。
- 反例:第一期就把两个还在变的功能抽成「通用 XX 服务」,结果两边需求一分叉就得加一堆参数 → 违反 H。
I. 用「四张图」判断模块边界
- 见第 2 步。四张图是 A~H 的客观证据来源:边界争议回到图上找答案,不靠主观感觉。
- 任何模块划分结论,都要能指出「依据哪张图的哪个信号」。
模块粒度(防过细/过粗)
- 过细信号:一个模块只有 1~2 张表、只有一个 CRUD、职责一句话说不满 → 合并进相邻同业务能力模块。
- 过粗信号:一个模块覆盖多个不相关业务对象、职责要「和/以及」连接、内部能拆出多个独立闭环 → 拆分。
- 合适粒度:一个模块 = 一个业务能力 = 一组强聚合业务对象 + 其完整生命周期 + 一致的数据所有权。
复用已有模块(铁律 2 的落地)
划分前必须先拿到「已有模块清单」:
- 基础模块(不重复开发):apppublic、sqlor、ahserver、accounting、appbase、rbac。
- 平台已有业务模块:查目标应用 pkgs/ 下已挂载模块 + 平台模块文档。
- 判定:候选模块能力 ⊆ 已有模块能力 → 复用(load_{module}() 挂载 / HTTP API 调用),不新建。
- 部分重叠 → 复用已有 + 新模块只做增量,通过接口对接,禁止 fork 已有模块代码。
输出模板(architecture.md 模块划分章节 + modules/{模块名}.md)
architecture.md 写:
- 四张图(业务对象/生命周期/数据所有权/业务依赖)——必须是 invoke_model t2i/i2i 生成的真实图片(
),禁止 mermaid/ASCII/文本图代替(平台无图像模型时按文字模板产出并如实标注配图缺失)。 - 模块清单表:模块名 | 业务能力(A) | 唯一责任(F) | 核心对象 | 依赖模块 | 开发顺序 | 复用/新建。
- 复用判定:哪些能力复用已有模块、如何挂载。
- 模块依赖图 + 拓扑开发顺序。
modules/{模块名}.md 写(格式见 sdlc-repo-standard):功能/仓库/技术栈/状态/依赖模块/开发顺序/关联应用。
反模式速查(命中即重划)
| 反模式 | 违反原则 | 修法 |
|---|---|---|
| 1~2 张表切一个模块 | A/D/粒度 | 按业务能力聚合 |
| 建「数据库/工具/公共」业务模块 | G | 用基础模块,不新建 |
| 两模块共写一张核心表 | C/F | 定唯一 owner,另一方走接口 |
| A、B 互相直接读写对方数据 | C/E | 抽接口,单向依赖 |
| 模块间依赖成环 | C/I(依赖图) | 合并环上模块或抽共享接口 |
| 第一期就抽「通用XX服务」 | H | 待稳定再抽,先各自实现 |
| 已有模块能实现却新建 | 铁律2 | 复用 load_{module}()/API |
| 巨型模块覆盖多业务 | A/B/粒度 | 按业务对象拆 |