测试驱动开发与观察循环:提升开发效率的核心原则

本文深入探讨测试驱动开发(TDD)及其背后的观察-决策-行动(ODA)循环原则,分析如何通过缩短观察周期提升开发效率,并讨论工具如持续集成和调试器在优化信息传递中的作用。

测试驱动开发与观察循环

2014年5月9日 by Max Kanat-Alexander

今天,Kent Beck、Martin Fowler和David Heinemeier Hansson之间进行了一场关于测试驱动开发(TDD)本质和使用的有趣讨论。TDD是一种先写测试再写代码的方法。

对话中的每位参与者对如何编写代码都有不同的个人偏好,这很合理。然而,从每位参与者的个人偏好中,可以提取出一个相同的原则:“我需要在做决策之前观察一些东西。” Kent经常(尽管不总是)喜欢先写测试,以便在编码时观察它们的行为。David经常(尽管不总是)想先写一些初始代码,观察它来决定如何编写更多代码,依此类推。即使他们谈论替代方法(例如Kent谈到他不使用TDD的时候),他们仍然总是谈到将观察作为开发过程的内在部分。

有人可能最小化这一点,说它只与调试或测试相关。确实,它在这些领域很有用,但当你与许多资深开发者交谈时,你会发现这个想法实际上是他们整个开发工作流程的基本基础。他们希望看到一些东西来帮助他们关于代码做出决策。这不仅仅发生在代码完成或有bug时——它发生在软件生命周期的每一刻。

这是一个如此广泛的原则,以至于你可以说所有软件开发的循环是:观察 → 决策 → 行动 → 观察 → 决策 → 行动 → 等等。

如果你想要一个术语,你可以称之为“观察循环”或“ODA”。

示例

我所有这些是什么意思?让我们举一些例子来让它更清晰。当进行TDD时,循环看起来像:看到一个 problem(观察)。决定解决问题(决策)。写一个测试(行动)。看测试并看API是否看起来好(观察)。如果看起来不好,决定如何修复它(决策),更改测试(行动),并重复观察 → 决策 → 行动,直到你喜欢API的样子。现在API看起来好了,运行测试并看到它失败(观察)。决定如何使测试通过(决策)。写一些代码(行动)。运行测试并看到它通过或失败(观察)。如果失败,决定如何修复它(决策)并写一些代码(行动),直到测试通过(观察)。根据软件设计原则、问题知识或编写先前代码时获得的数据决定下一步做什么(决策)。依此类推。

另一种有效的方法是先写代码。与上述序列的区别是,步骤3将是“写一些代码”而不是“写一个测试”。然后你观察代码本身以做出进一步决策,或者在代码后写测试并观察它们。

有许多有效的过程。

开发过程与生产力

有趣的是,据我所知,每个有效的开发过程都遵循这个循环作为其主要指导原则。甚至像敏捷这样覆盖整个团队的大规模过程也内置了这一点。事实上,敏捷在某种程度上是尝试让团队有更短的观察-决策-行动循环(每几周),而不是之前破碎的模型(瀑布,又名“大设计前期”),后者需要数月或数年来完成一个循环。

所以,更短的循环似乎比更长的循环更好。事实上,大多数开发者生产力的目标可能仅仅通过将ODA循环缩短到开发者、团队或组织的最小合理时间段来实现。

通常,你可以通过专注于观察步骤来实现这些更短的循环。一旦你做到了,循环的其他两部分往往会自行加速。(如果它们没有,还有其他补救措施,但那是另一篇文章。)

在观察中需要解决三个关键因素:信息传递给开发者的速度(例如,有快速测试)。传递给开发者的信息的完整性(例如,有足够的测试覆盖率)。传递给开发者的信息的准确性(例如,有可靠的测试)。

这帮助我们理解近几十年来某些开发工具成功背后的原因。持续集成、生产监控系统、分析器、调试器、编译器中更好的错误消息、突出显示坏代码的IDE——几乎所有“有效”的东西之所以有效,是因为它使观察更快、更准确或更完整。

有一个陷阱——你必须以人们实际可以接收的方式传递信息。如果你向人们倾倒大量信息而不让他们容易找到他们关心的特定数据,数据就变得无用。如果没有人收到生产警报,那么它就不重要。如果开发者从不确信接收信息的准确性,那么他们可能开始忽略它。你必须成功沟通信息,而不仅仅是生成它。

第一个ODA

有一个“大ODA循环”代表软件开发的整个过程——看到一个 problem,决定一个解决方案,并将其作为软件交付。在那个大循环中,有许多较小的循环(看到对一个功能的需求,决定功能应该如何工作,然后编写功能)。甚至还有更小的循环(观察单个更改的需求,决定一个实现,写一些代码),依此类推。

最棘手的部分是任何这些序列中的第一个ODA循环,因为你必须在没有先前决策或行动的情况下进行观察。

对于“大”循环,似乎你开始时没有什么可观察的。还没有代码或计算机输出来看!但实际上,你至少从观察自己开始。你有你周围的环境。你有其他人可以交谈,一个世界可以探索。你的第一次观察通常不是代码,而是现实世界中要解决的某种东西,以某种方式帮助人们。

然后当你在做开发时,有时你会到达一个点,你必须决定“我下一步做什么?”这就是了解软件设计法则可以帮助的地方,因为你可以将它们应用于你编写的代码和你观察到的问题,这让你决定工作的顺序。你可以将这些原则视为一种二手观察形式——数千人年的经验压缩成法则和规则,可以帮助你现在做决策。二手观察是完全有效的观察,只要它是准确的。

你甚至可以将观察过程本身视为它自己的小ODA循环:看世界,决定将注意力放在某物上,将注意力放在那件事上,观察它,基于此决定观察其他东西,等等。

可能有无穷的方式使用这个原则;以上所有仅代表几个例子。

-Max

评论

Alireza 说:2014年5月21日下午8:17

嗨,好文章。似乎完全有道理!!我最近也读了你的书《代码简洁》。我真的很喜欢它,不仅喜欢,我还在当前开发的软件中应用了它的一些原则。非常感谢你的伟大工作。

回复 Max Kanat-Alexander 说:2014年8月24日下午4:06

哇,太棒了!-Max

Mariano Roccasalva Firenze 说:2014年7月1日下午12:27

嗨Max,结论“软件开发是:观察 → 决策 → 行动 → 观察 → 决策 → 行动 → 等等。”让我想起了伽利略的科学方法。伟大,好工作 Mariano

回复 Max Kanat-Alexander 说:2014年8月24日下午4:06

哦有趣!我没读过他的方法。-Max

什么是测试驱动开发? | 软件专家 说:2017年1月3日上午10:00

[…]测试用例在设计时甚至开发还没有开始。一旦开发开始,测试用例用于通知项目的方向。这创建了更好地符合用户潜在需求的代码。由于测试用例将[…]

Matt B 说:2017年4月11日上午7:53

你重新发现了OODA循环!也许还有六西格玛的计划-执行-检查-行动。顺便说一句,我更喜欢你的表述。我从未真正理解“定向”到底是什么意思,以及为什么需要它。

Racquel from Philippines 说:2017年4月16日上午2:46

太有趣了…它有帮助..

代码简洁 » 如何成为一个伟大的程序员:意识、理解和责任 说:2017年12月20日上午11:00

[…]语言和屏幕上的颜色。但如果不实际看一些东西来理解,我永远无法知道[…]

什么造就了伟大的开发者体验? » 代码简洁 说:2025年4月15日上午3:03

[…]还值得注意的是,每个循环都是某种形式的观察、决策、行动循环,我在其他地方广泛写过。如果你致力于改善开发者体验,最好的方法之一是让它[…]

留下回复取消回复

联系 关于 书:理解软件 书:代码简洁

输入你的邮箱… 订阅

Max Kanat-Alexander 6月27日

我目前认为,AI代理可以成功生成的输出数量和质量取决于:1. 模型的质量。2. 代理的质量。3. 输入的质量(如提示或其他上下文)。4. 代理可以独立运行的确定性、客观验证的质量。

我目前认为,除非你是模型开发者,最重要的部分是“确定性、客观验证”。

简单来说,如果你告诉AI做某事,它需要某种方式能够验证它做了正确的事,靠自己。在软件中,这通常意味着运行测试、linter等,如果系统做了错误的事就会失败。

这意味着你的测试和验证工具越好,你从模型得到的输出就越好。不仅仅是测试的数量。它们必须是好的测试,有智能断言和好的错误消息。

它还意味着代理成功涉及思考如何将任务分解成可以各自通过自动化测试、linter等客观验证的单个部分。

作为说明,输入的质量也很重要并在我们控制之下。如果我们写更好的文档和更清晰的代码,代理做得更好。令人惊讶的是,几乎所有帮助人类写代码的东西也帮助代理。

阅读更多 2510 分享

Max Kanat-Alexander 6月4日

技术债务有价值的想法 mostly 是一个神话。当你做出一个糟糕的软件工程决策时,它会在几小时、几天或几周内减慢你的速度。那是上限。许多人认为需要数月或数年才能看到在软件设计上偷工减料的影响,但那 simply 不是真的。它几乎立即开始。做正确事的成本通常是几小时,也许一天,你几乎总是立即 recover 那时间。也就是说,做对通常花的时间与做错花的时间相同。“等等,什么?那怎么可能?我们偷工减料是为了节省时间!”它几乎总是结果根本不节省你时间!它使处理变更更混乱。它使代码审查更长。它在测试中以更混乱的方式失败,需要更长时间调试。它几乎从不节省你实际时间。

偶尔,你路径上有一些“岩石”如此巨大,你 simply 无法移动它。没有人应该花三个月设计一个新工具,只是为了你可以交付一个一天的功能,一次。但那是技术债务决策的 tiny, tiny 部分。

这变得更疯狂,因为如果你随着进行做对一切(你总是重构系统,使其看起来像是设计来做 exactly 它现在做的),那么一切始终保持相对容易。但如果你偷工减料,一切变得 compoundingly 更困难,到点你生成没有人能移动的“岩石”。复杂性不是某种线性东西,你可以后来回去投资线性量时间修复。你绝对可以让自己陷入一个如此糟糕的情况,你公司中没有人有时间或专业知识修复它。

这一切感觉如此无辜:“让我们 just 偷一些工减一些料,它将帮助我们 meet 这个截止日期,”(一个截止日期通常是想象的 anyway,你可以滑几周没有后果)。“很难弄清楚如何做对,我们可以拖延它吗?”然后 bam,非常快你发现自己在一个沼泽中,一切都很困难,“我们不知道为什么!”

我留给你最后一件事:当我直接编码我生命的每一天时,我对此完全 uncompromising。我基本上无法看坏代码——我必须重构它或我不能做工作。而且 somehow,我从未错过那部分我整个职业生涯中的单个截止日期。

阅读更多 12942 分享

Max Kanat-Alexander 5月30日

我估计,我每看到或被告知一万条坏建议,才收到一条好建议。互联网充满坏建议,因为文明充满坏建议。文明充满坏建议,因为全球教育大多不教人们思考、研究或确定什么是真的。相反,它教人们记忆和重复事实,其中大多数不重要、不真实或无用。

所以一般来说,我们不应惊讶互联网(尤其是社交媒体)充满不重要、不真实或无用的信息。它不是全部那样——我在网上学到了大量非常有用的东西。有大量有价值的内容。我会说,人们对事物的意见,无论是在报纸、博客文章、论坛还是其他, rarely 有那价值, though。

所以要点是什么?嗯,最好有某种方式确定某物是否重要或有用, before 你开始依赖它或向他人重复它。最简单的工具是说:“它有效吗?”这条数据可靠地帮助你完成某事吗?它100%的时间有效,还是更少?

对于许多帖子,你会发现:这条数据根本不帮助你做任何事。

阅读更多 249 分享

Max Kanat-Alexander 5月29日

你对系统做的任何更改在推出时会收到来自某人的负面反馈。这发生不是因为每个更改有问题,而是因为用户习惯系统的工作方式,他们不喜欢它改变了。他们可能批评新用户界面,或有某种情感论点关于为什么新东西“烂”,但通常他们真的只是 upset 任何更改发生了。这不是不寻常的;它是存在于几乎所有人类中的一个因素。人们往往有某种 appetite 对于他们愿意在一段时间内经历多少更改,如果你超出那,他们变得 upset。

重要的是识别 when 人们的反馈 simply 是这种“更改厌恶” vs 关于某物有价值的真实反馈。有几种方式告诉:1. 更改厌恶通常持续3到10天。如果你在推出更改后头3到10天内从用户收到反馈,并且那相同反馈不是由大量用户提供,值得考虑用户的响应是否只是更改厌恶。2. 更改厌恶反馈通常是情感的。它可能是侮辱性的。它可能表达为只是一个意见(“新菜单的颜色丑”)vs 一个事实(“我测量了,新工具比旧工具慢10倍。”)。

你在管理更改时试图避免的是创建如此多更改厌恶,以至于你引起反抗。反抗基本上看起来像如此多人变得愤怒,他们去找你的管理层,他们停止你的工作。当有疑问时,向更少人以更慢的扩展速率推出更小更改。随着时间的推移,你将学习你可以推出多少更改,多快。永远,永远不要做“大爆炸”发布,其中所有用户一次经历大规模更改。

现在,所有这些 said,永远不要归因所有反馈到“更改厌恶”。通常人们确实有合法的反馈。如果许多人提供你相同事实反馈,并且你看它,他们的反馈有道理,你认为修复它会改进产品,那非常可能不是更改厌恶。另外,说“这只是更改厌恶”不意味着你应该完全忽略反馈。你至少应该承认它,让人们知道他们被听到。它确实意味着你不应该与那人争论或尝试与他们推理,因为他们有情感反应,你尝试“逻辑”他们出来不会帮助任何人。如果你认为是更改厌恶,你承认他们,他们只是继续与你战斗,有时你应该只是忽略他们并继续做你的工作。如果他们3天后回来有一个更合理的论点,那么你知道不只是更改厌恶,而且他们可能那时更 helpful anyway。

阅读更多 274 分享

加载更多

© 2025 版权所有。由 The Fox 提供支持。 管理同意联系 关于 书:理解软件 书:代码简洁

转到顶部

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计