交付高质量软件的心智模型

2020-10-27 02:42:54

下面是一些陈述/假设,可以帮助我解释这篇文章的想法和目标:

重要的是,软件的构建和交付要在合理的短时间内完成。

开发软件的方法和方式有很多种,没有一种方法对所有组织都是正确的。

这篇文章的目标是分享我在职业生涯中学到的一种方法或一种方法的组合,以更快、更高质量地交付软件产品。这里没有我发明的任何东西。它仅仅是公司和个人通过书籍和框架建议和测试的方法的总结,并在我工作过的几家公司中应用。

我不建议将此视为交付/质量策略。需要根据对现有方法、流程和行为的观察和分析,为每个组织量身定做交付/质量策略。然而,我确实喜欢将其视为构建软件交付和质量策略时参考的心理模型。

我在这篇文章中想要强调的另外一件事是关于“测试”与“质量”的常见误解,以及当事情出错时求助于端到端测试(这并不是一件错误的事情)。

请联系我进一步讨论和挑战这一模式。我很想听听你的反馈(在我的个人网站上可以找到几种联系方式)。

在软件交付方面遇到很多困难是很常见的,而造成这种困难的原因是多方面的,这在每个组织中都是不同的。然而,围绕质量问题通常有一个共同的主题。

质量很难下定义。这需要与团队和风险承担者进行大量沟通,以了解哪些是可接受的,哪些是不可以接受的。在开始任何改变之前,理想的做法是与人们交谈,了解他们对当前产品质量和系统行为的看法-不同的人会根据他们的角色和他们对质量的定义有不同的看法。

做一个“软件交付回顾”,使人们能够识别当前发布过程中的痛点,编码实践中的痛点,或者规划实践中的痛点,等等。从识别问题开始。

通常,质量斗争/问题通过首先解决测试来解决。这不是不正确的。但是,有必要记住,测试是帮助提高质量的单个组件。因此,团队还需要考虑其他组件。

我们想要高质量的快速交货,我们想从某个地方开始。没有足够的时间进行讨论、回顾和规划。每个人都希望行动迅速,这没有什么错。因此,团队通常从增加测试覆盖率入手,从单元测试开始,到E2E测试结束。这是一件很棒的事情,我强烈鼓励这样做。但在详细介绍此方法之前,我想先谈谈端到端测试。

我在软件开发/测试领域认识的90%的人说E2E测试不好。它们又长又脆,速度慢,易碎,易碎,而且要花很多钱。我的个人经验与这种描述一致,我认为这些测试通常会在一两年内被放弃,这取决于组织重新评估其质量流程(或整体开发-和交付-流程)和调整新的工作方式的速度,这些新的工作方式可能会消除这种痛苦,可能需要进行一些权衡。

从上一段可能可以理解,我建议避免编写E2E测试,因为它们在一定时间后无论如何都会被放弃。事实上,我不是。我建议回归基础,采取务实的方法,最大限度地减少E2E测试的数量,以降低成本,并以不同的方式解决质量问题。

E2e测试通常模拟真实的用户场景。由于关注用户是每个组织的目标,这使得E2E测试成为一个超级好主意。

E2e测试有助于在应用程序的所有部分连接在一起的情况下运行应用程序,这将识别组件测试没有发现的bug

除此之外,我们喜欢过一种没有压力的生活(或者降低我们生活中的压力水平)。增加E2E测试将在投产前提供信心,这将给利益相关者带来一些安心。

我相信,把最终用户放在第一位,自动化回归套件,(尽可能)防止bug滑向生产,并致力于过一种没有压力的生活,这些都是正确和伟大的选择。

决定通过添加E2E测试来解决这些问题很容易,因为团队可以识别用户场景,然后通过浏览器模拟将其自动化。通常,团队在修复/改进系统质量方面压力很大,采用E2E看起来是最快的方式。但与任何决定一样,还需要考虑其他因素。

简单地说,E2E测试很脆弱,编写成本很高,运行起来很耗时,而且很难维护。它们很脆弱,对应用程序的微小更改都会破坏这些测试。

使用这种方法来解决质量问题本身很快就会成为一个问题,形成一个冰激凌蛋筒:

在这种方法中,E2E测试是第二道防线,它们涵盖了可能被忽略的依赖项。所以拥有它们是好的,但它们不能解决主要问题。E2E到位并不意味着质量问题得到解决。

即使有相当数量的单元测试(可能还有一些集成测试)、长时间运行的E2E测试套件和非常多的手动测试,在生产中仍然可能会遇到回归错误-下一节(在代码→自动化→E2E下)将详细介绍这一点。我们能做什么?

这些问题可能暗示现在是时候考虑有关交付高质量软件的总体方法了。

请注意,这里我提到了质量和不是测试,因为这是两件不同的事情。测试只是会带来更好质量的活动之一(可以争论它是否是主要活动-我们不会讨论这一问题)。

在本节中,我们将间接回答前面的一些问题(将最终用户放在第一位,阻止bug进入生产,等等)。

测试不应该在发布之前进行。我们应该在发布之前、发布期间和发布之后不断地进行测试。我喜欢丹·阿什比(Dan Ashby)关于持续测试的以下可视化描述:

但如何切实做到这一点,有很多工作需要完成,而且所有团队的时间和资源都是有限的。这并不容易,需要纪律和适应能力:

询问/质询所有功能请求(我们为什么需要它?这是要实施的正确做法吗?)。

讨论用户情景的测试(是否需要UI级别的测试,集成测试或单元测试是否足够?)。

大多数情况下,产品已经存在,我们不能放弃现有的手动测试(特别是如果在另一个级别没有足够的覆盖率)。当团队在早期讨论对其他领域的影响时,这将给出是否需要任何进一步的手动回归测试的提示。这主要是风险评估。

讨论分支方法是否有助于细粒度用户情景的开发和发布

分支似乎是我们曾经建立并忘记的东西,但实际上,时不时地对其进行评估是有好处的。随着开发过程的发展,可能需要相应地调整分支策略。例如,如果我们连续发布,或者有两个主分支,那么拥有一个发布分支就没有多大意义。

在开始开发之前,测试人员和开发人员之间的配对可能非常有用(测试优先方法-每个用户故事花费的时间不应超过15分钟)。

在吉拉机票上写下一个班轮的变化(如果可能的话,也可以作为测试)。

讨论如何部署用户情景(可以先部署后端吗?可以单独测试吗?是否可以在不影响系统中任何其他内容的情况下将其发布到生产中?)。

重新访问需要自动化的内容和级别-就谁在实施哪些内容达成高级别协议是有益的。

确定正在开发的项目在合并到主分支之前是否需要由其他人在本地进行测试。

代码审查非常重要--为审查留出足够的时间有助于在过程的早期阶段识别问题--如果审查没有配对,那么在本地运行最新的代码并对其进行一些探索性测试可能是有益的。

不用说,创建单元测试,并通过临时更改输入和/或实际代码来测试它们的失败

本地测试,无论是由测试人员还是由其他工程师进行测试。这比在测试环境中进行测试要好得多(这将在流程早期显示失败,在那里编写的解决方案仍然新鲜)-基于早期完成的配对,很可能不需要另一个工程师或测试人员。

手动测试本地实施的内容(探索性视觉测试)-是的,打开该应用程序并确保其行为符合预期。

涵盖主要业务案例(例如,如果用户情景建议实现允许设置值的字段,则E2E将设置正确的值,保存然后验证保存的值-我们不会在此级别测试错误的值,或者按钮是否启用或禁用)。

其他未覆盖的情况怎么办(例如,应禁用按钮)?如果可能,这些变体应该在不同的级别上涵盖。如果这是不可能的,那么在开发期间通过手动探索性测试来覆盖它就足够了-如果它后来在生产中被破坏了怎么办?如果这是一个主要场景,那么它将在测试中涵盖,不会投入生产。如果这是第二种情况,那么在生产中出现故障也没问题,只要我们有办法快速修复它并使其正常工作(发布方法在这里很重要)-但这可能不是业务的选择。在这种情况下,最好看看可能每天执行的可视测试方法,比如快照测试,其中会比较当前和以前的UI。请注意,即使有大量的测试,也不可能有无bug的软件。

应该以尽可能快的方式进行验证。例如,如果我们可以更快地验证网络请求是用正确的值提交的,我们就不应该打开另一个页面来验证设置是否被正确保存(另一个页面应该在它自己的测试中进行练习,在该测试中我们验证保存的值是否被正确检索)。

设置数据和访问正在测试的功能应该以尽可能快的方式进行。例如,如果我们需要单击多个按钮才能到达我们试图更新的字段,如果这样更快的话,最好直接导航到该页面并设置字段(单击按钮到达字段应该在不同的场景中执行)-如果我们需要创建用户以使字段可见以进行测试,则越好地以尽可能快的方式创建用户,无论是通过API、插入到数据库中,还是在可能的情况下模拟该记录。

可以包括合同测试,这将有助于使其他集成和E2E测试更容易、更有效。

单元测试有助于在开发周期的早期发现问题,这些问题可能是规范中的错误或缺陷

单元测试在重构代码片段、升级库或扩展功能时(例如在回归测试中)提供了信心,并允许开发人员确保模块仍然正常工作。

单元测试使集成测试变得容易得多,因为我们正在测试程序的各个部分,然后测试这些部分的总和。

单元测试允许覆盖输入、输出和错误条件,这将有助于覆盖更多边缘情况。

密切关注合并,以防多人在同一区域、冲突测试区附近工作。

构建类似于分支,是值得不断评估和寻找增强它的方法的好东西。建造速度慢吗?在构建过程中有没有我们可以去掉的步骤?

将这两个组件分开是非常重要的。这是在用户故事的基础上讨论的内容,团队定义是否需要功能标志。

发布和部署是这一提议模型的基石。出于以下原因,建议使用持续部署战略:

把风险降到最低。随着我们向单个版本添加更多代码(功能/修复),风险将会增加。

更快的生产时间,这意味着更快的反馈循环,无论是来自客户的反馈(如果是发布的),还是来自“在生产中测试”的反馈(如果它是一个隐藏的功能。

这通常会带来更快的交货周期和更好的质量。有些人会担心,即使在发布之前执行了大量的手动测试回归,错误仍然会被引入到生产中,那么如何在多个部署中避免这种情况呢?

主要是这些都应该通过开发的规划来覆盖,团队在那里评估影响的区域。如果要部署/发布一大段代码,这是一个提示,它需要进一步整理并拆分成多个可部署的故事(在流程的早期投资总是值得的)。

即使有影响,受单个更改影响的区域也比受多个更改影响的区域更容易后退。

随之而来的是对失败的反应文化。问题会出现,能否迅速解决这些问题是成功的关键。因此,应该有一个良好的监控和“生产测试”实践,以便快速响应。

我知道,更频繁的释放会降低风险,这似乎有点违反直觉。然而,现实中发生的情况是,这将显示出过程和制度中的薄弱环节,并有助于加强它们。

总而言之,采用世界上一些最成功的公司选择的这一过程将有助于:

降低部署风险-进行较小的更改意味着出现问题的可能性较小,并且更容易在出现问题时进行修复

更快的反馈循环-如果该功能可见,最终用户将能够更快地对其进行反映。或者,使用一些有用的数据在生产中进行测试将会有很大的好处。

下图直观地显示了我们如何分散风险、提高速度以及更快地响应问题:

生产中的反馈是使我们能够快速响应事件的最强大的工具之一。

有效的监控有助于快速发现问题(例如,如果发布后性能下降,我们可以快速响应)。

监视信息有助于确定未来版本的探索性测试的优先顺序,在这些版本中,可以将重点放在高使用率的组件上。

日志文件将提供低级详细信息,以诊断生产问题的根本原因。

产品中的探索性测试很不错,可以帮助开发人员体验用户对该功能的看法。

生产中的自动化E2E烟雾测试也是一个很好的想法,作为第三道防线

此流程需要灵活和可调整,以满足业务和团队需求。质量是一个非常宽泛和主观的术语。了解这对我们的产品利益相关者意味着什么,这一点很重要。然而,交付高质量的软件产品通常可以通过文化、体系结构、测试和过程的组合来完成。

采用分布式体系结构,并使用微服务将独立(可以说)实现对每个服务的频繁更新。

在这种方法中,高质量的自动化测试是必要的,以便在发布时充满信心。

我们是否满足了前面讨论的事项-将最终用户放在首位、使回归套件自动化、(尽可能)防止bug滑向生产,并以无压力的生活为目标?

我们把最终用户放在第一位,我们让最终用户能够非常快速地访问新实施的项目,而且损坏的风险很低(我们还通过快速反馈考虑了用户的意见)。

我们已经自动化了手动回归套件-这可能需要很长时间,我们可能没有,这会导致其他问题。我们提供了一种自动测试受影响内容和重要内容的方法。我们还建议快速反馈,快速修复循环。这样不是更好吗?

防止bug滑向生产(尽可能多)-我们建议采用一种积极主动的方法来积极地细化、计划、创建测试和小代码块,并在流程的早期进行配对,以防止问题滑向生产。

目标是过一种没有压力的生活-我不认为这是存在的,但随着时间的推移,我们通过部署经过单独测试的低风险项目来管理我们的压力