mcpField
R
refactor-module

refactor-module

github.com/plainlang开发8042 次安装2 天前更新
代码仓库

关于 refactor-module

refactor-module 用于将范围过宽的 .plain 模块重组为 requires 链,同时保留所有规格的行为与顺序。它指导用户完成拆分规划、确认、迁移和验证。

主要功能

  1. 01分析规格与依赖关系
  2. 02规划语义模块分组
  3. 03保留时间顺序
  4. 04分配并导出概念
  5. 05迁移测试并验证

适用场景

  1. 01拆分包含无关功能的模块
  2. 02规划安全的模块依赖链
  3. 03迁移规格并保留其行为

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/plainlang/plain-forge --skill refactor-module

安装后在 Claude Code 中输入/refactor-module确认已加载。

详细介绍

重构模块

先加载规则。 在读取、编辑或编写任何 .plain 文件之前,请调用 load-plain-reference 技能,并阅读它指引你查看的规则文件。只有当本次对话中已经运行过 load-plain-reference 时,才可跳过此步骤。

适用情形

  • 一个模块包含许多涉及多个不同领域或功能区的功能规格。
  • 模块中交织着互不相关的关注点,因此难以理解。
  • 模块的范围过于宽泛,难以添加新功能。
  • 用户明确要求拆分或重新组织模块。

指导原则

重构只调整结构。重构后各模块的组合行为必须与原模块完全一致。不得添加、删除或削弱任何功能规格。拆分应基于语义——将相关规格归为一组——而非改变行为。

输入

要重构的 .plain 文件,以及用户提供的分组指导(或请用户确认你提出的分组方案)。

阶段 1 — 分析当前模块

  1. 通读整个 .plain 文件——包括 frontmatter、定义、实现要求、测试要求和所有功能规格。还要阅读所有 import 和 requires 依赖链,以了解完整上下文。
  2. 盘点功能规格。 列出每项功能及其 func-id,并注明它引用的 :Concepts:。建立依赖关系图:哪些规格依赖较早的规格(引用了它们引入的行为或状态)。
  3. 盘点定义。 对每个概念,注明哪些功能规格引用了它。找出多个逻辑分组都会用到的概念,以及仅在某个分组内使用的概念。
  4. 确定逻辑分组。 寻找自然的切分点——共享概念、属于同一连贯领域或描述同一功能区的功能规格集群。常见分组包括:
    • 数据模型设置和 CRUD 操作
    • 业务逻辑和处理规则
    • UI 屏幕和导航
    • 集成和外部接口
    • 统计、报告和分析
  5. 验证分组的独立性。 每组规格在时间顺序上都应形成连续或近乎连续的区块。如果某组规格分散在其他组之间,可能需要调整拆分边界。

阶段 2 — 规划拆分

进行任何更改前,先向用户展示拟议的拆分方案,并获得明确确认。

2a. 定义模块链

模块组成一条 requires 依赖链,以保留功能规格原有的时间顺序。链中的第一个模块包含最早的规格;后续每个模块都 requires 前一个模块,并添加下一个逻辑分组。

original-module
  ↓ splits into
module-group-a  (no requires — this is the chain root)
module-group-b  (requires: module-group-a)
module-group-c  (requires: module-group-b)

如果原模块已有 requires 或 import 依赖,第一个新模块应继承这些依赖。

2b. 将功能规格分配到模块

每项功能规格只能放在一个模块中。分配时必须遵循时间顺序:

  • 每个模块内的规格,其相对顺序必须与原模块一致。
  • 沿依赖链排列的各模块必须保持顺序:模块 A 中的所有规格都必须早于模块 B 中的所有规格,模块 B 中的所有规格又必须早于模块 C 中的所有规格。
  • 某项规格不能移到其所依赖的规格之前的模块中。
2c. 将定义分配到模块

对每个概念,确定它所属的位置:

概念的使用范围放置方式
仅用于一个模块的规格中在该模块中定义
在依赖链中的多个模块中使用在首次使用该概念的模块中定义,并将其添加到该模块的 exported_concepts
已在某个导入模板中定义保留在导入模板中——无需更改

如果许多概念在所有模块中共享,可考虑创建一个新的导入模块(模板)来存放它们。这样可以避免 exported_concepts 列表过长,并集中管理定义。请使用 create-import-module 技能。

2d. 分配实现要求和测试要求
  • 适用于所有模块的要求应放在共享导入模板中。如果已有此类模板,请将它们保留在其中。
  • 特定于单个模块所属领域的要求应移至该模块。
  • 如有疑问,请将要求保留在共享模板中——各模块之间重复内容,总比模板范围稍广要糟。
2e. 呈现计划

向用户总结:

  • 拆分后模块的数量及其名称
  • 每个模块包含哪些功能规格(按 func-id 列出)
  • requires 链的顺序
  • 是否会创建新的导入模块
  • 每个模块导出哪些概念
  • 确认已涵盖所有原始规格(没有遗漏)

继续操作前,必须获得用户明确确认。

第 3 阶段 — 执行拆分

按顺序从链根开始创建新模块。

3a. 创建或更新导入模板(如有需要)

如果要将共享定义或要求移至新的导入模板,请先使用 create-import-module 技能创建该模板。

3b. 创建链根

创建链中的第一个模块:

  1. 设置 YAML frontmatter——继承原始模块的 import 引用。为下游模块需要的概念添加 exported_concepts。
  2. 添加 ***definitions*** 部分,包含此模块规格所用的概念以及需要导出的概念。
  3. 添加特定于此模块的 ***implementation reqs*** 和 ***test reqs***(如果导入模板未完全涵盖这些要求)。
  4. 添加分配给此模块的 ***functional specs***,保留其原始顺序和确切措辞。
  5. 将已移动功能的测试纯文本文件中的 module: 键设为新模块名称,并将文件移至该模块的标准位置;func-id 和场景文本保持不变。
3c. 创建后续模块

对链中的每个后续模块:

  1. 将 requires 设为指向链中的上一个模块。如果使用共享模板,则设置 import。
  2. 为链中后续模块需要的概念添加 exported_concepts。
  3. 为此模块的本地概念添加 ***definitions***。不要重新定义通过 requires(已导出)或 import 可用的概念。
  4. 添加特定于此模块的 ***implementation reqs*** 和 ***test reqs***。
  5. 添加分配给此模块的 ***functional specs***,保留其原始顺序和确切措辞。
  6. 以相同方式移动已移动功能的测试纯文本文件。
3d. 处理原始模块文件

创建所有新模块后:

  • 如果原始模块将被完全替代(所有规格均已移出),请删除它或重命名,以免造成混淆。
  • 如果其他模块依赖原始模块,则更新这些模块,使其改为 require 新链中的最后一个模块——该模块累积的代码和此前的功能规格涵盖了整条链。不过,导出的概念不会传递:如果下游模块引用了现在由新链中较早模块导出的概念,则它也必须在 requires 中列出该较早模块。

第 4 阶段 — 验证

4a. 完整性检查

这是最关键的验证。逐一检查原始模块中的每个功能规格,并确认它恰好出现在一个新模块中。不得遗漏、弱化、修改任何内容,也不得将内容留作隐含。

检查清单:

  • 所有新模块中的规格总数与原始规格总数相同
  • 每项规格的文本与原文完全一致(不得改写),且保留其 func-id
  • 每项功能的测试纯文本文件均已随之移动,module: 已更新,场景内容保持不变
4b. 时间顺序检查

验证沿 requires 链从根到叶依次阅读时,所有功能规格的时间顺序与原始顺序完全一致。任何规格都不得出现在其所依赖的规格之前。

4c. 检查概念是否可用

对于每个模块,验证:

  • 其规格中引用的每个 :Concept: 都在本地定义、通过 import 导入,或可通过 requires 中所列模块的 exported_concepts 获取
  • exported_concepts 包含下游模块所需的每个概念
  • 模块之间没有概念名称冲突
4d. 验证每个模块的结构

对于每个新模块:

  • 至少包含一个功能规格和一个实现需求
  • YAML 前置元数据格式正确
  • requires 和 import 路径正确
  • 模块文件位于仓库根目录(不在 template/ 中)
  • 规格与语言无关
  • 所有外部接口均明确列出
4e. 阅读所有新模块

完整阅读每个新的 .plain 文件,并向用户展示最终结构以供审批。如果用户要求修改,请应用修改并重新验证。

常见问题

拆分过度

创建许多仅包含 1–2 条规格的小模块,会增加开销,却不能提升清晰度。每个模块以包含 3–10 条功能规格为宜,并围绕一个连贯的主题分组。

破坏时间顺序

建立基础行为(入口点、数据库初始化、核心 CRUD)的规格,即使涉及多个领域的概念,也必须留在链的根模块中。只有在规格可以清晰分离时才进行拆分。

忘记设置 exported_concepts

如果模块 B 中的规格引用了模块 A 定义的概念(且 B 依赖 A),则该概念必须包含在 A 的 exported_concepts 中。缺少导出项会导致渲染失败。

拆分时修改规格文本

这是重构,不是重写。规格文本必须原样复制。如果某条规格需要改写才能适用于新模块上下文,这说明拆分边界不合理——应调整分组方式。

丢失测试 plain 文件

测试 plain 文件通过 module: 和 func_id: 与其功能关联。当某项功能移至新模块时,其 module: 键也要更改,并将文件移至新模块约定的位置;否则渲染器会报告找不到匹配功能的条目。

验证清单

  • 执行拆分前,用户已确认拆分计划
  • 所有原始功能规格都出现在且仅出现在一个新模块中——没有遗漏
  • 规格文本与原文完全一致——没有改写
  • 测试 plain 文件随对应功能移动,并重新绑定到新模块
  • requires 链中保留了时间顺序
  • 每个模块中引用的 :Concept: 都可用(本地定义、导入或导出)
  • 每个模块都正确设置了 exported_concepts
  • 没有概念名称冲突
  • 每个模块至少包含一个功能规格和一个实现需求
  • requires 链的顺序正确(根 → 叶)
  • 原模块已移除或更新
  • 下游模块(如有)已更新为依赖链末端模块,以及其引用了导出概念的任何更早链上模块
  • 用户已批准最终结果

评论

支持 Markdown