软件质量稳定性之殇
黑天鹅事件告诉我们要走出经验主义,不要将自己知道的东西太当回事,我们不知道的事比我们知道的事更有意义。蝴蝶效应告诉我们要及时感知问题,止损和熔断,避免问题范围扩大甚至传染到其他相关领域。墨菲定律告诉我们,我们知道的但是忽略的地方终究会出问题。
一言以蔽之,要将软件研发中的质量搞好并非易事。导致软件质量问题难以把控的原因还有很多,本节会详细进行分析。
业务高速发展带来的变化
在很多年前就有人想将软件从业者变成制造工人,不断进行流水线工作。但这几乎没什么可能,因为软件从业者要解决的问题域太复杂。虽然业界有很多规范、标准、套装软件,但是仍然未解决问题的万分之一。
阿里巴巴的电商业务在最近几年呈指数级增长,业务的发展速度惊人。阿里巴巴内部有一句话说:双11是业务的狂欢、技术的盛宴。
到目前为止,阿里巴巴做了10年双11,双11交易额从2009年的5.9亿元增长到2018年的2135亿元,实现了355倍的增长,交易峰值也从2009年的400笔每秒,增长到2018的49.1万笔每秒,系统规模也有几十倍、上百倍的增长,如图6.4所示。
图6.4
随着业务的高速发展,技术挑战越来越大,有些挑战甚至是无法借鉴的,只能靠自我创新。阿里巴巴面对的双 11 技术挑战,可以说是世界性的,特别是如何在零点峰值到来时确保系统稳定。
问题域的复杂性
IBM大型机之父佛瑞德·布鲁克斯在《没有银弹:软件工程的本质性与附属性工作》论文中提到:软件开发是极其困难的,这些困难分为两类:本质性的和附属性的;附加性的困难会随着工具的改善逐渐淡化,本质性的困难是最难解决的,其要点是问题域的复杂性。
问题域,就是针对现实世界中某个特定问题的所有相关方面的抽象。现实世界中的某些特定问题本来就是极其复杂的,根据这些问题做的抽象,问题域自然不会简单。因为不同的人看问题的角度可能不一样,所以抽象出的结果可能大不相同。
系统的复杂性
随着业务的发展,人们对可用性的诉求越来越高,但是可用性的提高必然导致系统的复杂度攀升。为了提升系统的可用性,应用的部署就可能从单机部署演化成集群部署。而集群部署在初期可能采用同城多机房的容灾方案,慢慢又会演化成异地多机房的容灾方案。而随着方案越来越复杂,多个机房之间的负载均衡、容灾方案等挑战也会越来越大。这还只是考虑了线上生产环境中的机器情况,再加入测试环境、灰度环境、预发布环境等,就会更加复杂。
除了集群部署,为了提升可用性等问题,我们也会将单体应用拆分成分布式应用,进而演化成微服务,各个应用之间通过RPC、异步消息等方式进行通信,这就会引入更多的数据一致性等问题。
举个例子,有一个主要用于支付链路的规则决策的系统,该系统起初可能只有4万行代码,后来增加到 8 万行代码,现在又增加到 10万行代码。代码行增加了,该应用的功能也增加了,同时系统的调用逻辑及运算的复杂度必然增加,那么如何保持对外 API 的TPS不降低,RT不降低/p>
技术债问题
技术债务是由Ward Cunningham在1992年创造的一个比喻,被定义为我们有意或无意中做了错误的或不理想的技术决策所累积的债务。
Steve McConnell将技术债务分为如下两类。
◎ 无意的:由于经验的缺乏导致初级开发者编写了质量低劣的代码。
◎ 有意的:团队根据当前而非未来进行了设计选型,这种方式可能很快解决了当前的问题,但很拙劣。
随着技术团队人员的能力提升,无意的技术债务可能会越来越少。但是在很多时候,我们欠下的技术债务往往是有意的,随着业务的高速发展,还会带来很多变化。为了快速实现业务的功能及验证商业决策,开发人员大多会采用很多临时方案。毫不客气地说,这些临时方案其实就是技术债。
临时方案的可怕之处,不仅仅在于其不全面,更在于如果不对其及时处理,可能就永远“临时”下去了。随着团队成员的不断更替,慢慢地就没人记得这个临时方案了。一个说好只支撑两个月的临时代码,可能两年后还在线上机器里运行着。
随着系统中的临时方案越来越多,我们需要还的技术债也越来越多。欠债并不可怕,可怕的是没有偿还计划。其实,任何系统都无法避免技术债,因为业务在不断发展,总需要做些妥协,这都无可厚非,但是一定要注意如下几点。
◎ 通过人员培训、代码审查等方式杜绝无意的技术债。
◎ 要尽量避免有意的技术债。
◎ 如果一定要引入技术债,则一定不要引入不计后果的技术债。
◎ 要记录所有欠下的技术债,并且有偿还计划。
技术债务和金融债务非常相似。一个人贷了款就会产生债务,如果可以定期还款,则所欠的债务是可以接受的,不会产生进一步的问题;但是,如果不还款,就会以利息作为惩罚,利息还会随着不还款次数的增加而增加。如果这个人在很长一段时间内不能支付任何款项,那么应计利息会使他更难以偿还债务。在极端情况下,这个人就不得不宣布自己破产。技术债务也一样,如果越积越多,最终也会导致非常严重的后果。
人、流程、文档的博弈
总之,我们不得不承认的事实包括:
◎ 无论写多少文档,如何维护“活文档”(一个特别熟悉代码的人)都是一个大问题;
◎ 关键时刻要靠人传、帮、带,要靠传承。
采用不能掌控的工具和框架
技术人员大多有采用新工具、新语言、新开源产品的追求。当全栈、多语言风潮席卷各 区的时候,不罗列一堆名词真心不好意思跟人交流。这还涉及技术带头人的偏好问题。
在前面的章节中,我们鼓励开发者学习新技术、新语言等。但是不得不说,有很多线上故障都是由于开发者对所使用的新技术不了解导致的。所以,对于新技术、新语言,我们应该充满期待,但是在真正将其引入日常工作中的时候,一定要考虑整个团队对于这项技术的接受程度及掌握程度。
质量意识
经过分析,80%的线上问题并不那么难以解决,其本质是未遵循规定的动作。比如修改了代码且未充分验证,认为就修改了几行代码,咋看都不会出错。从内建质量的角度来看,我们一般有多条质量防线,一个问题被遗留到线上,往往有3个以上的措施都失守了。很多故障的发生,都是因为质量意识的薄弱导致的。无论是开发人员还是测试人员,都应该对线上环境保持敬畏之心。前面提到过墨菲定律、蝴蝶效应及黑天鹅事件等,都是希望提醒读者们,尤其是开发者,要对自己的每一行代码都保持敬畏之心。
有一篇关于如何规范飞行员作风的文章提到的如下经验颇有借鉴意义。
◎ 不忘初心,严格遵守SOP(标准操作程序)。
◎ 减少侥幸心理,增强风险意识。
◎ 狠抓作风养成。
◎ 严厉处罚无后果违章,既要结果,又要过程正确。
文章知识点与官方知识档案匹配,可进一步学习相关知识Java技能树首页概览92321 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!