我在产品中测试(2019年)

2020-07-19 23:19:11

我并不总是测试我的代码,“世界上最有趣的人沉思着,这是有史以来最坚固的技术迷因之一,但当我测试时,我会在生产中测试。

自从我第一次看到这个表情包,我就一直在嘲笑它。。。2013年?这不仅仅是有趣。太搞笑了!

从那时起,“在产品中测试”已经成为我们与生产服务互动的所有不负责任的方式的缩写,或者在我们匆忙发货时偷工减料,为此我指责最有趣的人和他不可抗拒的迷因。

因为,坦率地说,我们所有人都在生产中测试。(至少,优秀的工程师是这样做的。)。这本身并不是坏事,也不是疏忽的表现--对于工程师来说,每天与生产交互,观察他们编写的代码与基础设施和用户以他们永远无法预测的方式交互的方式,实际上是一种不合格的好处。

在生产中进行测试是一种超级大国。是我们不能承认我们正在做这件事,然后投资于工具和培训来安全地做这件事,这是在扼杀我们。

测试的核心是通过检查已知故障、过去的故障和可预测的故障(可以说是您的已知未知)来减少不确定性。如果我在特定环境中运行一段确定性代码,我预计结果会以可重复的方式成功或失败,这让我对该环境下的代码充满信心。“Cool。

当我们说生产时,“我们通常指的是所有这些东西的星座,甚至更多。尽管我们尽了最大努力将EC2实例上的eth0卡上的固件版本等烦人的低级别细节抽象出来,但我在这里要让您失望的是:在不可预测的情况下,您仍然必须关心这些事情。

如果测试是关于不确定性的,那么您可以“在部署到生产环境的任何时候”进行测试。毕竟,每个部署都是工件、环境、基础设施和一天中的时间的独特且不可复制的组合。当你测试完的时候,它已经改变了

部署之后,您将不再测试代码,而是测试系统-由用户、代码、环境、基础设施和时间点组成的复杂系统。这些系统具有不可预测的交互,缺乏任何合理的排序,并且会发展出新的属性,这些属性会永久地、永远地违背您进行确定性测试的能力。

“我不总是测试,但当我测试时,我在生产中测试”这句话似乎暗示您只能做其中之一:在生产之前测试或在生产中测试。但这是错误的二分法。所有负责的团队都会执行这两种测试。

然而,我们只承认第一种类型的测试,即负责任的“类型”。没有人承认第二点,更不用说谈论我们如何能做得更好、更安全。没有人会在他们的测试中投资生产“工具”。这就是我们做得如此糟糕的原因之一。

对于我们大多数人来说,世界上最稀缺的资源是工程周期。每当我们选择利用时间做某事时,我们都会含蓄地选择不做数以百计的其他事情。选择把宝贵的时间花在什么上是任何团队都能做的最困难的事情之一。它可以成就一家大公司,也可以毁掉一家大公司。

作为一个行业,我们在生产系统的工具上系统性投资不足。我们谈论测试的方式和我们实际使用软件的方式完全集中在防止问题进入生产阶段。承认无论我们做什么,都会有一些虫子被刺激,这已经是一个无法言说的现实。正因为如此,我们发现自己缺乏在代码开发的最重要的黄色化阶段理解、观察和严格测试代码的方法。

让我给你讲个故事。2019年5月,我们决定为整个蜂巢生产基础设施升级Ubuntu。Ubuntu14.04AMI即将失去支持,自从我在2015年第一次建立我们的基础设施以来,它还没有系统地推出过。我们做了所有负责任的事情:我们测试了它,我们写了一个脚本,我们首先把它推广到临时服务器和狗粮服务器。然后我们决定推出它来刺激。事情并没有按计划进行。(他们曾经这样做过吗?)。

引导数据库仍在运行时,cron作业按小时运行时出现问题。(我们广泛使用自动伸缩组,数据存储节点相互引导。)。结果发现,我们只在一小时的60分钟中有50分钟测试了自举。自然,我们看到的大多数问题都与我们的存储节点有关,因为它们当然是。

数据在rsync期间过期时出现问题。Rsync在未看到段文件的元数据时死机,反之亦然。在插装、正常重新启动和命名空间方面存在问题。像往常一样。但它们都是负责任地在生产中进行测试的很好的例子

我们在一个人造环境中做了适量的测试。我们在非生产环境中尽了最大努力。我们建立了安全措施。践行可观测性驱动发展。我们添加了工具,这样我们就可以跟踪进度并发现故障。我们把它铺开,同时用我们的肉眼仔细观察它,看有没有任何不熟悉的行为或可怕的问题。

在投入生产之前,我们能不能把所有的错误都解决掉呢?不是的。你永远不能保证你已经解决了所有的错误。我们当然可以花更多的时间试图增加我们的信心,即我们已经解决了所有可能的错误,但你很快就达到了回报快速递减的地步。

我们是个初创公司。初创公司往往不会因为行动太快而失败。他们往往会失败,因为他们痴迷于实际上不能提供商业价值的琐事。重要的是,我们要达到合理的信任级别,处理错误,并拥有多个级别的故障保护(即备份)。

我们每天都在进行风险管理的实验,往往是在不知不觉中进行的。每一次你决定合并为主要的或部署为生产的时候,你都在承担风险。每次您决定不合并或部署时,您都在承担风险。如果你过于认真地考虑你正在承担的所有风险,它实际上可能会让你陷入瘫痪。

不部署可能比部署风险小,但事实并非如此。这只是一种不同的风险。您冒着无法运送用户需要或想要的东西的风险;您冒着部署文化迟缓的风险;您可能会输给您的竞争对手。在有限的爆炸半径下,经常和小块地练习危险的东西,比完全避免危险的东西要好。

组织的风险偏好会有所不同。即使在一个组织内部,也可能存在广泛的风险容忍度。容忍度往往是最低的,而偏执狂往往是最高的,你越接近在磁盘上放置比特,特别是用户数据或计费数据。对于开发人员工具端或离线或无状态服务,容忍度往往更高,在这些服务中,错误不太容易被用户看到或永久存在。许多工程师,如果你问他们,会宣称他们绝对拒绝一切风险。他们满怀激情地认为,任何错误都是多此一举。然而,这些工程师不知何故每天早上都会设法离开家,有时甚至会开车。(太恐怖了!)。风险无处不在,我们要做的每一件事。

不采取行动的风险不那么明显,但同样致命。当它们被摊销更长的时间或被不同的团队感觉到时,它们只是更难被内部化。好的工程纪律包括强迫自己每天承担很小的风险,并保持良好的实践。

事实是,分布式系统处于局部退化的持续状态。失败是唯一不变的。现在您的系统上正在以您不知道也可能永远不知道的一百种方式发生故障。纠结于个别错误,充其量只会把你逼到最近的威士忌酒瓶的底部,让你彻夜难眠。只有通过服务级别目标(SLO)和服务级别指标(SLI)接受错误预算,批判性地思考用户可以容忍多少故障,并连接反馈循环以使软件工程师能够从头到尾拥有他们的系统,才能重新获得内心的平静(和良好的睡眠)

一个系统的弹性不是由它是否没有错误来定义的,而是由它在许多错误中生存的能力来定义的。我们建立对人类和用户更友好的系统,不是通过降低我们对错误的容忍度,而是通过提高容错度。失败并不可怕。失败就是被拥抱,被实践,并成为你的好朋友。

这意味着我们需要帮助彼此克服对生产系统的恐惧和偏执。你每天都应该忙得不可开交。Prod是您的用户居住的地方。Prod是用户在您的基础架构上与您的代码进行交互的地方。

因为我们系统性地在生产相关工具上投资不足,我们选择直接禁止人们生产,而不是建造护栏,默认情况下,护栏帮助他们做正确的事情,让他们很难做错误的事情。我们已经将部署工具分配给实习生,而不是我们最高级的工程师。我们已经建造了一座玻璃城堡,在那里我们应该有一个更好的操场。

我们怎么才能把自己从这个烂摊子里弄出来呢?这个答案有三个方面:技术、文化和管理。

这是一款仪表盘游戏。在开发和传播有关可观察性和仪表性的合理约定方面,我们落后于我们作为一个行业应该达到的水平,因为我们一直在构建以适应愚蠢数据格式的限制太长时间了。我们必须考虑传播请求的完整上下文并定期发出请求,而不是将检测视为字符串和度量的最后努力。除非工程师能回答这样的问题,否则任何拉取请求都不应该被接受,我如何知道这个请求是否会中断?

工程师应该随叫随到,获取他们自己的代码。在部署的同时,我们应该条件反射地通过我们仪器的镜头来看待世界。它的工作方式和我们预期的一样吗?有没有什么看起来很奇怪的事?虽然模糊和不精确,但这是你抓住那些危险的未知未知,那些你从未预料到的问题的唯一途径。

这种对错误采取不健康的零容忍方式最常来自于控制狂的管理压力。管理者需要学会使用错误预算、SLO和SLI的语言,以结果为导向,而不是以灾难性和不可预测的方式潜入低水平的细节。管理层的工作是定下基调(并坚守底线),即错误和失败是我们的朋友和谦卑的老师,而不是要害怕和避免的东西。冷静点。冷静点。表扬你想看到更多的行为。

在高水平上分配资源也是管理层的工作。管理者需要认识到,80%的错误是用20%的努力就能捕捉到的,在这之后,你会得到急剧递减的回报。现代软件系统需要在生产前强化方面的投资较少,在生产后恢复能力方面需要更多投资

在将代码抛出墙外、等待分页、在代码发布时警惕地监视代码、监视工具和主动调整新功能之间有很多时间。根据安全需求、产品需求,甚至团队之间的社会文化差异,都有很大的变化空间。然而,有一点是不变的:现代软件工程师的工作只有在他们看到用户在生产中使用他们的代码之后才能完成。

我们现在知道,构建高质量系统的唯一方法是投资于软件所有权,让编写服务的工程师一直负责到生产。我们还知道,如果我们大大降低大多数团队遇到的中断和寻呼事件的数量,我们才能期望人们长期待命。弹性与所有权齐头并进,所有权与生活质量齐头并进。三者在良性循环中相辅相成。你不能孤立地工作在一个项目上:在生产中进行实验和测试的健康文化将这三个因素结合在一起。

从已知的未知中删除一些循环,并将它们分配给未知的未知-真正困难的问题-是闭合循环并建立真正成熟的系统的唯一途径,这些系统为用户提供高质量的服务,并为他们的人力资源投标提供高质量的生活。

是的,你应该在生产前和生产过程中进行测试。但如果我必须选择-谢天谢地我没有-我会选择在生产中观看我的代码的能力,而不是世界上所有的前期测试。只有一个代表现实。只有一个能给你权力和灵活性来回答任何问题。这就是为什么我会在推特上测试