CtrlK
BlogDocsLog inGet started
Tessl Logo

product-feature-tech-implement

基于功能设计文档与现有源码,端到端实现一个产品功能:开发、代码 review、测试用例编写与执行, 循环迭代直到测试通过,最终产出用户手册与实现总结文档(保存到当前项目 markdown/ 目录)。 触发条件:用户提供了功能设计文档(PRD/设计文档/需求描述)+ 源码目录(或代码库路径), 并希望"实现这个功能"、"开发这个功能"、"把这个设计文档变成代码"、"做这个功能的开发+测试"、 "完整实现并测试"、"端到端开发",或明确要求按"开发-review-测试"循环推进直到测试通过。 也适用于需要额外运行环境的开发任务,例如 PostgreSQL/MySQL 等数据库插件开发 (可能需要编译、搭建实例、配置参数、初始化、跑测试)、需要启动服务进程才能测试的后端功能、 需要特定运行时环境的库或框架功能。 即使用户只是说"帮我把这个功能做出来"、"按设计文档实现一下"、"这个功能开发完了麻烦测试一下", 但同时给出了设计文档和代码路径,也应使用本 skill。 本 skill 的核心是严格的"开发 ⇄ Review"循环 + "测试者不预先看代码"的盲测试原则, 因此当用户提到"独立测试"、"测试不能看代码"、"先写测试用例再看代码"、"black-box 测试"时, 也应优先使用本 skill。 不适用于:只是要求"写一个脚本"、"改一行代码"、"快速修一个 bug"等轻量级、 无需走完整开发-review-测试闭环的任务;也不适用于纯粹的代码评审(无需新开发功能) 或纯粹的测试用例编写(无设计文档、无需开发)这类单一环节请求—— 这些更适合直接处理而非套用本 skill 的完整闭环流程。

66

Quality

78%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Fix and improve this skill with Tessl

tessl review fix ./skills/skills_for_claude_web/product_feature_tech_implement/SKILL.md
SKILL.md
Quality
Evals
Security

Product Feature Tech Implement

一个把"功能设计文档 + 源码"变成"经过 review、经过测试、可交付"代码的闭环流程。

核心思想很简单:开发者和审查者反复拉锯,直到审查者满意;然后测试者在完全不知道代码长什么样的情况下, 只根据设计文档独立写出测试用例,再去跑这些测试连同已有测试;测试不过就打回开发,测试过了才算完。 这个"测试者不能偷看代码"的约束是整个 skill 里最容易被悄悄破坏、也最值得认真保护的一条规则—— 原因见下面"为什么要盲测试"。

为什么要盲测试

如果测试用例是照着代码写的,那测试只能验证"代码做了它自己以为该做的事",却验证不了 "代码做了设计文档真正要求的事"。这两者的差距正是 bug 藏身的地方:开发者对需求的理解偏差、 遗漏的边界条件、想当然的默认值——这些错误一旦被同一个脑子既写进代码又写进测试,测试就会 和代码一起错,谁也发现不了。让测试者只看设计文档独立写测试,本质上是用"两个互不通气的理解" 互相校验,偏差才会暴露出来。这就是为什么测试阶段要明确写着"千万不要先看代码"——不是走流程, 是这一步存在的全部意义。

整体状态机

┌─────────────────────────────┐
                    │   读取设计文档 / 源码 / 上下文   │
                    │   (PG 插件等场景额外读取依赖)   │
                    └───────────────┬───────────────┘
                                    │
                                    ▼
        ┌──────────────────────────────────────────────────┐
        │  循环 A:开发 ⇄ Review(直到 review 通过)           │
        │                                                    │
        │   developer 子代理 ──写/改代码──▶ reviewer 子代理     │
        │        ▲                              │            │
        │        └──────review 意见 / 修复要求────┘            │
        └───────────────────────┬────────────────────────────┘
                                │ review 通过
                                ▼
        ┌──────────────────────────────────────────────────┐
        │  tester 子代理(独立、不看代码)                      │
        │   - 若本任务此前已写过测试 → 跳过编写,直接复用         │
        │   - 否则:只读设计文档,独立编写新测试用例              │
        │   - 跑【新测试 + 已有测试】(含必要的环境搭建)         │
        │   - 输出测试报告                                     │
        └───────────────────────┬────────────────────────────┘
                                │
                  ┌─────────────┴─────────────┐
                  │ 测试失败                     │ 测试通过
                  ▼                            ▼
        回到循环 A 开头                    任务完成,关闭三个角色
        (带着测试报告去修 bug /              生成用户手册 + 总结文档
         补全未覆盖的功能)

整个外层是一个"无限循环"——没有预先设定的最大轮数,因为一个功能到底要改几轮谁也说不准。 但"无限"不等于"放任不管":每一轮必须真的取得进展(修复了具体问题、补全了具体功能点), 如果连续多轮都在原地打转(同一个问题被反复打回、测试报告和上一轮几乎一样),就不再是 "继续迭代",而是"卡住了"——这时候停下来把情况摊开给用户看,比硬着头皮空转更负责任。 具体判断标准见下面"何时该向用户求助而不是继续循环"。

开始之前:收集必要输入

进入循环前,先确认手上有这些东西,缺什么就问用户要什么(用 ask_user_input_v0 或直接提问都行, 看哪个更顺手):

  1. 功能设计文档:路径或内容。这是 developer 和 tester 共同的"宪法"——两边都依据它工作, 但谁也不许看对方依据它做出的产物(开发者不看测试用例,测试者不看代码)。
  2. 源码目录:现有代码库的路径,开发者要在这个基础上改。
  3. 额外运行依赖(按需):如果功能涉及需要独立运行环境才能测试的场景——最典型的是数据库插件 开发(PostgreSQL/MySQL 等),需要额外确认:
    • 数据库源码/安装路径,编译方式
    • 是否已有现成实例,还是需要本次搭建一套测试集群
    • 必要的连接信息、权限、配置参数
    • 参考 references/postgres-extension.md 了解 PG 插件场景的具体环境搭建步骤 其他场景类推:任何"代码本身之外,测试还依赖外部服务/进程/环境"的情况,都在这一步问清楚, 不要等 tester 子代理跑到一半才发现少了张图纸。
  4. 现有测试套件位置(如果有):tester 子代理需要知道"已有测试"在哪里,才能在新测试之外 一并跑它们,防止改动破坏了原本好用的功能。

如果用户的描述已经包含了以上信息,直接提取使用,不要为了走流程而重复发问。

任务状态文件:让循环记得自己做到哪了

子代理之间不共享记忆,每一轮都是全新开始的对话;如果不显式记录状态,"测试用例是否已经写过" "现在是第几轮"这类信息就会在每次循环里丢失,导致 tester 把测试重写一遍(违反用户的明确要求), 或者整个流程不知道何时该喊停。

在项目目录下维护一个状态文件 markdown/.feature_implement_state.json(隐藏文件,不算交付物, 不要出现在最终汇报里),结构大致如下:

{
  "feature_name": "一句话功能描述,用于文件命名",
  "design_doc_path": "...",
  "source_dir": "...",
  "iteration": 3,
  "loop_a_rounds_this_iteration": 2,
  "test_suite_written": true,
  "test_suite_path": "...",
  "history": [
    {"iteration": 1, "review_verdict": "未通过", "test_verdict": "未运行", "summary": "首版实现,review 发现 3 处问题"},
    {"iteration": 2, "review_verdict": "通过", "test_verdict": "失败", "summary": "review 通过,但测试发现并发场景未处理"},
    {"iteration": 3, "review_verdict": "进行中", "test_verdict": "未运行", "summary": "修复并发问题"}
  ]
}

每次开始新一轮(无论是循环 A 内部还是测试失败后回到循环 A)之前先读这个文件,结束时更新它。 test_suite_written 是关键字段——只要它是 true,tester 子代理这次就不再重新编写测试用例, 而是直接复用 test_suite_path 里已有的测试,把新一轮的代码拿去跑;只有在测试本身也需要因为 设计文档变更而调整时才重写,并且要明确告诉用户"测试用例本身也改了,原因是……"。

角色说明

三个角色的详细职责、输入输出格式、产出要求都写在 agents/ 目录下,进入对应阶段时去读:

  • agents/developer.md —— 子代理 1:开发者
  • agents/reviewer.md —— 子代理 2:代码审查者
  • agents/tester.md —— 子代理 3:测试者(进入这个阶段前,先读它里面关于"如何保证盲测试"的部分

根据运行环境调整执行方式

"子代理"这个词在不同环境里对应不同的实际能力,下面按环境分别说明该怎么落地这个流程。 不确定自己在哪个环境,看当前可用的工具列表里有没有任务派生/子代理类工具,没有就按 "无子代理环境"处理。

有子代理能力的环境(如 Claude Code、Cowork)

这是流程设计的原生形态,按字面执行即可:

  • 循环 A 内,developer 和 reviewer 各自是独立的子代理调用,每次调用把当前所需上下文 (设计文档、上一轮 review 意见、上一轮测试报告——如果有)整理后传入,子代理各自独立工作, 互不偷看对方的"私货"(developer 看不到 tester 写的测试代码细节,tester 完全看不到 developer 写的实现代码)。
  • tester 子代理在被派生时,prompt 里只能包含设计文档和已有测试套件的位置,绝对不能包含 代码目录路径或代码内容,这是物理隔离,比任何"请不要看代码"的口头约束都可靠——这件事的 安全性建立在你没有把代码位置写进 tester 的 prompt 这个事实上,而不是建立在它会不会自觉 遵守约束上。
  • 三个子代理任务都结束、且最终测试通过后,不需要额外动作"关闭"它们——子代理本身是按任务 生命周期存在的,任务完成即结束。

无子代理能力的环境(如 Claude.ai 网页/客户端)

这种环境下,"派生子代理"实际上是你自己依次扮演三个角色,在同一个对话上下文里完成。 这时"测试者不看代码"的物理隔离没有了——你作为同一个 Claude,扮演 developer 时已经读过代码, 扮演 tester 时没法真的"忘记"读过的内容。诚实面对这个限制,用下面的办法尽量减少污染, 而不是假装隔离仍然存在:

  1. 先写测试,再细看代码:进入 tester 阶段时,即使你脑子里有代码的模糊印象,也要先只 重新读一遍设计文档,把测试用例写下来落盘,写完之后才去翻代码细节执行测试。这样测试用例 的设计依据是有记录可查的(设计文档本身),不是凭着刚才读代码时的印象反推的。
  2. 在测试用例文件里写明依据:每个测试用例标注一句"对应设计文档第几节/哪个需求点", 这样事后review的人也能看出测试是不是真的独立于实现的具体写法。
  3. 角色切换时显式声明:在回复里清楚说明"现在切换到 reviewer 角色,只依据设计文档和 增量代码","现在切换到 tester 角色,重新对照设计文档而非刚才看到的实现细节来设计用例"—— 这不是给用户看的表演,是帮你自己在长对话里真正切换思维框架,效果是实打实的。
  4. 如果用户对"测试必须真正独立"这一点要求很高(比如这是个安全敏感场景),可以直接告诉用户 当前环境做不到物理隔离,建议的替代方案是:你先生成测试用例文件,用户开一个新对话/新会话 只把设计文档喂给一个全新的 Claude 实例去写测试,再拿回来给你跑——这是更可靠但更费事的做法, 由用户决定是否需要。

无论哪种环境,"循环 A 直到 review 通过""测试失败打回循环 A"这套状态机逻辑本身不变, 变的只是 developer/reviewer/tester 之间的隔离强度。

何时该向用户求助而不是继续循环

下面这些情况出现时,暂停循环,把情况清楚地告诉用户,而不是埋头继续转:

  • 同一个问题被打回两次以上仍未解决:说明这可能不是实现细节问题,而是设计文档本身有歧义 或矛盾,需要用户澄清意图,开发者和审查者再怎么拉锯也解不开一个本身说不清楚的需求。
  • 测试环境搭建本身失败(比如 PG 实例起不来、依赖装不上)且尝试了合理的排查后依然卡住: 这通常是环境/权限问题,不是代码问题,继续循环不会有帮助。
  • 测试报告和上一轮几乎一样(同样的用例、同样的失败点),说明上一轮的"修复"没有真正起作用, 值得停下来看看是不是 developer 子代理误解了 review 意见或测试报告。
  • 设计文档里的某个需求点在现有代码架构下几乎无法实现,或者实现代价(比如要推翻现有架构) 明显超出了"实现一个功能"的合理范围:这是架构级决策,应该让用户知道并做选择,不该由循环自己 decide。

求助时把当前状态文件里的 history 摘要给用户看一下,让用户能快速看懂"已经试了什么、卡在哪", 而不是从头解释一遍。

任务完成后:用户手册 + 总结文档

测试通过、循环结束后,再做两件事,都是 Markdown 格式,保存到当前项目的 markdown/ 目录:

用户手册(文件名建议 markdown/{功能名}_用户手册.md):写给"会用这个功能但不关心实现细节" 的人看——这个功能是什么、怎么用、有哪些参数/选项、典型使用场景举例、常见问题。不要把实现细节 或开发过程写进去,那是下一份文档的内容。

实现总结文档(文件名建议 markdown/{功能名}_实现总结.md):写给"想知道这个功能是怎么做出来的" 的人看——做了哪些代码改动(文件、模块层级即可,不需要逐行解释)、过程中 review 发现并修复了 哪些问题(这是有价值的信息,说明代码质量是怎么被把关的,不要省略)、测试覆盖了哪些场景、 测试过程中发现并解决了什么问题、最终经过了几轮迭代。可以直接基于状态文件里的 history 整理, 这正是它存在的目的之一。

写完这两份文档后,可以视情况删除或保留状态文件 .feature_implement_state.json——如果用户后续 可能基于同一个状态继续迭代这个功能(比如又来了新需求),保留它会让"循环记得做到哪了"这件事 对未来的请求依然有效;如果这是个一次性任务,清理掉也无妨。

Repository
digoal/blog
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.