clean-room
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClean room
干净室设计
Clean-room design: one party studies the original and writes a specification, a
second party builds from that specification alone, having never seen the
original. The wall between them is the whole point — an implementation you have
read anchors you to itself, and every "improvement" downstream of that anchor is
a variation on what is already there rather than an answer to the problem.
Four phases. The wall stands between phase 2 and phase 3, and it is a real
context boundary — a subagent — not a promise to ignore what you have read.
One named piece of functionality per run; given more than one, ask which. The
output is a proposal. Do not edit the target code; that is a separate ask.
干净室设计:一方研究原有实现并编写规格说明,另一方完全基于该规格说明进行开发,全程不接触原有代码。两者之间的“壁垒”是核心——如果你已经读过原有实现,就会被它束缚,此后所有的“改进”都只是在原有基础上的变体,而非真正针对问题的解决方案。
整个流程分为四个阶段。壁垒存在于第二阶段和第三阶段之间,它是真实的上下文边界——由子代理(subagent)实现——而非仅仅是“忽略已读内容”的承诺。
每次运行仅针对一项明确的功能;若收到多项功能需求,需询问用户优先处理哪一项。输出结果为一份改进提案。请勿直接编辑目标代码,这属于单独的请求范畴。
1. Trace
1. 追踪
Read the target end to end and write down, for the brief:
- Every entry point, and who calls each one.
- The data in and the data out, at the boundary — shapes, types, units, nullability.
- Every branch, and the condition that selects it.
- Every side effect: I/O, network, filesystem, DB, global state, logging, clocks, randomness.
- Every error path and what it does — retries, swallows, propagates, corrupts.
- What it plugs into: interfaces it must satisfy, modules that depend on it, modules it depends on.
- Hard constraints: language, runtime, deployment target, already-installed dependencies, performance and security requirements, compatibility it cannot break.
- How it is tested today, and what currently makes it hard to test.
Then hunt the scars — the obligations a careful read still misses, and the
reason an alternative that looks simpler so often is not:
- Comments carrying workaround, hack, because, don't remove, see issue.
- Defensive branches for states that "cannot happen".
- Test names describing strange inputs.
- and
git logover the target's path, for commits whose message is a fix.git blame - Error handling written for one specific vendor, version, browser, or platform.
- Config flags that exist only to switch something off.
Separate essential (what it must achieve — behaviour, guarantees, contracts)
from incidental (this library, this data structure, this file layout). Only
the essential crosses the wall.
Done when every branch and every side effect is accounted for and the scar hunt
has been run.
通读目标代码,为撰写需求简报记录以下信息:
- 每个入口点及其调用方。
- 边界处的输入输出数据:结构、类型、单位、是否可为空。
- 每个分支及其触发条件。
- 所有副作用:I/O、网络、文件系统、数据库、全局状态、日志、时钟、随机数生成。
- 所有错误路径及其处理方式:重试、忽略、传播、数据损坏。
- 代码的依赖关系:必须满足的接口、依赖该模块的其他模块、该模块依赖的其他模块。
- 硬约束:编程语言、运行时环境、部署目标、已安装的依赖、性能与安全要求、不可破坏的兼容性。
- 当前的测试方式,以及当前导致测试困难的因素。
随后寻找“遗留痕迹”——即仔细阅读仍可能遗漏的隐性需求,也是看似更简洁的替代方案往往不可行的原因:
- 包含 workaround(临时方案)、hack(取巧实现)、because(原因说明)、don't remove(请勿删除)、see issue(查看问题)等字样的注释。
- 针对“理论上不可能出现”的状态添加的防御性分支。
- 描述特殊输入的测试用例名称。
- 目标代码路径的 和
git log记录,查找包含修复说明的提交。git blame - 针对特定厂商、版本、浏览器或平台编写的错误处理逻辑。
- 仅用于关闭某项功能的配置开关。
区分核心需求(必须实现的行为、保证、契约)与非核心细节(使用的库、数据结构、文件布局)。只有核心需求可以跨越壁垒传递到下一阶段。
当所有分支和副作用都已梳理完毕,且完成了遗留痕迹的排查后,本阶段结束。
2. Brief
2. 需求简报
Write the brief to a scratch file. It is read by someone who has never seen this
repository and never will:
markdown
undefined将需求简报写入临时文件。阅读这份简报的人从未见过也不会接触当前代码库:
markdown
undefinedProblem
问题
What goes wrong in the world when this does not exist. Two or three sentences.
如果该功能不存在,业务场景中会出现哪些问题。用2-3句话描述。
Goal
目标
The observable outcomes. Behaviour and guarantees, not mechanism.
可观察的预期结果。聚焦行为与保证,而非实现机制。
Context
上下文
What this plugs into: the callers, the callees, the data crossing each boundary.
Anything it must interoperate with.
该功能的对接对象:调用方、被调用方、跨边界传递的数据。所有必须兼容的对象。
Hard constraints
硬约束
Language, runtime, deployment target, dependencies already present, performance,
security, compatibility. Say which are immovable and which are preferences.
编程语言、运行时环境、部署目标、已存在的依赖、性能、安全、兼容性。说明哪些是不可变更的,哪些是优先选项。
Obligations that must hold
必须满足的隐性需求
The scars from the trace, stated as requirements. "Handles a payload of 0 bytes",
not "there is an if-statement for empty payloads".
从追踪阶段发现的遗留痕迹转化而来的需求。例如:“处理0字节的负载”,而非“存在针对空负载的if语句”。
Out of scope
范围外内容
What this must not try to solve.
该功能无需解决的问题。
Done looks like
验收标准
How correctness is observed from outside. The acceptance criteria.
Written in problem language throughout. Two checks before it crosses the wall:
1. It names no file, function, class, or library from the implementation.
2. Every line is satisfiable by at least two visibly different implementations.
A line only one implementation could satisfy is a *how* — rewrite it or cut it.
The second check is the one that matters. A brief written in the shape of the
code — same decomposition, same nouns, same seams — re-anchors the designer just
as effectively as handing over the source.如何从外部验证功能的正确性。即验收条件。
全程使用业务问题语言描述。在传递到壁垒另一侧前,需完成两项检查:
1. 简报中未提及原有实现中的任何文件、函数、类或库。
2. 每一项需求至少能通过两种明显不同的实现方式满足。若某条需求只能通过一种实现方式满足,说明它描述的是“实现方法”——需重写或删除该内容。
第二项检查至关重要。如果简报的结构与原有代码一致(相同的分解方式、相同的术语、相同的拆分点),那么即使没有直接提供源代码,也会同样束缚后续的设计工作。3. Design, behind the wall
3. 壁垒后的设计
Dispatch one subagent (, or whatever this harness calls an
agent with web access) with the brief pasted into its prompt. It works from the
brief and the open internet; the repository stays shut. Instruct it:
general-purposeYou are designing a solution from a brief. You have never seen an implementation and will not look for one — the repository is out of bounds. Design the simplest, most robust thing that satisfies the brief.Take the first option that holds: the standard library; a native platform feature; a dependency the brief says is already installed; one small, well-maintained third-party library; only then code written from scratch.Search the web for how this problem is normally solved and for libraries that solve it. For each library you propose, gather the evidence — latest release, release cadence, whether issues get maintainer replies, how many maintainers, adoption, license, archived or deprecated status — and sort it into one bucket:
- Alive — releasing, maintainers answering issues.
- Finished and fine — quiet, but stable API, not archived, no deprecation notice, security fixes still land. Age is not decay; a small library can be done.
- At risk — one maintainer, issues unanswered, forks pulling ahead.
- Dead — archived, deprecated, or no maintainer response in a year.
Recommend only from the first two.answers most of this without an API key; fall back to the repository host where it has no data.https://api.deps.dev/v3Mark every obligation in the brief as met, unmet, or unclear against your own design. Every one of them, explicitly.Return: the design in the fewest moving parts you can manage; each component and what it is responsible for; the libraries with their bucket and evidence; the seams that make it testable and the test plan those seams enable; the failure modes and what happens at each; and the two or three places this design could turn out to be wrong.
Without a real subagent there is no wall — say so plainly rather than running
phase 3 in the same context and calling it clean. If the designer could not
reach the web, label the result: the alternative was invented from first
principles, and its account of how the world solves this is unverified.
Scan the returned design for paths and symbols from the repository. The wall is
structural for what you have already read, but the subagent keeps its own file
tools. On a hit, re-run once with a firmer prompt; on a second hit, ship the
judgement labelled anchored.
Done when every library carries a bucket, every obligation carries a mark, and
the test seams are named.
派遣一个子代理(subagent)(通用型代理,或当前工具链中具备网络访问权限的代理),将需求简报粘贴到其提示词中。子代理仅基于需求简报和公开互联网进行工作,完全不接触代码库。需对子代理下达如下指令:
你需要基于需求简报设计解决方案。你从未见过任何现有实现,也不会去查找——代码库是完全禁止访问的。设计满足需求简报的最简、最健壮的方案。按优先级选择实现方式:标准库;原生平台特性;需求简报中说明已安装的依赖;小型且维护良好的第三方库;最后才考虑从零开始编写代码。通过网络调研该问题的常规解决方案及相关库。对于每个拟推荐的库,收集以下证据——最新版本、发布频率、维护者是否回复问题、维护者数量、采用度、许可证、是否归档或废弃——并将其归类到以下类别:
- 活跃——持续发布新版本,维护者及时回复问题。
- 稳定可用——更新频率低,但API稳定,未归档,无废弃通知,仍会发布安全修复。老旧并不等同于失效;小型库也可能处于成熟稳定状态。
- 风险较高——仅一位维护者,问题无人回复,衍生分支发展更快。
- 已废弃——已归档、标记为废弃,或一年内无维护者响应。
仅推荐前两类库。无需API密钥即可获取大部分上述信息;若无数据,可 fallback 到代码托管平台查询。https://api.deps.dev/v3将需求简报中的每一项需求标记为已满足、未满足或不明确,对应你设计的方案。每一项需求都必须明确标记。返回内容:尽可能简化的设计方案;每个组件的职责;推荐库的类别及证据;保证可测试性的拆分点及对应的测试计划;故障模式及处理方式;该设计可能存在的2-3个潜在问题。
如果没有真实的子代理,就无法建立有效的壁垒——需明确说明这一点,而非在同一上下文中执行第三阶段并声称是干净室设计。如果设计无法访问网络,需标记结果:该替代方案是基于基本原则推导的,其关于行业常规解决方案的描述未经验证。
检查返回的设计中是否出现代码库中的路径或符号。对于你已阅读过的内容,壁垒是结构性的,但子代理有其独立的文件工具。若发现匹配项,需重新运行一次并强化提示词;若再次出现匹配项,需将判断结果标记为“受原有实现束缚”。
当所有推荐库都已归类、所有需求都已标记、可测试拆分点已明确后,本阶段结束。
4. Verdict
4. 评估结论
Now put the plan next to the code and judge, element by element, on four axes:
correctness against the brief, simplicity (moving parts, lines, concepts
a newcomer must hold), robustness (failure modes actually handled), and
testability (seams, determinism, no hidden I/O).
Find the fence first. For every behaviour the code has that the plan lacks, ask
why the code does it — Chesterton's fence. Each one resolves to:
- In the brief, dropped by the plan — the plan is incomplete, not simpler. Score it as incomplete.
- Absent from the brief — phase 1 missed it. Go and find out why the code does it before scoring anything.
- Genuinely dead — the code is carrying weight nothing needs. That is a finding in its own right.
A plan is only simpler when it does the same job with less.
Then the gate. Recommend a change only when all three hold:
- The alternative meets every obligation. If it misses one because the brief was wrong, fix the brief — never waive the obligation.
- The win fits in one sentence and is something the reader cares about: code no longer maintained, a class of bug gone, a seam for testing, maintenance shifted onto a live library.
- The win survives its own cost — migration size, migration risk, and the risk carried by any new dependency.
Any miss and the verdict is Keep. A consolation change is a defect in this
process, not a courtesy.
Pick one verdict:
- Replace — the plan wins on the axes that matter here. Propose it as a sequenced set of changes, smallest shippable step first.
- Graft — parts of the plan win. Propose each part as its own independent change, ordered by value over effort. Say explicitly which parts of the current code stay and why.
- Keep — the current implementation wins. Say so plainly and stop.
Report testability findings under every verdict, Keep included: a design that is
right but untestable still earns a proposed refactor for its seams.
For each proposed change give: what changes, which axis it wins on, rough size,
what it risks, and how it is verified. End with the open questions the trace
could not answer.
现在将设计方案与原有代码逐一对比,从四个维度进行评估:符合需求简报的正确性、简洁性(移动部件数量、代码行数、新手需理解的概念数量)、健壮性(实际处理的故障模式)、可测试性(拆分点、确定性、无隐藏I/O)。
首先找出“切斯特顿围栏”。对于原有代码具备但设计方案缺失的每一项行为,需询问代码为何要实现该行为——即切斯特顿围栏原则。每个问题的结果分为三类:
- 需求简报中存在,但设计方案遗漏——设计方案不完整,并非更简洁。需标记为不完整。
- 需求简报中未提及——第一阶段追踪遗漏了该需求。在进行评估前,需先查明代码实现该行为的原因。
- 真正的冗余代码——代码承载了无实际用途的逻辑。这本身就是一项重要发现。
只有当设计方案在完成相同工作的前提下使用了更少的资源,才能称之为更简洁。
随后判断是否需要变更。只有同时满足以下三个条件时,才建议进行变更:
- 替代方案满足所有需求。若因需求简报错误导致遗漏某项需求,需先修正需求简报——绝不能放弃该需求。
- 收益可以用一句话概括,且是读者关心的内容:移除不再维护的代码、消除某类bug、增加可测试拆分点、将维护工作转移到活跃的第三方库。
- 收益大于成本——包括迁移规模、迁移风险,以及新增依赖带来的风险。
只要有一项不满足,结论就是“保留”。妥协性的微小变更属于流程缺陷,而非出于礼貌。
选择以下结论之一:
- 替换——设计方案在当前场景的关键维度上更优。建议将其拆分为一系列可逐步交付的变更,从最小可发布的步骤开始。
- 移植——设计方案的部分内容更优。建议将每个部分作为独立的变更,按价值/投入比排序。明确说明原有代码中哪些部分会保留及原因。
- 保留——当前实现更优。需明确说明并停止后续建议。
无论结论是哪种(包括保留),都需报告可测试性相关的发现:即使设计方案是正确的,但如果不可测试,仍需提出针对拆分点的重构建议。
对于每一项建议的变更,需说明:变更内容、优化的维度、大致规模、潜在风险、验证方式。最后列出追踪阶段无法解答的开放性问题。