...

软件质量是什么?

2021-09-09

软件质量是什么?

业界通常将软件质量定义为如下两部分:

Functional Quality - How well software complies with or conforms to customer specifications.

Structural Quality - How software meets non-functional requirements that support the delivery of the functional requirements, such as robustness or maintainability.

质量是个很抽象的相对概念,如果打个比喻的话,会觉得质量和安全感有很多相似之处。安全感是什么?看不见摸不着,是不怕走夜路?不怕下水?抑或可以自在独处?

每个人对安全感的要求是不一样的,同一个人在不同的年龄段对安全感的要求也不一样。襁褓中的婴儿大部分都很怕和母亲分离,因为他们和母亲从生命开始的那一刻起就有了切不断的联系,他们怕离开母亲独自面对子宫以外的环境。有些人可能因为小时候有溺水的经历,即便成年之后,也无法涉水,对河流,大海有难以言状的恐惧。

同样的,在不同行业,有不同的质量标准。广义上讲,我们有食品质量,有工程质量,有软件质量等等。狭义到我们的软件开发,即使同一产品,不同的用户对产品质量的高低感受肯定也是有个体差异的。

另外质量像安全一样是个相对的概念,一般情况下我们会认为家里相对马路上来说是更安全的。但这是一般大概率的情况下,但当地震发生的时候,空旷的马路上也许就比家里安全多了。质量也一样,软件质量的优劣,是需要满足特定行业特定用户群体的产品诉求,符合某一年龄段或者特定性别用户的使用习惯,兼容大部分目标用户特定设备需求等等。

软件质量是一个抽象的存在

软件质量在线的时候我们是比较难察觉它的存在的,我们不知道它就存在于我们的每一次需求讨论中、每一念的设计斟酌里、每一回车的代码提交时。但是一旦有客户抱怨产品不好用,或者发现产品缺陷时,质量这个隐形的存在似乎就变得特别醒目。貌似跟我们的健康一样,我们健健康康的时候,很少觉察到健康的重要性,快乐地熬着夜撸着串。但是一旦我们生病了,这要忌口,那要注意,我们惊觉原来健康和我们的一餐一眠,一时一刻的情绪都息息相关。

软件质量是各个质量属性的综合

通常情况下,人们习惯说好的软件质量就是实现了客户对软件的所有需求。但是什么是需求呢?在敏捷开发环境下,我们用用户故事来管理,沟通产品需求。而用户故事我们通常会归类为功能需求和非功能需求。

举个例子,小区门禁系统通过人脸识别实现自动开门,这是个很明确的功能需求。满足了功能需求我们就能说这个软件的质量很好了吗?某天某位业主画了个浓妆,或者剪了个刘海,该系统无法识别了,功能无法满足了。你会发现,通常功能性需求和非功能性需求是交织在一起的,很多非功能性需求是为了辅助功能性需求的更好实现。软件质量一定是需要去界定质量特性,及满足这些特性应该具备哪些质量属性。

再举个例子,我们可以拿生活中送礼物这事儿来类比。比如情人节到了,我们或多或少会期望收到一份来自另一半的礼物。而且还期待对方能无需提示,主动自愿,悄咪咪地准备一个自己心仪的礼物。把‘收到礼物’ 看作‘What’,那‘无需提示,主动自愿,悄咪咪地准备’,就是‘How’。如果跟你说:钱都在你那里,你想买什么自己买就是了。毫无仪式感和主动性,这个礼物会让人开心吗?

质量模型

作为一个妈妈(被迫营业的非专业的育儿家),我知道孩子的安全感是可以被定义为很多维度的:满足感,可控感,信任感等等。而且这些不同的安全感有其特定的建立阶段,例如一岁之前,如果孩子能得到父母很好的照顾,持续的慈爱,婴儿的满足感就能被适当建立。我相信育儿专家们对孩子的安全感一定有更专业的系统定义、建立及评估方法。质量也一样,即使很抽象,具有行业差异,但是 IT 从业者从来没放弃过对其进行定义和评估,因此产生了各种不同的质量评估模型

这些模型都在试图将软件质量这个笼统而抽象的概念,细化成不同粒度的质量要素和质量属性。

作为项目上的 QA,我们需要先根据产品特点和客户需求梳理出目标产品的质量属性,根据属性去定义质量指标。再根据质量指标来指导开发流程,产品架构,测试策略,测试活动,风险管理等等。

软件质量的形成

以上讨论了软件质量是什么?那软件质量是如何形成的呢?要回答这个问题,需要先来看看什么是软件交付以及软件交付流程。

软件交付

在敏捷背景下,我们会认为软件交付就是快速地把客户的想法变成为高质量的软件交付到用户手中以获得商业价值。

软件交付是一个流程,从最开始 PO 的一个想法抑或一个业务痛点开始到最后一个成型的软件产品,中间会经历很多的活动。大概包括但不仅限于以下活动:

根据上面的讨论我们可以看到软件交付实质上是一个复杂的团体工程活动:

  • 包含多个交付活动,活动之间存在极强的关联性,上游不合格的工件很有可能就成了下游工序的阻碍。也有可能某个工件流经了好几个环节之后才得以发现有缺陷,以至于返工。

  • 涉及多个角色,角色之间需要沟通,而角色之间又会由于成长环境、教育背景、工作经历、思考习惯等的差异导致认知上的差异。

对应软件开发生命周期,我们可以看到如下的软件质量形成过程。质量在开发的各个环节一步一步建立起来,同样每个环节都是有可能直接或间接地贡献缺陷。根据业务痛点或诉求,精准的产品定位,正确的需求分析,完备无误的需求实现,全面细致的需求测试等等活动才能构建出一个高质量的产品特性。

在我们的交付中,总是免不了由于人的认知偏差导致的主观或客观的失误,例如具备业务可行性但不具备技术可行性的需求,半年前设计的不具备可扩展性的架构导致的性能问题,由于单元测试缺失或不足导致在新特性开发过程中造成的对原有特性的破坏。按照来源分类, 缺陷通常会有如下来源:

  • 需求问题导致的缺陷

  • 架构问题导致的缺陷

  • 设计问题导致的缺陷

  • 编码问题导致的缺陷

  • 测试问题导致的缺陷

  • 发布问题导致的缺陷

  • 集成问题导致的缺陷

不管何种开发模式,我们都认同一点,软件交付的任何一个环节都是有可能引入产品缺陷的。敏捷更强调在各个环节通过不同的活动和实践去主动规避缺陷的发生。而且这些活动和实践,需要频繁地,持续地践行,做到持续反馈;及时调整交付方式,优先级,精准定位产品价值和市场需求。

软件质量的多面性

软件质量是个很大的概念,它有很多张面孔,可以涉及软件生态的方方面面。

  • 可以是软件的使用质量(quality in use),即最终用户可感知的软件质量。

  • 可以是软件的内部质量(internal quality),产品的架构的合理性、可伸缩性,内部代码简洁度、规范性、可读性、可测性等。

  • 可以是软件的外部质量(external quality),即软件的各种行为,使用软件能做什么。

  • 可以是流程质量(process quality),能力成熟度模型,AMA ( Agile Maturity Assessment)、更早的 CMMI (Capability Maturity Mode) 等等。

  • 还可以是交付质量(delivery quality), 例如我们的 agile trade off,4-Key-Metrixs 。

Agile Trade-Off 图片来自网络

不同类型质量之间的关系

对软件质量的类型有所了解之后,你可能会问:不同的软件质量类型之间的关系是怎样的?

流程质量,即一个团队软件交付流程的优劣,这里的优劣是相对的,非绝对的,但优劣的本质在于:

  • 是否能让需求在交付过程中保真顺畅地流转?

  • 交付的各种产物是否都有对应的业务价值?

  • 是否每种形态的中间物(故事卡,产品架构,产品代码,测试代码,测试覆概率等)都有相应的检测和反馈机制?

一般项目在立项的时候就会去定义 Way of Working, 软件工件在流转过程中的 Definition of Done。这些都是从流程上去规范软件开发,保证团队以正确的方式做正确的事,避免偏离航线。

内部质量,即产品架构的合理性,可扩展性,代码的规范性,可读性,简洁度,组件重用等等,这些质量属性往往对客户是不见的。内部质量除了和开发人员技术能力有关外,直接受流程质量的影响。例如重构,TDD,引入编码规范和 lint 工具,code review 等等。内部质量通常与以下问题有关:

  • 能在现有产品上直接快速演进新特性吗?

  • 现有产品能有效支持短期内快速增长的用户量吗?

  • 业务逻辑和技术框架足够解偶以满足定期的更新维护吗?

外部质量,用户通过软件可以完成特定的业务任务,即当执行程序,或使用软件的时候,软件的具体行为。通常外部质量即是满足产品预先定义的业务需求,和内部质量相比,外部质量的好坏会直接影响客户对软件的使用的。

使用质量,是比外部质量更大范畴的关于软件可用性,易用性,易学性及用户体验为中心的质量维度。业界对使用质量的评估,有专门的模型,例如 QUIM model

综上所述,流程质量影响内部质量,内部质量影响外部质量,外部质量影响产品的使用质量。例如:团队流程不顺,会导致沟通不畅,会影响需求在团队里流转时的保真性,导致需求的错误实现或是遗漏。反过来,采用什么样的流程取决于团队对内部质量的要求,内部质量要求又取决于外部质量甚至使用质量指标。例如:使用质量有安全性要求,因此团队需要在故事卡准备,接口设计,开卡,结卡,编码,测试各个环节将此质量指标考虑进去。

测试和软件质量

以上我们讨论了软件质量是什么,软件质量的形成以及软件质量的类型。接下来我们再来看看,我们的测试活动和软件质量又有何种关系。

流程质量

流程质量基本没有常规意义上定义的测试活动,主要是通过各种实践活动来保证各个角色对于产品需求的理解是一致的,所有人 On the same page,做了正确的事。我们对于开卡、结卡, 迭代计划, 迭代演示,结对,代码评审的好处是毋庸置疑的。更有 CMMI (Capability Maturity Model Integration), AMA(Agile Maturity Assessement) 等等,都是对流程成熟度进行评估的模型。

那作为 QA,需要做到的就是帮助团队识别现有流程的痛点和风险,提出流程改进建议,并推行更好的流程实践在团队中落地。如此,QA 便能从流程质量上帮助团队实现质量内建,以避免流程缺陷导致的产品缺陷甚至是项目风险。

内部质量

2019 年的 5 月份的时候,Martin Fowler 发布了一篇名为 ‘Is High Quality Software Worth the Cost?’的文章,里面对内部质量做了很好的解释。也是这篇文章激发了我对于质量的总结和探索,才有了今天的这篇文章。其中如下这个图将内部质量对软件交付的影响进行了很好的可视化。

内部质量高的产品是更容易进行长期的产品演进迭代的,而且会以相对更低的成本进行产品的升级迭代。牺牲产品内部质量,确实在短期内可以获得很高的交付速率,但对于后期新需求的开发是不利的,甚至为了某一新特性的实现必须重新架构产品,调整前期已经实现的功能特性。但同时在短期内,团队需要花费更多的精力来提升内部质量。具体的内容,大家可以查看原文。

那我们如何来提升和保证产品的内部质量呢?

质量内建,测试左移

  • Test Driven Development

  • Acceptance Test Driven Development

  • Code Coverage

  • Code Review

  • Pair Programming

快速反馈

  • Test Pyramid

  • CI/CD DevOps

质量人人负责

  • Kick-Off

  • Elaboration

  • Shoulder-Check

  • Sign-Off

  • Bug Bash

以上保证内部质量的活动中,大部分都是工程实践,即流程质量。

这也是为什么敏捷倡导全员负责,质量在形成过程中,测试人员能起到的作用更多是一个质量大使的角色,而真正贡献质量的是交付中的各个角色。测试活动也不仅限于常规意义上的测试,而是一个更大范围的校准,对齐,验证和反馈。这就要求 QA 从质量的角度,和交付中的各个角色进行合作沟通,并在合适的时候对他人的质量意识进行赋能。一支人人有质量意识,开发人员都是 Test-Infected-Developer 的团队,从某种意义上说,是不需要特定的 QA 角色的,人人可以戴上质量这顶帽子,践行质量保证的活动。

外部质量

产品的外部质量怎么来保证呢?前面已经提到了像特性测试,验收测试,探索性测试都是对外部质量很好的保证。包括我们的很多自动化测试类型也是对外部质量的进行自动化反馈机制,例如 E2E 自动化测试, UI 的视觉回归测试,API 接口测试等。

除了这些常见的测试活动,我个人比较推荐的一个测试思想是的基于风险的测试( Risk based testing)。作为项目的测试人员或者 QA,在项目上我们的首要职责肯定是帮助团队规避由产品缺陷导致的质量风险。风险是一个可能会发生的问题,发生的可能性越大,影响越大,那么该风险的严重程度就越大。以潜在的质量风险来指导测试活动的开展,能以最少的资源,规避最大可能的风险。

使用质量

当产品发布到真实环境后就正式地进入到了使用阶段。终端用户在他们的设备上,他们的网络环境下,他们认为的产品目标下去使用产品,用户所感知的产品质量就是使用质量。使用质量相对不能测试,或者说测试活动具备多样性、不可预测性。

相较于常规测试,生产环境我们更倾向于收集日志,监控预警,统计用户行为,进行用户调查分析,或者A/B Testing

在 2016 年的时候,Thoughtworks 技术雷达就提出了 QA in production,这个概念于 2017 年出现在 MartinFowler 的网站上。北京的林冰玉同事也专门对 QA in Production 进行了非常详尽的阐述 。

通过以上每种质量和相应的保障机制,我们不难发现,真正意义上的测试能保障的并不像我们想象的那么多。所以才有了戴明那句关于质量和测试的经典名言:

软件质量是无法通过测试做到真正的提升的,待到测试时,软件质量已经在那里,它是在软件开发生命周期中一步步构建出来的。而测试活动,只能是一定程度的验证,质量水平反馈,以推进改进的发生。

正因为测试和软件质量有如此关系,我们也通常如此总结:

软件质量不是

  • 0 缺陷

零缺陷?不可能,只是没发现而已,抑或对大部分用户来说不算缺陷。

  • 100% 自动化

自动化只是帮助我们实现质量反馈的一种形式,并不能说有了很全面的自动化就能保证团队能交付高质量的软件。而且受制于技术栈,产品特殊性,抑或人力成本,100% 的自动化对很多项目基本是不可能的。这一点可以参看我之前总结的关于敏捷自动化测试。

  • QA 的责任

  • 没有技术债

敏捷测试

我们总说“质量内建,全员负责”,但是很多时候我们的客户会问,为什么要 TDD?都 TDD 了,为什么还需要测试?为何有这些实践?希望以上对质量的讨论解答了这些问题。

我在入职第一天就接受了 TW 的测试指导思想的洗礼,截取其中核心思想的部分,如下:

随着敏捷的广泛运用和从业者不断的实验探索,后来又相继有了测试左移,测试右移,持续自动化等等敏捷质量实践。在 Thoughtworks 我们的 QA 同志们更是总结了一套敏捷测试宣言,这些实践和宣言都是基于软件质量本质在敏捷开发模式下的更进一步落地和反思。

在敏捷开发模式下的质量模型长什么样呢?和传统的偏产品本身的使用质量评估模型相比,敏捷质量模型,更强调流程和实践的评估。这些都是因为我们认同流程实践是能带来质量由内而外的提升的。

如果我们只是知道这样做有好处,而没思考为什么要这样做,对于构建高质量的软件也是一种团队级的意识障碍。

参考文档:
https://www.academia.edu/3713846/Different_Software_Quality_Model

https://insights.thoughtworks.cn/qa-in-production-practice/

https://www.thoughtworks.com/insights/blog/agile-quality-management-model

https://insights.thoughtworks.cn/agile-testing-manifesto/