mcpField
B
break-down-func-spec

break-down-func-spec

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

关于 break-down-func-spec

面向 `.plain` 规格编写者的技能,可将过于复杂的功能规格拆分为较小且有序的规格。它还会检查拆分结果是否保留原有行为,并适配模块上下文。

主要功能

  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 break-down-func-spec

安装后在 Claude Code 中输入/break-down-func-spec确认已加载。

详细介绍

拆分功能规格

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

适用场景

  • analyze-if-func-spec-too-complex 将某个规格标记为 TOO COMPLEX。
  • 怀疑某个规格超过 200 LOC 限制,需要提前拆分。
  • 某个规格包含多个应当分开的行为、构造或关注点。

输入

要拆分的功能规格,以及它所属的完整 .plain 文件。

工作流

  1. 阅读完整的 .plain 文件 — 阅读定义、实现要求和所有功能规格(包括 requires 模块),以了解上下文。
  2. 确定要拆分的规格 — 即被标记为过于复杂的规格,或用户指定的规格。
  3. 分析规格过于复杂的原因 — 使用 analyze-if-func-spec-too-complex 中的判断指标:
    • 是否捆绑了多个不同的行为?
    • 是否一次引入了太多新构造?
    • 是否包含复杂的分支逻辑或条件路径?
    • 是否将跨领域关注点与核心功能混在一起?
    • 是否在一个规格中描述了完整的 UI 屏幕?
    • 是否涉及跨多个实体的复杂数据转换?
    • 是否隐含着一个必须用代码构建的重要技术组件(引擎、解析器、调度器、算法、状态机、同步机制)?
  4. 确定拆分边界 — 找出可以自然拆分的部分。每个拆分后的规格都必须:
    • 独立且有意义(结合前面的规格也能单独理解)
    • 自包含(无需依赖后续规格即可发挥作用)
    • 不超过 200 LOC 限制
  5. 起草替代规格 — 按时间顺序编写较小的规格,并根据 semantic-ids.md 为每个规格设置自己的 func-id;保留原规格主要行为的替代规格可以沿用原 func-id。第一个替代规格通常负责搭建基础,后续规格则在此基础上逐步增加行为。
  6. 验证功能完整性 — 这一步至关重要。所有替代规格合在一起,必须涵盖原规格描述的 100% 功能。逐一检查原规格中的每种行为、条件和细节,并确认它们恰好出现在一个替代规格中。不得遗漏、弱化或含糊处理任何内容。如果原规格中的任何功能缺失,就将其补充到合适的替代规格中,或另建一个规格。
  7. 验证每个替代规格 — 对每个规格运行 analyze-if-func-spec-too-complex,确认其符合限制。
  8. 检查冲突 — 使用完整的替代规格集合,以及文件中所有现有规格和它们的 requires 链,运行一次 analyze-func-specs。批量分析器会在一次调用中报告所有冲突的规格对(替代规格 × 现有规格,以及替代规格 × 替代规格)——不要逐对循环检查。使用 resolve-spec-conflict 解决报告的每一对冲突,然后对已修改的规格集合重新运行 analyze-func-specs,直到结果为 COMPATIBLE。
  9. 替换文件中的规格 — 删除原有功能(标题和正文),并在其位置插入替代功能,每个功能都以 # <func-id> 为标题并附上正文,同时保留时间顺序。
  10. 同步测试 plain 文件 — 对每个替代功能调用 add-test-scenarios。它会将原测试 plain 文件中的每个场景移至其所测试的替代功能,为尚无场景的结果编写测试场景,并在原 func-id 不再存在时删除原文件。
  11. 再次阅读文件,确认位置和语法正确。

拆分策略

策略 1:分离不同的行为

如果规格捆绑了多个可独立测试的操作,则将每个操作拆分成单独的规格。

之前:

***functional specs***

# manage-recipes
A :User: can create, edit, and delete :Recipe: items, with validation on all fields.

之后:

***functional specs***

# create-recipe
A :User: can create a :Recipe:. Only valid :Recipe: items can be created.

# edit-recipe
A :User: can edit an existing :Recipe:. Validation rules apply to the edited fields.

# delete-recipe
A :User: can delete a :Recipe:.
策略 2:将设置与行为分开

如果规范引入了一个新结构,并立即定义其复杂行为,请将其拆分为设置和行为。

之前:

***functional specs***

# meal-plan-screen
The :MealPlan: screen displays a weekly grid of :Slot: items, allows drag-and-drop reordering, and shows nutritional totals per day.

之后:

***functional specs***

# meal-plan-grid
The :MealPlan: screen displays a weekly grid of :Slot: items.

# reorder-slots
A :User: can reorder :Slot: items within a day on the :MealPlan: screen using drag-and-drop.

# daily-nutrition-totals
The :MealPlan: screen displays nutritional totals for each day.
策略 3:将核心逻辑与横切关注点分开

如果规范将主要功能与错误处理、重试、缓存、分页或日志记录混在一起,请将横切关注点提取到各自的规范中。

之前:

***functional specs***

# fetch-ingredients
:Ingredient: data is fetched from the external API with pagination, retry on transient errors, and caching for 10 minutes.

之后:

***functional specs***

# fetch-ingredients
:Ingredient: data is fetched from the external API.

# fetch-ingredients-paged
:Ingredient: data is fetched from the external API in pages.

# retry-ingredient-fetch
Fetching :Ingredient: data is retried on transient errors.
策略 4:将条件分支分开

如果规范描述了不同的模式或分支,请为每种模式或分支分别编写规范。

之前:

***functional specs***

# generate-meal-plan
:MealPlan: generation depends on :DietType:. Standard plans use round-robin assignment. Restrictive plans filter out excluded ingredients first, then apply round-robin. Custom plans allow manual slot-by-slot selection.

之后:

***functional specs***

# generate-standard-plan
A standard :MealPlan: is generated using round-robin :Recipe: assignment.

# generate-restrictive-plan
A restrictive :MealPlan: is generated.
- Excluded :Ingredient: items are filtered out first.
- Round-robin :Recipe: assignment is then applied.

# assign-custom-plan
A :User: can manually assign :Recipe: items to :Slot: items for a custom :MealPlan:.
策略 5:逐步构建 UI

如果规范描述了完整的屏幕,请将其拆分为布局和各个交互元素。

之前:

***functional specs***

# dashboard-screen
The :Dashboard: screen shows a summary card with stats, a scrollable list of recent :MealPlan: items, a floating action button to create a new plan, and a bottom navigation bar.

之后:

***functional specs***

# dashboard-summary-card
The :Dashboard: screen shows a summary card with :MealFrameStats:.

# dashboard-recent-plans
The :Dashboard: screen shows a scrollable list of recent :MealPlan: items.

# dashboard-new-plan-button
The :Dashboard: screen includes a button to create a new :MealPlan:.
策略 6:提取可复用的技术组件

有时,规范之所以过于复杂,并不是因为它打包了许多行为,而是因为它隐含要求在规范中直接构建一个重要的技术组件,例如引擎、解析器、调度器、布局算法、状态机或同步机制。当复杂性集中在单个组件上时,横向拆分行为并无帮助。此时应将组件提取出来:为它定义一个概念,在链条中更早的位置用专门的规范构建它,然后改写原规范,通过引用该组件来使用它。由于规范会按从上到下的顺序逐步生成,原规范现在所隐含的代码会少得多——它只需连接一个已存在的组件,而不必从头实现。

在第一个引用该组件的规范之前,通过 add-concept 在 ***definitions*** 中定义组件概念。

之前:

***functional specs***

# export-report-pdf
A :Report: is exported to PDF, laying out multi-page tables with repeating headers, page numbers, and charts rendered from :Report: data.

之后:

***functional specs***

# pdf-renderer-tables
:PdfRenderer: lays out multi-page tables from structured content.
- Table headers repeat at the top of each page.
- Each page shows its page number.

# export-report-pdf
A :Report: is exported to PDF using :PdfRenderer:, embedding charts rendered from :Report: data.

提取出的组件规范与改写后的原规范必须共同覆盖原始功能的 100%(步骤 6):原规范必须引用该组件,绝不能重新描述它。将组件的技术和架构选择放在 ***implementation reqs*** 中,而不是功能规范中。如果组件是独立的子系统,或会在多个模块间复用,请使用 create-requires-module / refactor-module 将其提升为独立模块,而不是同级规范。

保留时间顺序

替代规范占据原规范的位置。较早的规范保持不变。第一个替代规范应仅根据其上方的规范就能成立。后续每个替代规范都可以引用此前规范中的行为。

原功能的测试纯文本文件也应以相同方式拆分:每个场景都移至它所测试的替代功能中;不再适用于任何一个替代项的场景应重写;启用一致性测试时,每个替代项都应至少以一个一致性场景结尾(参见 add-test-scenarios)。

验证清单

  • 已从文件中移除原始规范
  • 替换规范合计覆盖原始规范的 100% 功能,没有任何遗漏
  • 每项替换规范所隐含的代码量均 ≤ 200 LOC(已通过 analyze-if-func-spec-too-complex 验证)
  • 替换规范与现有规范之间不存在冲突(已通过一次批量 analyze-func-specs 调用验证)
  • 替换规范彼此之间不存在冲突(由同一次批量调用检查)
  • 替换规范的时间顺序正确
  • 每项替换规范都具有独立意义
  • 替换规范中引用的所有 :Concepts: 均已定义
  • 提取出的任何技术组件均已定义为概念,由其自身更早的规范构建,并且原始规范只对其进行引用(而非重新描述)
  • 替换规范与语言无关
  • 所有规范均已按照 concise-specs.md 精简——拆分不是重新添加说明文字的许可
  • 所有外部接口均保持明确
  • 测试纯文本文件遵循拆分结果:每项替换功能对应一个文件,移动或重写每个原始场景,且没有任何场景绑定到已不存在的 func-id

评论

支持 Markdown