11 KiB
Raw Blame History

name description category tags trigger_conditions related_skills
module-partitioning Use when 划分软件模块/确定模块边界/复核模块拆分/把功能清单归并成模块。八原则(A业务能力/B业务边界/C高内聚低耦合/D业务闭环/E生命周期独立/F唯一责任/G基础设施非业务模块/H稳定后再抽象)+四张图(业务对象/生命周期/数据所有权/业务依赖)判定边界,优先复用已有模块。 software-development
module
architecture
boundary
partitioning
design
requirement
需求分析/设计阶段要把功能清单划分成模块
复核或重做已有模块划分,判断模块边界是否合理
判断某个功能该归入哪个模块、是否该独立成模块
模块拆分过细(1~2表一模块)或过粗(巨型模块)需要重新归并
function-point-counting
feature-granularity-and-testing
module-development-spec
web-application-spec

模块划分(八原则 + 四张图)

把「功能清单」归并成「模块清单」的判定方法。模块 = 一个可独立开发/复用/部署挂载的业务能力单元 (Host-Agnostic Python 包,见 module-development-spec;不独立部署,挂在应用伞下)。

铁律(用户强调):

  1. 模块划分面向概念聚合,禁止 1~2 张表就切一个模块——按业务能力聚合,不按表/页面/CRUD 机械切。
  2. 能用已有模块实现的功能,必须用已有模块,不重复造(基础模块 apppublic/sqlor/ahserver/ accounting/appbase/rbac,以及平台已有业务模块)。先查已有模块清单再划分。
  3. 模块划分是架构决策:requirement 阶段出初步划分(八原则+四张图),design 阶段复核+细化。
  4. 产出必须含:模块清单 + 每模块的业务能力/边界/唯一责任 + 模块间依赖 + 开发顺序(拓扑序)。

输入与输出

  • 输入:功能清单(来自 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 模型生成真实图片嵌入文档 (![图名](URL));禁止 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 写:

  1. 四张图(业务对象/生命周期/数据所有权/业务依赖)——必须是 invoke_model t2i/i2i 生成的真实图片(![图名](URL)),禁止 mermaid/ASCII/文本图代替(平台无图像模型时按文字模板产出并如实标注配图缺失)。
  2. 模块清单表:模块名 | 业务能力(A) | 唯一责任(F) | 核心对象 | 依赖模块 | 开发顺序 | 复用/新建。
  3. 复用判定:哪些能力复用已有模块、如何挂载。
  4. 模块依赖图 + 拓扑开发顺序。

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/粒度 按业务对象拆