Yadda 3.0.0:AI Agent 时代的 BDD
英文标题:🔶 Yadda 3.0.0: BDD in the Age of AI Agents
JavaScript BDD 库 Yadda 发布 3.0.0,完成 Node-only 化、ES6 现代化、TypeScript 类型定义支持,并移除 CasperJS、PhantomJS、Bower 等过时集成。作者称,大部分现代化工作由 Claude Code 搭配 Opus 4.8 在约一天内完成,完善且独立于生产代码修改的测试套件是保障 Agent 输出质量的关键。文章认为,随着多个编码 Agent 并行开发逐渐可行,人的协调与编排能力正取代单纯编码,成为新的瓶颈。作者进一步指出,BDD 的可执行自然语言规格既可为 Agent 提供领域上下文,也能持续验证实际行为,因此在 Agent 驱动的软件开发中具有新的价值。
中文
Yadda 3.0.0:AI Agent 时代的 BDD
我刚刚将 Yadda 3.0.0 发布到 npm。
如果你还不了解它,Yadda 是一个面向 JavaScript 的 BDD 库。和 Cucumber 一样,它将自然语言规格映射为可执行代码;但它从一开始就被设计为对规格的编写方式限制更少。
这意味着,你不必写成这样:
Given a university, The University of East Anglia
And The University of East Anglia offers a degree course in Computer Science with entry requirements of ABB
And an A-Level graduate, Steve
And Steve has a D in Physics
And Steve has a D in Maths
When Steve applies to study Computer Science at The University of Bouvet Island
Then The University of East Anglia rejects the application
而可以写成这样:
The University of East Anglia offers a degree course in Computer Science
The entry requirements for which are ABB
Steve is an A-Level graduate
With a D in Physics
And a D in Maths
When Steve applies to study Computer Science at The University of East Anglia
They reject his application
两者都是可执行规格。我认为后者明显更易阅读。
Yadda 3 有哪些变化?
Yadda 3.0 的大部分工作都是现代化改造。
Yadda 已经存在很久,仓库中积累了许多面向 JavaScript 生态组件的集成和工具,而其中一些如今本身已经成了历史遗留。Yadda 3 仅支持 Node,移除了浏览器打包以及 CasperJS、PhantomJS、Bower 和 Component 等过时集成;将测试套件迁移至 node:test;采用 Biome 和 lefthook;将源码现代化为 ES6 语法;并新增了包括 Playwright 和 Puppeteer 在内的当前示例。它现在还提供 TypeScript 类型定义。
这些都很实用,但并不特别值得展开讲。这次发布有两点在我看来更为重要。
大部分代码由 Claude 编写
我使用 Claude Code 和 Opus 4.8 完成了 Yadda 的现代化改造。
Yadda 3.0 史诗任务本身也是由 Claude 编写的,它将工作拆分为一系列刻意隔离的阶段:删除过时功能、更新工具链、将机械性格式调整与行为变更分开处理、现代化源码、探索 API 变更、更新示例和 CI,最后完成元数据、文档和 TypeScript 类型定义。
我们在实施每个阶段之前都会先进行规划,随后我基本让 Claude 自行完成工作。它犯的错误少得惊人;更令人印象深刻的是,它识别出了一些相当微妙的边界情况——这些问题在最初看似只是机械式的现代化改造中,很容易被忽略。我几乎没有进行干预。
一个重要因素是,Yadda 原本就拥有完善的测试套件。我还刻意避免要求 Claude 在同一步中修改生产代码及其对应测试。如果一个 Agent 同时修改两者,那么即使测试套件变绿,作为证据的说服力也会变弱,因为它可以在改动实现的同时改变“正确”的定义。将这些变更分离,为 Claude 提供了更强的外部约束。
从开始工作到发布软件包,实际耗时大约一天,而且期间我还在并行处理其他事情。
今年年初,我曾撰文讨论一项实验:为什么人们对 vibe coding 体验的看法如此两极分化。我当时的结论是,结果极大取决于如何使用 Agent。受到严格约束和监督的 Claude,能够非常迅速地产生极佳结果;而在放任状态下,它往往会出现架构漂移、不必要的代码和运营债务。
那只是七个月前,而能力已经有了巨大进展。即便如此,说 Claude 现在只需极少人工干预就能编写这些代码,仍远远不足以描述正在发生的变化。
编码不再是瓶颈
要理解这一趋势的走向,有必要不再只考虑单个开发者与单个编码 Agent 之间的对话,而是设想多个 Agent 并行工作。
目前已经有多种实现方法。你可以直接运行多个 Claude Code 会话。Git worktrees 允许每个 Agent 针对彼此隔离的工作副本进行工作。cmux 等工具让管理一组 Claude 会话变得更方便;而 Claude Code Agent View 则提供了另一种方式,用于查看多个会话正在做什么,以及哪些会话需要关注。
所有这些方式都能让你的开发速度显著快于串行工作,但我很快又碰到了另一个限制:我自己管理并行工作的能力。我可以轻松地同时推动三项任务,有时也能处理四到五项。但超过这个数量后,我开始丢失上下文:每个 Agent 在做什么、已经做了哪些决定、哪项任务正在等待我,以及接下来需要审查什么。
在这一阶段,模型并没有过载,机器也没有过载。瓶颈是负责协调工作的人的能力。我越来越确信,良好的编排将成为下一个重要层次。
并非只有我得出这一结论。我的同事 Marco 在 My AI Engineering Journey 中描述了几乎完全相同的演进过程:从将 AI 用作自动补全工具,到监督和信任 Agent,再到认知负荷成为约束条件的并行 Agent。他在这条道路上比我走得更远,并采取了相应行动:先围绕 Claude Code 和 worktrees 构建了编排 UI Otto,随后又推进到协调实现、审查、反馈和文档的 Agent 流水线。
更重要的一点是,AI 辅助软件开发仍在以极快的速度演进。单个 Agent 的编码能力已经大幅提升,并行执行已经具备实用性,而下一个约束日益变成如何协调所有这些能力。实现这一目标的工具和方法也在同样快速地发展,现在可以说甚至比模型更新本身更重要。
这也让我回到 Yadda。
为什么现在更新一个 BDD 库?
我一直认为 BDD 在多个方面都很有价值。
首先,用自然语言编写需求会迫使你清晰地表达领域概念;更重要的是,它会促使你以一致的方式表达这些概念。如果你在编写实现之前就先写下这些规格,这种领域语言往往会在整个代码库中传播。同样的概念开始出现在类名、函数名、API 定义、数据库模式、CSS 类和用户界面中。这会赋予代码库一种一致性,而这种一致性事后再去实现会异常困难。
其次,可执行规格比传统的程序化测试更容易被理解。产品经理、分析师或领域专家有现实的可能读懂:
When Steve applies to study Computer Science
Then the university rejects his application
而他们不太可能从一个包含 fixtures、mocks、builders 和 assertions 的 Jest 测试中提取出同样的含义。
第三,BDD 为功能测试提供了有用的抽象层。规格描述意图,而步骤实现处理选择器、页面导航和浏览器交互等机制细节。这带来了与 Page Object 模式 类似的部分优势:用户界面的变更通常可以在抽象层内部被消化,而不是泄漏到数百个测试中。
不过,BDD 一直存在成本。BDD 测试在初始阶段需要更长时间来编写。你需要思考语言表述、创建可复用步骤,并抵制将过程式脚本伪装成英语的诱惑。回报会在之后显现:更好的领域建模、更顺畅的沟通,以及更易维护的功能测试。这种延迟回报一直使 BDD 更难被证明是合理的,但我认为 AI 改变了它的经济性。
可执行规格是 Agent 的优质上下文
设想一种正变得越来越可行的工程工作流。
会议会被自动转录,并保存为 GitHub discussions。这些讨论会被分析,并用于更新项目 wiki。系统从 wiki 中挖掘需求和 issues。随后,由一组编码 Agent 接手这些 issues,进行实现、审查和协调。
wiki 可以告诉你,某人认为系统应该做什么。它可以告诉你系统过去做过什么。它甚至可以告诉你 Agent 推断出系统应当做什么。但它本身无法告诉你,系统是否真的做到了。可执行规格可以。这让 BDD 在 Agent 化开发环境中的意义比过去更大。
BDD 中昂贵的部分,是生成并维护规格。AI 让其中大部分工作变得廉价。转录文本、讨论或需求几乎可以轻而易举地被转换为候选规格;人类可以集中精力判断语言和行为是否正确,而不是亲手输入全部内容。一旦被接受,该规格就不再只是文档,而会成为一份契约。
实现 Agent 可以用它理解所需行为。测试 Agent 可以用它确定需要验证什么。审查 Agent 可以用它质疑实现。CI 可以持续验证它。由于它是可执行的,它始终与软件行为保持耦合,这是 wiki 页面永远做不到的。
这里存在一种有趣的反转。BDD 的诞生部分是为了让软件规格对人类更有用,但当大量软件由机器编写时,可执行规格最终可能对机器更有价值。自然语言为 Agent 提供丰富的领域上下文,而可执行步骤确保规格始终扎根于系统的实际行为。
另一个变化是(在 Yadda v3.1.0 中加入):支持使用 GitHub 风格 Markdown 编写功能规格。这让它们更容易在仓库中阅读;更重要的是,它们可以自然地与项目 wiki 以及人类和 Agent 用于理解系统的其他关键知识资产并存。现在,同一份规格可以写成:
# Feature: University applications
## Scenario: Applicant does not meet the entry requirements
- The University of East Anglia offers a degree course in Computer Science
- The entry requirements for which are ABB
- Steve is an A-Level graduate
- With a D in Physics
- And a D in Maths
- When Steve applies to study Computer Science at the University of East Anglia
- They reject his application
它仍然是一份可执行规格,但在 GitHub 上查看时,它的外观和行为都更接近项目中的其他文档。
Yadda 3 已在 npm 上发布,其源代码、文档和示例均位于 GitHub。
English / 原文
Yadda 3.0.0: BDD in the Age of AI Agents
I’ve just published Yadda 3.0.0 to npm.
For anyone unfamiliar with it, Yadda is a BDD library for JavaScript. Like Cucumber, it maps ordinary language specifications to executable code, but it was designed from the ground up to be much less prescriptive about how those specifications are written.
That means that instead of writing something like:
Given a university, The University of East Anglia
And The University of East Anglia offers a degree course in Computer Science with entry requirements of ABB
And an A-Level graduate, Steve
And Steve has a D in Physics
And Steve has a D in Maths
When Steve applies to study Computer Science at The University of Bouvet Island
Then The University of East Anglia rejects the application
you can write:
The University of East Anglia offers a degree course in Computer Science
The entry requirements for which are ABB
Steve is an A-Level graduate
With a D in Physics
And a D in Maths
When Steve applies to study Computer Science at The University of East Anglia
They reject his application
Both are executable specifications. I find the second considerably easier to read.
What’s changed in Yadda 3?
Most of Yadda 3.0 is a modernisation exercise.
Yadda has been around for a long time, and the repository had accumulated integrations and tooling for parts of the JavaScript ecosystem that are now themselves historical curiosities. Yadda 3 is Node-only, removes browser bundling and obsolete integrations such as CasperJS, PhantomJS, Bower and Component, moves the test suite to node:test, adopts Biome and lefthook, modernises the source to ES6 syntax, and adds current examples including Playwright and Puppeteer. It also now ships TypeScript definitions.
All useful, but not especially interesting to write about. There are two things about the release that I think are much more significant.
Claude wrote most of it
I modernised Yadda using Claude Code with Opus 4.8.
The Yadda 3.0 epic, which was itself written by Claude, broke the work into a series of deliberately separated phases: remove obsolete functionality, update the toolchain, perform mechanical formatting separately from behavioural changes, modernise the source, explore API changes, update examples and CI, then finish the metadata, documentation and TypeScript definitions.
We planned each phase before implementing it, and then I largely let Claude get on with the work. It made remarkably few mistakes and, more impressively, identified some fairly subtle edge cases that would have been easy to miss during what initially looked like a mechanical modernisation. I made very few interventions.
One important factor was that Yadda already had a comprehensive test suite. I also deliberately avoided asking Claude to modify production code and the corresponding tests in the same step. If an agent changes both simultaneously, a green test suite becomes weaker evidence because it is free to change the definition of “correct” at the same time as the implementation. Keeping those changes separate gave Claude a much firmer external constraint.
From starting the work to having the package published was roughly a day of elapsed time, and I was doing other things in parallel.
At the beginning of this year I wrote about an experiment asking why experiences of vibe coding were so polarised. My conclusion then was that the results depended enormously on how the agent was used. A tightly constrained and supervised Claude could produce extremely good results very quickly. Left to its own devices, it tended towards architectural drift, unnecessary code and operational debt.
That was only seven months ago, and the capability has moved on enormously. Even so, saying that Claude can now write this code with very little intervention barely scratches the surface of what is changing.
Coding is no longer the bottleneck
To appreciate where this is going, it helps to stop thinking about a single developer having a conversation with a single coding agent and instead consider several agents working in parallel.
There are already several ways to do this. You can simply run multiple Claude Code sessions. Git worktrees let each agent work against an isolated working copy. Tools such as cmux make running a collection of Claude sessions more manageable, while Claude Code Agent View provides another way of seeing what multiple sessions are doing and which ones need attention.
All of these let you build significantly faster than working serially, but I fairly quickly hit another limit: my own ability to manage the parallel work. I can comfortably keep three tasks moving at once, and sometimes four or five. Beyond that, I start losing the context of what each agent is doing, which decisions have been made, which task is waiting for me and what I need to review next.
At that point, the model is not overloaded and the machine is not overloaded. The bottleneck is the human coordinating the work. I’ve become convinced that good orchestration is the next important layer.
I’m not alone in reaching that conclusion. My colleague Marco describes almost exactly this progression in My AI Engineering Journey, moving from AI as autocomplete, through supervised and trusted agents, to parallel agents where cognitive load becomes the constraint. He is further along this journey than I am, and has responded by building Otto, an orchestration UI around Claude Code and worktrees, before moving on to agent pipelines that coordinate implementation, review, feedback and documentation.
The larger point is that AI-assisted software development is still moving extraordinarily quickly. Individual coding capability has improved dramatically, parallel execution is already practical, and the next constraint is increasingly the coordination of all that capability. The tools and approaches for doing so are developing just as quickly, and are now arguably even more important than the model updates.
Which brings me back to Yadda.
Why update a BDD library now?
I’ve always thought BDD was valuable for several reasons.
Firstly, writing requirements in ordinary language forces you to articulate the domain and, more importantly, encourages you to articulate it consistently. If you write those specifications before writing the implementation, that domain language has a habit of propagating through the codebase. The same concepts start appearing in class and function names, API definitions, database schemas, CSS classes and user interfaces. That gives the codebase a coherence that is surprisingly difficult to achieve retrospectively.
Secondly, executable specifications are far more accessible than conventional programmatic tests. A product manager, analyst or domain expert has a realistic chance of understanding:
When Steve applies to study Computer Science
Then the university rejects his application
They are much less likely to extract the same meaning from a Jest test containing fixtures, mocks, builders and assertions.
Thirdly, BDD provides a useful abstraction layer for functional tests. The specification describes intent while the step implementation deals with mechanics such as selectors, navigation and browser interaction. This provides some of the same benefits as the Page Object pattern: changes to the user interface can often be absorbed inside the abstraction instead of leaking through hundreds of tests.
There has always been a cost, though. BDD tests take longer to write initially. You need to think about the language, create reusable steps, and resist the temptation to write procedural scripts disguised as English. The payoff comes later, through better domain modelling, better communication and more maintainable functional tests. That deferred payoff has always made BDD harder to justify, but I think AI changes the economics.
Executable specifications are very good context for agents
Consider an engineering workflow that is becoming increasingly plausible.
Meetings are automatically transcribed and stored as GitHub discussions. Those discussions are analysed and used to update a project wiki. The wiki is mined for requirements and issues. Those issues are then picked up, implemented, reviewed and coordinated by a collection of coding agents.
A wiki can tell you what somebody thought the system should do. It can tell you what the system used to do. It can even tell you what an agent inferred that the system ought to do. It cannot, by itself, tell you whether the system actually does it. An executable specification can. That makes BDD much more interesting in an agentic development environment than it was before.
The expensive part of BDD was producing and maintaining the specification. AI makes much of that work cheap. A transcript, discussion or requirement can be transformed into a candidate specification almost trivially, with a human concentrating on whether the language and behaviour are correct rather than typing it all out. Once accepted, that specification becomes more than documentation. It becomes a contract.
An implementation agent can use it to understand the required behaviour. A testing agent can use it to determine what needs validating. A reviewing agent can use it to challenge an implementation. CI can continuously verify it. Because it is executable, it remains coupled to the behaviour of the software in a way that a wiki page never can.
There is an interesting inversion here. BDD was created partly to make software specifications more useful to humans, but executable specifications may turn out to be even more valuable when much of the software is being written by machines. The natural language gives agents rich domain context, while the executable steps ensure that the specification remains grounded in the behaviour of the system.
One other change (added in Yadda v3.1.0) is support for writing feature specifications as GitHub-flavoured Markdown. This makes them easier to read in the repository and, more importantly, allows them to live naturally alongside the project wiki and the other key knowledge artefacts that humans and agents use to understand the system. The same specification can now be written as:
# Feature: University applications
## Scenario: Applicant does not meet the entry requirements
- The University of East Anglia offers a degree course in Computer Science
- The entry requirements for which are ABB
- Steve is an A-Level graduate
- With a D in Physics
- And a D in Maths
- When Steve applies to study Computer Science at the University of East Anglia
- They reject his application
It remains an executable specification, but when viewed on GitHub it looks and behaves much more like the rest of the project’s documentation.
Yadda 3 is available on npm, and the source, documentation and examples are on GitHub.