开发高质量软件的5大原则

多少次的惨痛教训告诉我们,在软件应用发布维护版本或者补丁之前,应该避免使用其最新版本。虽然每个人都知道初始发布版本V和稳定发布版本V.n之间存在软件质量鸿沟,这个问题却一直没有得到解决。

本文将会讨论5个具有可操作性的原则,以帮助开发团队跨越质量鸿沟

1. 使用代码覆盖率反映测试完整性

软件测试的目的都是为了保证软件能在最终用户使用时是正常运行的。然而,软件测试面临着挑战,如何保证测试的完整性?很多开发组织会制定测试规程去匹配需求文档或者用户文档。这种测试方法可以验证正常操作路径,但是测试边界、错误场景都无法验证。这种方法通常只能保证60%~70%的代码覆盖率。 唯一保证测试完整性的办法就是在测试用例执行过程中收集和分析代码覆盖率数据,以确定应用的哪些功能被执行,更重要的是确定应用的哪些功能没有被执行到。由此看来,代码覆盖率分析是确定应用程序的测试进展的最佳方法,也是测试完整性的唯一可靠度量指标。代码覆盖率分析可以贯穿从开发者测试到发布测试的应用程序全生命周期。 然而,100%的代码覆盖率并不能证明应用程序就是完美的,它只能证明在工程上软件是高质量的。事实上,许多和关键性安全软件开发有关的标准都将代码覆盖率视为开发过程的一部分。比如:DO-178B/C (航空航天a), ISO 26262 (汽车), IEC 61508 (工业控制), FDA and IEC 62304 (医疗设备) and the CENELEC standard (铁路应用)。

图1:分析源代码覆盖率是度量测试活动完整性的最佳方式

2. 使用单元测试提高测试覆盖率

一旦开始度量代码覆盖率,当前测试覆盖率会明显低于100%,这都是测试只专注在正常路径的测试,忽略错误情况和边界情况造成的。最明显的提高覆盖率的方式就是增加额外的功能测试,但是应用程序代码中的20%~30%的确很难在生产环境中通过功能测试执行到,因为触发错误处理是很难的。

图2:覆盖率鸿沟是由于测试专注在正常路径的测试,忽略错误情况和边界情况造成的

严重的bug一般都是在非常规操作的情况下发生的,这些操作是从来预料到的。 这就是为什么使用单元测试的原因,单元测试对于构建健壮稳定的应用程序非常重要,因为单元测试能够触发应用程序最小粒度的功能并且证明最小粒度的需求被恰当地实现了。 在做单元测试时,一般都会使用mock等技术来独立运行程序方法。这样有很多的好处,开发者可以很方便的在开发过程中发现、定位、修改问题,单元测试还允许触发错误来测试错误处理等情况,这在生产环境中是不可能实现的。

3. 保证测试易于执行,测试结果易于理解

知难行易,很多工程师使用了不同的方法和工具想要保证测试易于执行,测试结果易于理解,比如: 开发者测试:用于保证应用程序在方法级别的正确性 集成测试:用于保证功能级别的正确性 系统测试:用于保证系统级别(最终用户使用)的正确性

图3:共同的测试协作平台是实现该工作流的关键

当测试照此分类之后,不同的测试由不同的工程师团队负责。实际上,测试工程师基本不可能执行开发者测试,开发也不会执行系统测试。为了提高软件质量,我们需要打破这种隔离,团队中的所有人都可以在任意时间执行软件任意版本的任何一种测试。共同的测试协作平台是实现该工作流的关键,该平台应该包括所有测试的前提条件和期望结果。工程师应该可以一键执行任何一个测试,除此之外,工程师还应该能够快速的debug失败的测试。

4. 实现自动化、并行、基于变更的测试

当通过测试覆盖度分析提高测试完整性、通过组织共同参与测试之后,下一步我们就要保证测试能够快速的执行。之所以测试会被换分为如此多的类型,由不同的部门负责,原因之一就是一个完整的系统测试需要花费几个小时、甚至几天才能完成。 如何提高测试执行速度呢?——构建一套可扩展、并行的、基于变更的测试基础设施 单个测试必须是原子性的、足够小、足够快的。将新测试用例加入到现有测试套件时,往往会出现测试时间成倍增加的情况。这导致测试很脆弱且难于维护。在设计测试用例时,我们一定要保持某个测试必须有其自己的前提条件,而不是依赖于其他测试的输出。

图4:每个测试必须定义它自己的前提条件而不依赖于其他测试的输出

除了测试维护性和重构测试之外,原子性还可以带来如下好处:

基于变更的测试,只执行被软件变更影响到的测试用例 并行的执行测试,同时执行更多的测试用例

大部分组织都实现了持续的自动化的增量式的软件构建系统,但是测试的依然是阶段性的。 基于变更的测试 基于变更的测试(CBT)分析受到变更的代码,智能的选择受到影响的测试子集。这比运行所有的测试快很多。基于变更的测试能够帮助我们实现严谨的持续集成开发过程。在持续集成的check-in阶段,CBT能够快速的验证新的提交并更早的检测出问题。 并行的执行测试 通过持续集成、虚拟化测试环境能够极大的提高测试用例并行速度,降低测试执行时间。

5. 不断重构代码以提高可维护性

代码重构是在不修改软件外部行为或者API的情况下重构内部组件结构。如果没有重构,随着时间的推移,代码会变的异常复杂和难以维护,当新特性和缺陷修改的代码加入进来之后,也会破外原本优雅的架构。 代码重构提高了代码可读性,降低了复杂度,降低了维护成本。好的代码重构能够通过简化逻辑和减少复杂度,以解决系统中隐藏的、遗留的、未被发现的、易受攻击的问题。 重构的最大障碍来源于缺少测试保证软件的功能正确性。软件都会存在脆弱和充满缺陷的部分,开发者往往会犹豫是否要修改这些地方,因为他们害怕破坏现有的功能。想要自信地进行重构,我们需要建立一套测试用例,以保证软件的功能正确性。

结论:

在过去的三十年里,工具、设计模式、开发范例都在变化,很多工具都承诺可以不增加工作量的情况下提高质量。然而,并没有银弹。提高软件质量是每个人的责任。提供软件质量的最有效的方式还是提供软件测试效率。

原文地址:https://dzone.com/articles/five-principles-for-engineering-high-quality-softw

译者曰:

  1. 软件质量不仅仅是软件功能符合需求而已,代码的可维护性等技术债务指标应该不断被强调,并且采用内建质量的方式在开发过程中建立起质量,而不是依靠检查来提高软件质量。
  2. 测试驱动开发,很多创业团队采用这种方式保证MVP(最简化可行产品),同时TDD也保证了软件的质量总是符合预期的。
  3. 测试覆盖率要和圈复杂度结合使用,圈复杂度过高的,测试覆盖率必然会降低,因为需要写更多的测试用例才能覆盖到代码的全部可能执行路径。建议圈复杂度低于10。
  4. 代码重构必须基于良好的自动化测试,否则测试MM会掐死你的 。

END

原文发布于微信公众号 - DevOps时代(DevOpsTimes)

原文发表时间:2017-08-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Rainbond开源「容器云平台」

【微服务干货系列】Yelp公司总结的微服务架构的实践经验

1222
来自专栏13blog.site

大型网站技术架构(四)--核心架构要素

2868
来自专栏Android 开发者

[译] 从 Android Studio 切换至 D8 dexer

3994
来自专栏韩伟的专栏

经典软件架构模式

目录 (一) 架构模式是什么 (二) 分层模式案例 (三) 微核模式案例 (四) 管道与过滤器案例 (五) MVC模式案例 (六) REST模式案例 (七) S...

4165
来自专栏架构师之路

朋友圈微博feed流,推拉实践

上一篇《feed流拉取,读扩散,究竟是啥?》关于feed流的拉取还是推送,只写了一半“拉取”,今天把另一半“推送”(写扩散)的坑填完。

2613
来自专栏沃趣科技

降低保险行业TCO成本最好的方式是……

保险行业升级测试工作较多,此为行业背景。从客户甲了解到,他所在的DBA团队一方面要承担数据库日常维护工作,另一方面也要为业务部门提供测试数据库。除去生产环境的日...

50314
来自专栏恰同学骚年

《大型网站技术架构》读书笔记一:大型网站架构演化

此篇已收录至《大型网站技术架构》读书笔记系列目录贴,点击访问该目录可获取更多内容。

1151
来自专栏老九学堂

这是篇Java数据库开发的干货,你确定不收藏吗?

无论你开发的是一款PC端的Web应用,还是一款移动端的app,都需要一个数据库来存储你的业务数据(包括电商的商品信息、游戏的道具信息、社交的人员信息等等)。可以...

4215
来自专栏Linyb极客之路

模块化与微服务比较

本文比较了微服务和模块化整体架构(modularized monolith )的区别。现在大家一股脑从整体单片monolith迁移到微服务,但是这种转变真的适合...

4273
来自专栏Aox Lei

微信公众号信息抓取方法(一)——抓取公众号历史消息列表数据

研究微信抓取之前, 看过知乎有大神写的比较完善的例子, 受到启发, 才完成了整个微信公众号的抓取。 微信公众号内容的批量采集与应用 微信抓取的难点: 1. 无法...

5.1K3

扫码关注云+社区

领取腾讯云代金券