从实战角度看如何构建高质量的软件:一线工程师的一份质量手记
概述
这篇文章聚合了我多年开发生涯中所学到的、亲身经历的关于提升工程质量的绝大部分知识、技能与经验。
要构建高质量高可用软件,个人觉得,可以分四层来进行:
- 代码质量: 高质量软件的基石。 任何设计、测试和工程方法都无法挽救烂代码写出来的系统。
- 设计质量: 设计质量往往关乎软件的全局性品质,比如稳定性、可扩展性、健壮性等。
- 测试质量: 通过良好设计和实现的系统,需要测试质量来把关,保证代码没有重要BUG和变更不影响原有系统。
- 工程质量: 在代码、设计、测试质量的保证下,还需要工程手段(比如CodeReview, 持续集成、线上错误巡检等)来聚合所有的环节,保证更好的输出。
代码质量
代码质量的提升,主要可以通过遵循良好的编程风格和习惯、追求和学习编写优秀代码、熟悉和避免常见编程错误与陷阱、注重细腻的代码细节、持续小幅重构来实现。 代码能力就像球员的脚法和控球技术,脚法不细腻的人很容易自溃防线。
由于编程实质上是一种严谨的逻辑表达活动,因此,训练自然清晰的口头和书面表达技能,严谨缜密的逻辑思考,也是间接提升代码质量的方法。
- 写代码的指导思想:如何写出易测、清晰、健壮的牢固代码
- 如何编写可信赖的代码
- 编写更少bug的程序的六条准则
- 代码的味道
- 写出可复用代码的基本思想与实践
- 实现可扩展代码的四步曲
- 精练代码:一次Java函数式编程的重构之旅
- 一次重复代码重构的思考及探索
- 代码问题及对策
设计质量
设计质量的提升,需要丰富的开发设计经验、对健壮性、稳定性、扩展性、可维护性、高压力承载能力等系统质量指标的全面理解,更深入透明地理解系统的运行,以及仔细考量避开陷阱。设计质量就像球员对全场的理解和掌控能力,懂得很好的传球和助攻。
设计质量需要理解不同系统的特性。中小型系统通常没有太大的压力负荷,主要做好性能、健壮性、可扩展性和可维护性的设计;对于大并发系统,需要考虑承受持续而平稳的高压力负荷和峰值压力。需要挖掘系统的薄弱点并加以改进完善。
设计质量有时也与产品策略有关。较宽松的产品策略,会给设计留出更多的选择空间;而较苛刻的产品策略,则会限制设计的选择,日后改造起来成本也较大。 比如只允许导出距当前N分钟之前的订单。 N 越大,导出设计的选择空间越大,比如访问备集群数据、离线计算等,可以提升整体集群访问的稳定性,理解和维护成本也会大幅降低; 而 N 越小,会暗示商家更“即时”地导出,需要的实时性也越强,实际上并无必要。我以前还有觉得 N 设置小一些让商家觉得系统的牛逼,现在觉得挺幼稚的想法。
软件设计是一个需要持续拓展的领域。软件的复杂度主要体现在对复杂业务及业务组合的综合理解与领域建模,落地在性能、维护成本、可扩展性、可定制性、稳定性、安全性和透明监控的设计方案中。非一朝一夕之功,亦非固定模式可循。目前还在持续积累中。
- Web服务端软件的服务品质概要
- 设计方案考量的准则与细则
- 因修改报表名称引发的“惨案”
- 批量发货阻塞启示:深挖系统薄弱点
- 订单导出应对大流量订单导出时的设计问题
- HBase指定大量列集合的场景下并发拉取数据时卡住的问题排查
- 通用订单搜索的API设计得失录
- 有赞订单导出的配置化实践
测试质量
测试质量的提升,主要可以通过单测、接口测试、对比测试、压力测试等来保证。 对于开发人员来说,测试质量的提升主要靠两点: 1. 编写覆盖性强的单测和接口测试的习惯和素养; 2. 开发尽可能自动化的测试用例和对比工具。 多多益善,有胜于无。
测试主要追求高效。高效意味着有效与效率。高效的测试用例和高效地创建高效测试用例。 高效的测试用例: 以有限的测试用例覆盖核心流程和方法、主流程和方法、常用流程和方法、会造成资损的流程和方法、影响用户使用的流程和方法。测试用例忌追求全面,但是要覆盖足够全面。高效地创建测试用例: 设计良好的测试框架,通过配置化的方式来快速增加测试用例,而不是需要编写测试代码。测试数据与测试代码分离。
- 订单搜索分页失效的教训:怠惰必受惩罚
- 使用Groovy+Spock轻松写出更简洁的单测
- 深入探究单元测试编写
- 使用Java函数接口及lambda表达式隔离和模拟外部依赖更容易滴单测
- 使用Groovy+Spock构建可配置的接口测试用例集
- 基于Groovy+HttpRestful的超轻量级的接口测试用例配置的设计方案及DEMO实现
- 预发和线上的自动化对比工具微框架
- 输入输出无依赖型函数的GroovySpock单测模板的自动生成工具(上)
- 克服“测试怠惰”的习惯
工程质量
工程质量的提升,主要可以通过团队开发规范、CodeReview、持续集成、错误日志巡检等手段来保证。
质量评分建议
- 功能实现,可接受的性能 50分
- 适当单测,覆盖主流程和核心方法 60分
- 适当的日志,覆盖主要路径和状态 63分
- 添加错误和异常处理,增强系统健壮性 68分
- 代码遵循良好的编程风格和惯用法,很少重复代码 72分
- 对象职责划分合理,交互比较清晰 75分
- 性能达到比较优异,消除系统明显薄弱点 80分
- 有设计良好的公共接口、模块和API及实现 83分
- 为扩展变化预留了设计空间 85分
- 有通过配置化和定制化实现需求的能力 88分
- 代码与设计流畅自然清晰 90分
- 正常服务运行稳定,高压力负荷下坚挺 92分
- 可靠性超过99.99% 95分
- 透明严密的系统监控与报警 97分
- 故障自动恢复能力 99分
- 无坚可摧,神一样的系统 100分