26-管理-项目质量

      随着国内软件生命周期管理的愈渐成熟,很多开发团队已经认识到软件质量的重要性和必要性,各种质量保障工具和流程层出不穷。
      从经济的角度看,开发人员提交的代码的质量严重影响着整个软件的开发和维护成本。
从系统的角度看,软件是通过程序代码实现的,是代码质量的外在表现,尤其是对于一些军工或航天类行业来说,代码的质量高于一切。代码质量的重要性不言而喻。
      只有提高代码质量,才能从根本上提高软件的质量。要保证并提高代码质量,可以从多个角度入手,譬如良好的设计、统一的编码规范、强化的代码评审、有效的代码静态分析等,除此之外,我们还应该从代码运行分析入手,发现软件的性能和内存瓶颈,保证代码的运行质量。

代码质量

      软件行业有一条公理——代码会不可避免地走向腐烂。腐烂并不意味着代码不可用,而是表示代码的维护成本极高。
      代码质量一般指代码本身的质量,包括复杂度、重复率、代码风格等。代码是团队的共同财产,代码质量是团队技术水平和管理水平的直接体现。代码质量下降通常会自成因果,导致恶性循环。如以下两点:

  • 破窗效应:在烂代码上继续生产烂代码,开发人员的心里负担会小很多。
  • 传染性:烂代码传递着一种不在意质量,只看业务成果的负面信息,会伤害团队的技术热情和工作氛围,导致更多烂代码的出现。

高质量代码的优势有以下好处:

  • 在发生问题时,能够帮助开发人员快速理解和定位。
  • 可以加快应用的迭代速度,不必花费过多的时间来修复BUG和优化代码逻辑。
  • 能够帮助新的项目开发成员更快、更容易地融入项目开发中。
  • 在需要其他人员补位的情况下,便于团队成员之间快速做好承接。
  • 有效促进团队间交流合作,提升开发效率。

      降低质量要求,事实上不会降低研发成本,反而会增加整体的研发成本。在研发阶段通过降低质量所“节省”的研发成本,会在软件维护阶段加倍偿还。因此为了保证项目质量不持续下降,则需要主动采用技术或者管理手段来缓解甚至抑制烂代码越来越多的趋势。

常见的产生原因

      烂代码产生的常见原因是业务压力大,开发人员没有时间或者意愿追求代码质量。在向业务压力妥协产生烂代码后,开发效率会下降,导致压力增加,形成恶性循环。为了缓解业务压力,常见的做法是“堆人头”,但是单纯地增加人力,会因为工作风格不一致、沟通成本上升等原因导致烂代码更多。

解决方案

      要遏制这种恶性循环,既需要主动对代码质量进行管控,也要持续进行技术升级,才能系统性解决问题。不过两种方案都需要长期投入才能产生效果。
通常情况下,人们倾向于通过“堆人头”的方式快速解决业务压力的问题,巨大的代码资产库变得极端复杂。有个段子说:”世界上最遥远的距离不是生与死,而是你亲手制造的BUG就在你眼前,你却怎么都找不到它”。面对软件开发的根本性困难(复杂性、非一致性、易变性和不可见性),我们需要Back to Basics(回到根本),那些基本守则永远不会过时。
代码质量可以采用传统的业界标准进行衡量,比如编码规范、可读性、可维护性、代码重复率及可测试性。

  • 编码规范:统一代码规范有助于提升代码可读性及工作效率。
  • 可读性Code Review是一个很好的检测代码可读性的手段。Don’t make me think(别让我思考),这是一本书的名字,这本书是讲交互设计的。“别让我思考”也是软件工程师应该追求的目标。
  • 可维护性:代码的可维护性是有很多因素协同作用的结果。代码分层清晰、模块化好、高内聚低耦合、遵从基于接口而非实现编程的设计原则等,就可能意味着代码易维护。除此之外,代码的易维护性还与项目大小,业务复杂程度、文档是否全面等诸多因素有关。
  • 代码重复率:遵守DRY(Don’t Repeat Yourself)原则,尽量减少重复代码的编写工作。定期对项目进行代码重复度检测是一件很有意义的事,可以帮助开发人员发现冗余代码,进行代码抽象和重构。重复的代码一旦出错,就意味着大量的工作和持续的不可控,就要考虑将重复的代码提取出来,封装成公共的方法或组件。
  • 可测试性:代码的可测试性同样可以反映代码质量的好坏。代码的可测试性差,比较难写单元测试,基本上就能说明代码设计的有问题。

      根据以上5个原则,可以在不同阶段进行应对和处理。如在开发时,在团队中建立代码规范制度。在代码提交时,基于代码规范使用自动化工具进行代码质量检查。

代码质量指标

      根据多年的实践经验,可以总结为:高质量的代码,除了符合产品的功能设计需要之外,还应该是便于维护、执行效率高、经过充分测试并且拥有较好的稳定性。通常具有以下特性:

  1. 鲁棒(Solid and Robust)

      代码不仅要被正确执行,我们还要考虑对各种错误情况的处理,比如各种系统调用和函数调用的异常情况,系统相关组件的异常和错误。
对很多产品级的程序来说,异常和错误处理的逻辑占了很大比例。

  1. 高效(Fast)

      程序的运行应使用尽量少的资源。资源不仅仅包括CPU,还可能包括存储、I/O等。
设计高效的程序,会运用到数据结构和算法方面的知识,同时要考虑到程序运行时的各种约束条件。

  1. 简洁(Maintainable and Simple)

      代码的逻辑要尽量简明易懂,代码要具有很好的可维护性。
“大道至简”,能否把复杂的问题用简单的方式实现出来,这是一种编程水平的提现。

  1. 简单(Small)

      在某种意义上,代码的复杂度和维护成本是和代码的规模直接相关的。在实现同样功能的时候,要尽量将代码写的简短一些。
      简洁高于简短。这里需要注意,某些人为了能把代码写的简短,使用了一些晦涩难懂的描述方式,降低了代码的可读性。这种方式是不可取的。

  1. 可测试(Testable)

      代码的正确性要通过测试来保证,尤其是在敏捷的场景下,更需要依赖可自动回归执行的测试用例。
      在代码的设计中,要考虑如何使代码可测、易测。一个比较好的实践是使用TDD(Test Driven Development,测试驱动开发)的方法,这样在编写测试用例的时候会很快发现代码在可测试性方面的问题。

  1. 共享(Re-Usable)

      大量的程序实际上都使用了类似的框架或逻辑。由于目前开源代码的大量普及,很多功能并不需要重复开发,只进行引用和使用即可。
      在一个组织内容,应鼓励共享和重用代码,这样可以有效降低代码研发的成本,并提升代码的质量。
      实现代码的共享,不仅需要在意识方面提升,还需要具有相关的能力(如编写独立、高质量的代码库)及相关基础设施的支持(如代码搜索、代码引用机制)。

  1. 可运维(Operational)

可运维已经成为软件研发活动的重要组成部分,可运维重点关注成本、效率稳定性三个方面。
程序的可运维性和程序的设计、编写紧密相关,如果在程序设计阶段就没有考虑可运维性,那么程序运行的运维目标则难以达成。

  1. 可扩展(Scalable and Extensible)

      快速响应需求的变化,是互联网公司的一个重要挑战。可考虑使用插件式的程序设计方式,以容纳未来可能新增的功能。
      以上8条标准,如果要记住,可能有些困难。我们可以把它们归纳为三个方面。

方面 对应的特性
正确和性能 鲁棒、高效
可读和可维护 简洁、简短、可测试
共享、运维和运营 共享、可运维、可扩展

代码评审

      代码评审,英文名称叫做Code Review,是指通过阅读代码来检查源代码与编码标准的符合度,以及代码质量的活动。
      日常工作中,除编写代码之外,“代码评审”也是一项很重要的工作。

为什么要做好代码评审?

代码评审的重要意义表现在两个方面。

  1. 代码评审有助于提升代码质量。
  2. 代码评审有助于知识的传递。

      在2017年的一份关于代码评审调研报告中,代码评审被认为是提高代码质量最重要的方法,除了代码质量之外,评审还被视为改进团队协作方式的主要方法,包括团队范围内的知识共享、指导缺乏经验的开发人员以及增加协作频率。如下图所示:

6-管理-项目质量"
提升代码质量的重要性排序
如果仔细审视,我们会发现在研发过程中,由于代码质量低,导致了很多问题的出现。

  1. 在团队内缺少可以复用的代码,每次都需要重新编写几乎所有的代码逻辑。
  2. 很多时间花费在定位Bug和修复Bug上。
  3. 代码可读性差,阅读代码逻辑需要花费大量的时间,且难以准确理解。
  4. 代码难以维护,在不久后就只好推倒重来,这会带来巨大的资源投入和研发风险。

总之,在研发过程中降低对代码质量的要求是一种”短视”行为,从整个软件生命周期来看,保证代码的高质量才是更加经济和高效的方法。

如何做好代码评审?

代码评审中,通常会发现代码中存在如下一些问题:

  1. 各种拼写错误。
  2. 未优化的代码实现。
  3. 不必要的复杂代码。
  4. 缺少必要的注释。
  5. 重复实现已经存在的代码逻辑。
  6. 缺少必要的单元测试。

……
有一些人对代码评审有一些人情方面的顾虑。”我把别人的代码打回,是不是影响我们之间的关系?”类似这样的观点有很多。代码评审原本是一名软件工程师的经常性工作,现在在一定程度上已经扭曲为一种“社交”行为,需要考虑人情世故?!要以一个正确的心态看待这个工作流程。
评审人对代码评审应该持有的态度:

  1. 评审人对被评审的代码逻辑应做到“完全看懂”。最好的情况是,评审人对所评审代码的掌握情况就像自己写的代码一样。
  2. 评审人对什么是好的代码应该有正确的认识。好的代码,绝不仅仅是“可以运行”,还需要综合考虑其正确性、可维护性等标准(参考代码质量指标)。
  3. 评审人对代码的质量应具有一丝不苟的态度。软件是一种“非常容易腐烂”的物质,切不可有放纵的心态。
  4. 要将代码评审放在和编写代码同等重要的位置上。
  5. 在代码评审中要以“提升代码质量”为最终目标,代码编写者和代码评审人要共同努力。因此,代码评审不是单方的事情,而是需要双方的紧密沟通和配合。

线上评审

      线上评审也叫交叉评审。交叉评审简单来讲就是:你评我的、我评他的、他评你的…..,成员之间相互评审,每个人既是Author又是Reviewer,依赖于团队规范,每次提交的代码必须经过审核,这种模式更适用于人数多一些团队,我们团队每天几个Merge请求,从另外一种角度看也解决了Leader的合并任务繁琐问题,更重要的是对代码质量有了更多的提高,否则评审只是个摆设了。
      在2017年的一份关于代码评审调研报告中指出,工作量(55.1%)、时间限制(44.1%)和人力不足(33.7%)是代码评审的最大障碍。线上评审如同敏捷研发中“小步快跑”的思路,将一个大的评审拆分为多个较小的评审。

线下评审

      这个阶段的CR通常伴随着一些业务知识进行评审, 比如你正在开发一个系统的权限模块, 那就针对人员、角色、模块等等进行一系列的评审, 设计是否合理? 模块划分是否耦合? 消息机制是否完善? 可扩展性是否满足发展需要?等等。这块可以极大的提高我们在对系统架构设计方面的能力。

      总结一下,代码评审是提升代码质量的最好方法,代码评审有利于在团队内传递知识,代码评审是辅导他人编码的最好方法。所以我们在日常研发工作中要重视代码评审,做好代码评审。只有理解了代码评审的意义,才会在工作中自觉认真地做好代码评审。

代码质量平台——SonarQube

      SonarQube是代码质量管理的开源平台,可以用于管理源代码的质量,能够从7个维度检测代码质量,展示静态代码扫描的结果。
      第1个维度,代码设计。SonarQube会检测代码中的依赖、循环等关系,来判断当前代码的设计是否合理。
      第2个维度,代码规范。SonarQube 会使用CheckStyle等代码检测工具扫描代码规范是否合理,从而规范代码的编写。
      第3个维度,代码潜在缺陷。SonarQube会使用FindBugs等代码检测工具扫描代码是否存在问题,找出代码中的潜在缺陷。
      第4个维度,代码复杂度。如果代码的复杂度过高,则会导致维护困难。SonarQube会分析代码的复杂度,当增量代码超出复杂度阈值时及时给出预警,从而避免代码腐败。
      第5个维度,代码重复率。如果代码中存在大量的重复代码则说明当前质量低下,大部分此类问题都是在代码实现时没有进行抽象复用造成的,SonarQube可以扫描出这些重复率高的模块,并给出对应的提示。
      第6个维度,代码注释。通常来说,代码缺少注释会使其可读性下降,尤其在团队人员变动时,新的开发人员仅能通过阅读代码来了解代码功能。SonarQube能扫描代码,找出代码中注释过少或过多的地方。
      第7个维度,代码单元测试覆盖率。SonarQube能够很方便地统计代码单元测试的覆盖率,从而保证代码的质量。

      SonarQube巧妙地使用了插件机制。通过插件机制,SonarQube不仅可以支持JavaScript、Java等二十余种编程语言的代码质量管理与检测,还可以集成不同的测试工具、代码分析工具,以及持续集成工具,例如,PMD、CheckStyle 、FindBugs 、Jenkins等。SonarQube会对不同的代码质量检测插件的执行结果进行加工处理,以量化的形式度量代码质量的变化,从而可以方便地对不同编程语言和规模的工程进行代码质量管理。SonarQube还对大量的持续集成工具提供了接口支持,开发人员可以很方便地在持续集成工具中使用SonarQube。
      SonarQube的工作原理是先使用代码质量检测工具(如CheckStyle、FindBugs、 PMD等)分析代码,然后将分析结果写入与SonarQube服务器绑定的数据库,服务器会通过不同语言的插件算法对代码分析结果进行再加工,最终将代码分析加工结果以可视化、可度量的方式展示给用户,如下图所示。

指标

SonarQube提供了一系列的指标帮助开发人员了解项目的代码质量现状。
可靠性( Relibility) :只要有一个次要Bug,项目评级就为B;
只要有一个重要Bug,项目评级就为C;
只要有一个严重Bug,项目评级就为D;
只要有一个阻断性Bug,项目评级就为E。

安全性(Security) 是衡量代码漏洞数量的标准,从低到高分为A、B、C、D、E 5个等级:没有漏洞,项目评级为A;只要有一个次要漏洞,项目评级就为B;只要有一个重要漏洞,项目评级就为C;只要有-一个严重漏洞,项目评级就为D;只要有一个阻断性漏洞,项目评级就为E。

可维护性(Maintainability) 可以被用来衡量代码质量。SonarQube建立 了一套公式:
可维护性数值=技术债务成本/项目代码总开发成本,将可维护性进行了量化,从低到高分为A、B、C、D、E 5个等级,A到D的默认值分别为0.05、0.1、 0.2、 0.5, 只要超过0.5评级就为E。技术债务成本指修复当前不规范的代码需要投入的时间,项目代码总开发成本指从零开始重写代码所需的成本。SonarQube默认的开发一行代码的成本为30分钟,如果总代码行数为100行,那么项目代码总开发成本为3000分钟,假设技术债务为300分钟,则可
维护性数值为0.1,对应的可维护性评级为B。

覆盖率(Coverage)由条件覆盖率和行覆盖率共同组成,即单元测试覆盖的源代码行数占总代码行数的比率。

重复(Duplications) : SonarQube 会扫描项目中代码的重复情况,开发人员可以通过该指标查看到代码的重复密度、重复行数、重复文件块及重复文件数量等信息。

大小(Size):该指标直观反映当前项目的代码体量。通过该指标可以查看到新增代码行数、总代码行数、
方法数、目录数文件数以及注释行数等信息。

复杂度(Complexity) :指代码的圈复杂度,复杂度越高代表代码越难以阅读和维护。代码中的条件分支越多,代码的复杂度就越高,测试和维护越困难。

问题(Issues) :将项目中扫描出来的问题进行归类,按处理状态划分为新增的违规、违规、待处理的问题、重开的问题、已确认问题、误判的问题、不需要修复的问题。

以上几个指标在一定程度上能够反映当前项目的代码质量,SonarQube还会根据问题给出相关的建议。

安装和使用

高质量的软件项目管理可以提高用户满意度、软件系统的可靠性、安全性、可维护性和可扩展性,同时也可以提高开发效率和降低成本,提高公司的声誉和竞争力。

原文链接:https://juejin.cn/post/7224903881729130556 作者:高灯GFE

(0)
上一篇 2023年4月23日 上午10:16
下一篇 2023年4月23日 上午10:26

相关推荐

发表回复

登录后才能评论