测试已经成为限制开发人员效率提升瓶颈的原因。
译自 We Need a New Approach to Testing Microservices,作者 Nočnica Mellifera (她/她的)在七年开发工作之后进入开发者关系领域。她专门从事容器化工作负载、无服务器和公共云工程。Nočnica长期以来一直倡导开放标准,并就开源、Kubernetes和云原生技术进行演讲和研讨会......
微服务架构的妙处在于其分布式特性。没有任何一个人需要管理、监控或编写系统的每一个部分。当出现问题时,它应该被隔离在少数几个服务中,所以你不需要每次都去找同样的高级工程师。相反,只有来自那些服务各自团队的专家才需要了解这个问题。但是当涉及到测试发布时,情况变得奇怪地集中化了。
集成测试对微服务来说是一个高度关键的阶段,因为这时你常常会发现你的代码是否真正可用。尽管在集成测试之前可以进行单元测试和一些带模拟和存根的测试,但集成阶段是大多数真正测试发生的地方。问题是,这种测试要么无法进行,要么无法非常真实地进行,直到相当后期的过程。更糟的是,它是集中化的,通常由一个团队负责管理测试或暂存环境,并且有一个缓慢的反馈循环,其中集成过程中发现的问题会被记录下来,然后发送回开发该功能的开发团队进行修复。
我们需要像分散开发和生产操作的许多其他组件一样,以分散的方式测试。我们需要让开发人员尽早(“向左移”)进行更多测试,以便他们可以尽早发现集成问题——在他们的代码影响其他团队之前。
具有讽刺意味的是,测试的集中化导致了更多环境的出现。这种模式似乎发生是因为,由于测试是集中化和相对缓慢的,团队试图提前添加环境来了解代码是否能在暂存和测试环境中工作。
需要多少个环境才足够呢?此外,为什么这不是我们所有人都能达成一致的事情呢?当我刚开始作为开发人员时,我有一个质量保证(QA)环境和一个生产环境。暂存在中间,但它没有被使用并且不能非常准确地反映生产。后来,我发现我笔记本电脑上代码的初始运行是另一个环境,代码正在其中运行。所以我有开发、QA 和生产环境。这就够了!但是看看最近对DevOps工程师的非正式调查,询问他们拥有哪些环境: 超过三分之一使用开发、测试、暂存和生产环境。
现代DevOps和CI实践,当应用于微服务和现代托管架构时,它们使我们回到了更像瀑布一样的部署——笨拙的做法,通常依赖人为过程才能完成代码部署。导致这种反模式的一个因素是QA和运维必须管理的大量不同环境。
我们的场景开始于一个周一的工程团队视频通话。他们正在构建一个云原生应用程序,小团队(A、B 和 C)周一上午见面,定义他们将为其微服务添加的功能。每个团队管理1到3个微服务,他们非常了解自己的代码库以及如何快速添加新功能。A团队就他们将要工作的内容达成一致,并定下一个目标发布日期为下周一,即7天后。他们将无法做到,环境将是罪魁祸首。让我们来谈谈为什么。
尽管A团队像自己的后背一样熟悉他们的微服务代码,但他们无法单独运行服务代码而获得太大的好处。当他们编写代码时,这样做可能有所帮助,但它对B团队服务的依赖性足够大,以至于它不会告诉你太多信息。因此,A、B和C团队都使用一个名为Dev的共享环境来部署和测试他们的代码。所有这些都非常容易、非常方便,周一下午编写的代码可以在同一天部署到共享集群上。这个Dev集群的巨大优势在于它是最新版本的: 三个团队最新版本的服务都在上面。
然而,在这一天,某些事情没有正常工作,每次A团队的服务与B团队的服务交互时都会失败。没关系,A团队可以在Slack上联系并搞清楚。
Dev集群的伟大之处在于你可以部署任何你想要的东西,但是当B团队上周晚些时候进行试验时,他们将服务B留在了一个无法按设计处理请求的状态。没关系,他们进行了回滚,到周二上午每个人都准备好进行测试。
到周二下午,情况看起来不错,所以他们准备将其发布到QA环境。这是必要的一步,因为QA和运维工程师在此集群上维护了许多在Dev上不可用的依赖项。像第三方支付提供商等在QA环境中具有虚拟凭据,更“生产般”版本的数据存储也在其中。一旦A团队打包其更新并编写拉取请求(PR),它就可以进入下一个团队了。
QA团队查看主分支的合并以知道何时该将更改部署到QA集群并从那里开始测试。这个功能比预期晚了一天,但到周三上午他们准备开始。通常,QA团队不测试单个微服务,更喜欢获取所有更新并对系统进行端到端(E2E)测试。这是一个巨大的帮助,因为这意味着他们知道更新是否确实适用于完整系统。但它也最终会导致延迟。
事实证明,这些更新依赖于B团队上周的新功能,出于各种原因,它们还没有合并到主分支。现在他们真的看到了延迟。诊断这个问题需要一些时间,A团队直到周四上午才意识到问题是将QA与B团队的更改同步。他们要求B团队赶快将更改合并到主分支,但这是一个人为过程,需要时间,所以直到周五上午,所有内容才最终合并并准备返回QA。
此时,他们已经错过了最后期限,但情况正从糟糕变得更糟: QA团队的测试频率各不相同,但他们通常不完全按需工作。这意味着他们已经错过了本周的测试运行,必须等到周一。A团队可以从Selenium或Playwright获取一些自动化测试反馈(假设他们针对Staging运行自动化端到端测试)。但这些测试并不能覆盖所有情况,所以A团队必须决定是否值得等待QA的反馈,或者他们应该直接继续前进,修复自动化测试找到的问题,以准备进行更多手动测试。
请记住,他们现在正在第二周初了解服务A的功能是否存在真正的集成问题。QA很可能会发现真正的问题。一旦QA确实发现问题,他们必须记录问题并包含复制步骤。他们不是原始的功能开发人员,所以这个文档可能会也可能不会将这些开发人员引回问题的确切原因。
开发人员从缺陷队列中处理发现的问题,除非他们真的准备推进此功能,否则A团队不太可能立即解决此缺陷。此时,一周的时间表已经延长到两周或更长时间。
两周半过去了,他们准备发布。当然,这是一个重要功能,所以他们希望产品经理和其他人签署更改。值得注意的是,这没有包含在最初的一周估计中,但它仍然算数。
要么通过使用功能标志要么通过第三个预发布环境,QA通过的更改发布给内部利益相关方进行审查。虽然这没有包含在最初的时间表中,但当功能与预期不完全匹配时,它会影响时间表。QA或运维级别的任何人都无法解决这个问题,所以这个功能完全返回到A团队。更糟糕的是,由于B团队在过去的两周中更新了其服务,他们在Dev环境上的协商、等待QA环境同步等都会发生相同的延迟。
微服务及其相互依赖性会对流畅、高速度的开发和部署流程造成实际问题。上述时间线并不异常,如果没有人异步处理关键的优先级0(P0)问题,发布新功能的时间可以从几周延长到几个月。由于该过程涉及开发和QA多次就问题进行沟通,与理想情况相比,该过程的自动化程度较低,人工操作较多。这是九个月的瀑布流程吗?不是,但为了保持竞争力,我们需要寻求尽可能好的开发人员速度,而这并不是。
结果将是越来越多的提交与其他团队的工作打包在一起。这可以确保在QA上进行的测试尽可能多地涉及更新。这对高准确性测试很有好处,但对开发速度不利。
除了异步问题和缓慢流程的一般摩擦外,上述大部分内容都涉及直接的人与人之间的沟通来诊断和解决问题。QA团队必须记录错误和复制步骤,开发团队必须反复描述新的提交给QA等等。这种人与人之间的沟通极大地增加了摩擦和对同步工作的需求。想象一下,上述场景中的分布式团队在欧洲、北美和亚洲工作。相同的两周流程可能需要一个月。
这就是测试流程集中化如何导致缓慢的基于工单的问题沟通,以及相对高速的异步产品开发流程,因为多个团队试图同步测试而受阻。
在一个最近的Reddit主题帖中,用户u/ellensen描述了一个与上述场景一致的设置:
我们的DEV环境是一个没有自动部署流水线的沙盒环境,我们的应用程序使用与自动化环境相同的Terraform进行配置,只是由开发人员从他们的笔记本电脑手动应用。这就像一个沙盒环境,没有任何预期的稳定性,可以随心所欲地对应用程序做任何事情,其他开发人员甚至不应该期望应用程序正在运行或者像他们上次离开应用程序时那样。
这是一个自由与稳定性交易的基本平衡的示例: Dev环境允许你做任何你想做的事情并手动应用更新。另一方面,开发人员不能指望当他们返回此环境时事情会稳定。
Ellensen继续描述TEST和STAGE如何非常相似,开发人员通常采取略有不同的路径,以确保他们的代码在进入QA之前可以正常工作。但然后来了沮丧:
整个系统非常稳定且运行良好;因为一切都是由Terraform维护的,维护起来并不困难,[...] 但当你进行更复杂的重构,需要大量移动组件时,你可以在进入生产环境之前在开发、测试和暂存环境中练习部署。在三次测试部署之后,你可以非常确定一切都运行正常,我们极少甚至从未在生产环境中进行过不良部署。
虽然该流程不太可能向生产环境发布错误代码,但它确实缓慢,并且在发布过程后期发现的任何问题都可能需要一些异步工作进行修复。 此外,主要服务的重大更新必须传播到大量上游环境中。