Redian新闻
>
ZOMBIES:为什么简洁性是交付健壮软件的关键(五) | Linux 中国

ZOMBIES:为什么简洁性是交付健壮软件的关键(五) | Linux 中国

科技
 
导读:当你坚持最简场景时,你最终会得到最简单的解决方案。                                 
本文字数:4140,阅读时长大约:6分钟

当你坚持最简场景时,你最终会得到最简单的解决方案。

在前面的文章中,我已经解释了为什么将编程问题看作一整群丧尸来处理是错误的。我用 ZOMBIES 方法来解释为什么循序渐进地处理问题更好。

ZOMBIES 表示以下首字母缩写:

◈ Z – 最简场景(Zero)
◈ O – 单元素场景(One)
◈ M – 多元素场景(Many or more complex)
◈ B – 边界行为(Boundary behaviors)
◈ I – 接口定义(Interface definition)
◈ E – 处理特殊行为(Exercise exceptional behavior)
◈ S – 简单场景用简单的解决方案(Simple scenarios, simple solutions)

在系列的前四篇文章中,我展示了 ZOMBIES 方法的前六个原则(LCTT译注:原文为前五个,应为笔误)。

第一篇中 实现了最简场景🔗 linux.cn,它为代码提供了最简可行路径。第二篇文章中执行了 单元素场景和多元素场景上的测试🔗 linux.cn。第三篇中介绍了 边界和接口🔗 linux.cn。第四篇中处理 特殊行为🔗 linux.cn。在本文中,我将介绍最后一项:简单场景用简单的解决方案。

简单场景用简单的解决方案

回顾这个网购 API 的实现过程,你会发现总是有目的性地坚持考虑最简单的场景。在这个过程中,最终你会得到最简单的解决方案。

ZOMBIES 方法通过坚持简洁性来帮助你交付健壮优雅的解决方案。

胜利了吗?

似乎一切工作都结束了,一个不那么认真负责的工程师很可能会宣布胜利。但开明的工程师总是会探索得更深一点。

我一直推荐做 变异测试🔗 opensource.com(mutation testing)。在圆满结束这个练习项目,开始新的征程之前,用变异测试来敲打敲打你的解决方案是明智的。况且你也不得不承认,变异很适合对付丧尸的。

你可以在开源网站 Stryker.NET🔗 stryker-mutator.io 上进行变异测试。

Mutation testing

看起来有一个存活的变异体。这可不是好兆头。

这意味着什么呢?当你自认为解决方案无懈可击的时候,Stryker.NET🔗 Stryker.NET 却表示在你的地盘上并非一切安好。

让我们来看看这个存活下来的烦人变异体:

Surviving mutant

变异测试工具将

  1. if(total > 500.00) {

变异为:

  1. if(total >= 500.00) {

然后运行测试,结果对于这个变化没有一个测试失败。如果业务处理代码中发生了一处变动却没有任何一个测试失败,这就意味着你遇到一个存活的变异体。

为什么要在意变异体

为什么存活的变异体是麻烦的征兆呢?因为你写的业务处理逻辑代码控制着整个系统的行为。如果业务处理逻辑改变,系统的行为也应该随之改变。而系统行为的改变应该会导致测试表示的期望被违反。如果没有期望被违反,那就说明这些期望对系统行为的描述还不够准确。这也意味着你的业务处理逻辑中存在漏洞。

要解决这个问题,你需要干掉这个存活下来的变异体。要怎么做呢?一般来说,有存活的变异体意味着有期望被遗漏了。

仔细检查代码,梳理已定义的期望,看看漏掉了什么:

◈ 期望 0:新建购物框里有零个商品(这隐含了总价为 ¥0)。
◈ 期望 1:向购物框添加一件商品的结果是购物框里有一件商品,如果这件商品的价格是 ¥10,那么总价为 ¥10。
◈ 期望 2:向购物框添里加入一件价值 ¥10 的商品,再加入一件价值 ¥20 的商品,总价是 ¥30 。
◈ 期望 3:关于从购物框移除商品的期望。
◈ 期望 4:总价大于 ¥500 时打,享受九折优惠。

缺了什么呢?根据变异测试报告,你没有定义订单总价刚好为 ¥500 的销售策略。你已经定义订单总额大于 ¥500 和小于 ¥500 时的情况。

定义边界情况的期望:

  1. [Fact]
  2. public void Add2ItemsTotal500GrandTotal500() {
  3. var expectedGrandTotal = 500.00;
  4. var actualGrandTotal = 450;
  5. Assert.Equal(expectedGrandTotal, actualGrandTotal);
  6. }

第一步先写一个假的实现让测试失败。现在共有 9 个微测试。其中 8 个通过,第 9 个失败了:

  1. [xUnit.net 00:00:00.57] tests.UnitTest1.Add2ItemsTotal500GrandTotal500 [FAIL]
  2. X tests.UnitTest1.Add2ItemsTotal500GrandTotal500 [2ms]
  3. Error Message:
  4. Assert.Equal() Failure
  5. Expected: 500
  6. Actual: 450
  7. [...]
  8. Test Run Failed.
  9. Total tests: 9
  10. Passed: 8
  11. Failed: 1
  12. Total time: 1.5920 Seconds

将硬编码值替换成正样例的预期代码:

  1. [Fact]
  2. public void Add2ItemsTotal500GrandTotal500() {
  3. var expectedGrandTotal = 500.00;
  4. Hashtable item1 = new Hashtable();
  5. item1.Add("0001", 400.00);
  6. shoppingAPI.AddItem(item1);
  7. Hashtable item2 = new Hashtable();
  8. item2.Add("0002", 100.00);
  9. shoppingAPI.AddItem(item2);
  10. var actualGrandTotal = shoppingAPI.CalculateGrandTotal(); }

共添加了两件商品,一件价值 ¥400,另一件价值 ¥100,总价是 ¥500。调用计算总价的函数,期望的总价是 ¥500。

运行,9 个测试全部通过!

  1. Total tests: 9
  2. Passed: 9
  3. Failed: 0
  4. Total time: 1.0440 Seconds

现在是揭晓真相的时刻。这个新增的期望能够清理掉所有的变异体吗?运行变异测试来看看结果:

Mutation testing success

成功了!10 个变异体全都被干掉了。太棒了!现在你可以放心地发布这个 API 了。

结语

如果从这次练习中有什么收获的话,那就是 技术性拖延(skillful procrastination) 这一概念的提出。这个是一个重要的概念,因为我们中的许多人往往会在客户描述完他们的问题之前,就盲目地去设想解决方案。

主动拖延

拖延对于软件工程师来说并不是一件容易的事情。我们总是急于动手写代码。我们熟悉各种设计模式、反模式、编程原则和现成的解决方案。我们总是迫不及待想将它们应用到可执行的代码中,并且倾向于一次性做大量的工作。所以在行动之前仔细考虑每个步骤是一种美德。

这个练习说明 ZOMBIES 方法能够通过一系列深思熟虑的小步骤来帮你实现解决方案。但是有一点需要特别注意,根据 Yagni🔗 martinfowler.com 原则,这些深思熟虑常常会飞得太远,以至于最终形成一个大而全的系统。这会产生臃肿、紧密耦合的系统。

迭代式开发与增量式开发

在这次练习给我们的另一个重要收获是让我们意识到保持系统持续可用的唯一方法是采用迭代式的开发方法。你通过改造已有代码开发出整个购物 API。这种改造工作是在迭代优化解决方案的过程中不可避免的。

很多团队混淆了迭代和增量。这是两个完全不同的概念。

增量式方法是假设是你有完整清晰的需求,然后通过增量累加的方式来构建解方案。大体上来说,你一点点地构建各个部分,然后将所有的部分组装在一起。大功告成!解决方案已经准备好交付了!

相比之下,迭代式方法中,你并不很确定自己需要交付给客户的是什么。因为这个原因,你更加小心谨慎。你会小心翼翼地避免破坏能够运行的系统(也就是说系统处于稳态)。如果不得不扰动已有的平衡,你也会采取最小侵入性的方式。你专注于用尽可能小的工作量来快速完成每次得改动工作。你倾向于让系统尽快回到稳态。

这就是为什么迭代式方法在真正实现一个功能之前总是先提供一个假实现。你硬编码一系列的期望,以验证小的修改不会导致系统无法运行。然后进行必要的修改,用实际处理代码替换硬编码的值。

作为经验法则,在迭代方法中,你的目标是通过设计期望(微测试),对代码进行不断改进。每进行一次改进,你都要检验系统,以确保它处于工作状态。以这种方式不断前进,最终会达到满足所有期望的程度,并且此时代码已经被重构,没有任何存活的变异体了。

一旦达到了这种状态,你就可以相当自信地交付解决方案了。

由衷感谢 Kent Beck🔗 en.wikipedia.org、 Ron Jeffries🔗 en.wikipedia.org 和GeePaw Hill🔗 www.geepawhill.org 在我的软件工程学习道路的启发。

愿 ZOMBIES 方法在软件开发的征程上帮助到你。

(题图:MJ/ca463fc6-021b-4818-ba3d-9cd3c8736577)


via: https://opensource.com/article/21/2/simplicity

作者:Alex Bunardzic 选题:lkxed 译者:toknow-gh 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

LCTT 译者 :Xiangbin Ma
🌟🌟
翻译: 8.0 篇
|
贡献: 3254 天
2014-07-01
2023-05-29
https://linux.cn/lctt/toknow-gh
欢迎遵照 CC-BY-SA 协议规定转载,
如需转载,请在文章下留言 “转载:公众号名称”,
我们将为您添加白名单,授权“转载文章时可以修改”。


微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
Linus Torvalds:我是那些“清醒的共产主义者”之一 | Linux 中国【吐槽大会】《祈望》如何在 Linux 系统中使用 Ventoy 创建多重引导的 U 盘 | Linux 中国哈佛访校记Reminders:一个漂亮的开源 Linux 应用,可帮助你完成工作 | Linux 中国如何在 Rocky Linux 9 / AlmaLinux 9 上安装 KVM | Linux 中国ZOMBIES:在软件开发中定义边界和接口(三) | Linux 中国春雨潇潇使用 ChatGPT AI 从英文文本生成 Linux 命令 | Linux 中国终端基础:在 Linux 中删除文件和文件夹 | Linux 中国我和大海有个约——清明祭父有感(2023)简洁、酷炫!率先布局Z世代,这家头部券商推出颠覆性投资交易软件大家最喜欢的 Linux 终端字体 | Linux 中国TUXEDO Stellaris 16(Gen5)是目前所能找到的终极 Linux 笔记本电脑 | Linux 中国奥巴马说过不让中国人过上美国人的好日子吗?渡十娘|小说连载:螺蛳姐姐(五)敏捷组织 | 银行数字化转型实用工具箱“CBOT 1+4”系列(五)五个斯坦行游记(五)开源朗读者 | Linux 只是一个内核:这是什么意思? | Linux 中国Agustín Hernández:中美洲建筑背景下的未来主义巨构7 个超轻量级 Linux 发行版 | Linux 中国为什么黑客更喜欢使用 Kali Linux? | Linux 中国risiOS:一个易于使用的基于 Fedora 的 Linux 发行版 | Linux 中国10 个最佳 Linux 虚拟化软件 | Linux 中国2023 年最佳 Linux 视频编辑软件 | Linux 中国揭秘 GNU/Linux:为什么几乎没人敢这么称呼它?Zombies won't win研究了100个ChatGPT的真实案例,这或是我们一生遭遇的最大机会!(五)Transl Res:中科大叶山东团队揭示:糖尿病动脉粥样硬化发病机制中的关键损伤因子ZOMBIES:我的软件开发和测试简便指南(一) | Linux 中国人生若只如初见(五)下如何在 Linux 中合并 PDF 文件 | Linux 中国人生若只如初见(五)上Arch Linux 的最佳 GUI 包管理器 | Linux 中国测评适用于 Linux 中 Wayland 的最佳屏幕录制软件 | Linux 中国在 Linux 上用 Kdenlive 编辑视频 | Linux 中国
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。