3.7

View in English

3.7 软件维护

概述与动机

大多数软件的绝大部分生命历程,都不是在被构建,而是在被维护。系统一旦投入生产,就进入了一个(往往长达数年甚至数十年)阶段:修复缺陷、适应不断变化的环境、改进已经能用的部分,并预防未来的麻烦。在大型企业中,尤其是在政府部门中,这一阶段占据主导地位。税务引擎、福利系统、国防平台和核心财务账本,其维护周期通常远远超出委托建造它们的人当初的预期。软件维护是一门学科,致力于在软件整个运行生命周期内,保持已交付软件的正确性、时效性和价值。

维护长期以来被低估、被轻视,而这种错误的代价高昂。跨越数十年的一项又一项研究都表明,维护占软件全生命周期总成本的一半以上,对于长期存续的系统,常被引用的比例在 60% 到 90% 之间。然而组织在规划、预算、配置人手和庆祝的,往往只是最初的构建,仿佛那就是整项事业的全部。此后的一切都被当作事后补充,从一个日益缩水的预算池中拨款,交给任何有空的人去做。结果是可以预见的:脆弱的系统、士气低落的维护人员、不断攀升的变更成本,最终演变成一场被冠以”遗留系统问题”(第 3.6 章)之名的危机,而其本质其实自始至终都是一个未被管理的维护问题。

本章遵循 SWEBOK(软件工程知识体系)中的软件维护知识领域以及 ISO/IEC 14764 标准。内容涵盖维护的基础知识与四种公认的类别;使维护变得困难的关键问题,包括成本、人员配置和士气;维护流程;程序理解、再工程和重构这几项核心技术;如何估算维护成本;以及(本章杠杆效应最高的一个理念)如何从一开始就为可维护性而设计。本章的核心信念是:维护不是跟在工程之后的次要活动,而是软件工程中占比最大的部分,必须像对待工程本身一样,为其做规划、配置资源并给予尊重。

关键原则

  • 维护占据生命周期的大部分,而不是尾声。 从第一天起就为它规划和预留预算;它的花费将超过构建本身。
  • 四个类别是不同性质的工作。 纠正性、适应性、完善性和预防性维护有着不同的驱动因素和节奏;大部分工作量并不是修 bug。
  • 你无法改变你不理解的东西。 程序理解是维护中占比最大的单一活动;要让代码及其历史变得易于理解。
  • 可维护性是一种设计属性。 未来变更的成本,在很大程度上是由构建阶段所做的决策决定的;要有意识地为它进行设计。
  • 小而安全的持续变更,胜过被推迟的大变更。 要在测试安全网的保护下增量地重构和现代化,而不是不断积累”变更债务”。
  • 软件即便静止不动,也会老化。 环境在不断变化(依赖项、平台、法规),因此一个静止不变的系统会悄然腐坏;预防性维护是真正的工作。
  • 维护人员理应获得一流的地位。 维护团队的士气、知识留存和人员配置,直接决定了长期的成本和风险。

建议

区分维护的四个类别,并为每一类配置人手

ISO/IEC 14764 和 SWEBOK 都认定了四个类别,把它们混为一谈是常见的规划错误。纠正性维护修复运行中发现的缺陷。适应性维护让软件在环境变化时(新的操作系统、浏览器、依赖项、硬件、法规或对接系统)继续正常运行。完善性维护通过新增功能、提升性能、改善可用性和增强可维护性,为用户和维护人员改进软件。预防性维护则在潜在故障显现之前,通过对脆弱区域进行加固、清理和现代化,来修正这些潜在故障并降低未来的风险。一种有用的进一步划分,是把纠正性和预防性归为”修正”(处理故障),把适应性和完善性归为”增强”(处理新需求)。至关重要的是,实证研究一致发现,大部分维护工作并非纠正性的;增强和适应才是主导。要相应地做好预算和人员配置,并跟踪你的工作量实际落在哪个类别中,以便对其进行管理。

投资于程序理解

维护中占比最大的单一活动,是充分理解现有系统,从而能够安全地对其进行修改。维护人员花在阅读和推理代码上的时间,通常远多于修改代码的时间。要有意识地降低这项成本。让文档紧贴代码并保持更新(第 2.7 章)。通过架构决策记录(第 1.6 章)和整洁的提交历史(第 2.6 章)来保存决策历史。使用静态分析、依赖关系图和代码导航工具,来绘制陌生领域的地图。特征化测试(用于固定当前行为、包括各种怪癖的测试)能把默会的理解,转化为可执行、可持久保存的知识。当理解成本高昂时,每一次变更都缓慢且充满风险;当理解成本低廉时,维护就变成了常规工作。

在测试安全网下持续重构

重构是一种有纪律的代码结构调整,用于改善代码的内部质量,同时不改变其外部行为。持续、小步骤地进行重构,能够对抗代码向复杂性自然漂移的趋势,让变更成本保持平稳,而不是不断攀升。不容妥协的前提条件是一套可靠的自动化测试套件(第 2.4 章)。没有它,所谓的”重构”就只是充满风险的重写。要把重构融入日常工作:每次接触一个模块,都让它比你发现时略微干净一点,而不是把清理工作留给那些罕见的、大规模的、危险的时刻。这正是预防性维护的实践,也是成本最低的一种维护方式。

当增量变更已经不够用时,进行再工程

当一个组件已经退化到常规变更的成本或风险过高的地步时,再工程(对一个系统进行检查和改造,以新的形式将其重新构建)就是更重的工具。再工程通常将逆向工程(从实现中还原设计和意图)与正向再工程(在保留行为的同时,重建为更好的结构)结合起来。优先采用有边界的、增量的方式进行再工程,使用绞杀者模式(strangler fig)和抽象分支(branch-by-abstraction,第 3.6 章)等模式,而不是整体推倒重写。再工程处于从维护到现代化的连续谱系之上:重构针对局部的小范围问题,再工程针对结构性问题,而现代化针对平台层面的问题。

运行一套明确定义的维护流程

维护活动能从一套明确的、可重复的流程中受益,正如 ISO/IEC 14764 所描述的那样:流程实施(建立计划和程序)、问题与修改分析(分诊、复现、评估影响和成本)、修改实施、维护评审与验收、迁移,以及退役。要用有纪律的变更管理把这一切包裹起来:每一项维护请求(无论是缺陷报告还是增强请求)都应被记录、按类别分类、评估影响、排定优先级,在版本控制之下配合测试来实现,经过评审,并通过正常的流水线发布(第 11.2 章)。影响分析()理解一项拟议变更可能触及的一切()是核心环节,值得投入真正的精力。退役同样是流程的一部分:安全地停用一个系统、迁移其数据和用户、并保存相关记录,这是必须被规划、而不是临时应付的维护工作。

明确地估算维护成本,并为其提供资金

不要把维护当作免费的东西,或是构建预算中的噪声。要对它进行估算。常见的方法包括维护工作量比率(一条被广泛使用的经验法则,即年度维护成本大约相当于最初开发成本的 15% 到 25%,尽管长期存续的关键系统在其生命周期内累积的成本会远高于此)、诸如 COCOMO II(构造性成本模型)之类的参数化模型及其维护和复用扩展,以及基于你自己历史数据(缺陷率、变更量和变更成本)的度量驱动预测。要把这些估算结果输入到总拥有成本分析以及第 10.10 章所讨论的经济学之中。一个系统的购买价格或构建成本只是首付款,按揭还款才是维护,而它应当出现在每一份商业论证之中。

从一开始就为可维护性而设计

对维护成本影响最大的杠杆,是在维护开始之前就已经被施加的。用 ISO/IEC 25010 的术语来说,可维护性(可分析性、可修改性、可测试性和模块化)是一种设计质量属性,必须成为一项明确的需求,而不是一个侥幸的巧合。要偏好模块化、松耦合、高内聚的设计(第 2.2 章);清晰的接口和关注点分离;强健的自动化测试;可读的代码和最新的文档;以及丰富的可观测性,使运维人员和维护人员能够看清系统正在做什么(第九部分)。这里的每一项决策,都是用眼下多付出的一点努力,去换取系统在实际存续的数十年间不断复利累积的巨大节省。为可维护性而构建,是整个生命周期中回报最高的一项投资。

权衡:优点与缺点

方法优点缺点
持续重构 / 预防性维护保持变更成本平稳,降低风险,投资回报率高需要持续投入精力,却没有可见的新功能;需要强健的测试
推迟维护(“维持现状”)本季度成本最低;为新功能释放产能变更债务不断累积;最终引发危机,迫使采取昂贵的行动
对退化组件进行再工程恢复可维护性,延长有效寿命需要大量精力和风险;必须谨慎地保留原有行为
预先为可维护性而设计终生节省不断复利累积;未来每一次变更都更容易初始成本和纪律要求更高;收益被推迟,也不那么显而易见

维护中反复出现的权衡,是当前成本与未来成本之间的取舍,而诱惑总是倾向于推迟。跳过重构、放任依赖项老化、让维护团队饥饿,这一切在本季度看起来都是免费的,因为账单会在之后到来:变成一个更慢、更有风险、更昂贵的系统,最终演变成一场”遗留系统危机”。良好维护的纪律,就是现在支付小额的、持续的、看得见的成本,以避免日后支付巨额的、突如其来的、足以毁掉职业生涯的成本。由于这种节省被推迟且不可见,这项权衡需要真正理解生命周期经济学、而不仅仅是关注发布日期的领导层。

与团队讨论的问题

  1. 在你们的预算中,谁拥有”维护”这个数字,它是一条一流的预算科目,还是从构建预算中省下来的边角料? 维护占据了全生命周期成本的大部分,对于长期存续的系统通常在 60% 到 90% 之间,然而它却常常被当作事后补充来提供资金,交给任何有空的人来负责。当预算只是剩余物时,预防性工作是最先被削减的,变更债务不断累积,随之而来的是可预见的滑向”遗留系统危机”。请带上一个真实的估算(维护工作量比率、参数化模型,或你自己的历史变更成本数据),并指明谁对系统整个生命周期的资金负责。解决办法是在每一份商业论证中明确为维护做预算,就像按揭款项与购房价格并列出现一样。只庆祝上线时刻的领导层,将持续让这个真正耗费大部分金钱和风险的阶段得不到充分的资金支持。

  2. 你们是否为预防性维护划定了受保护的产能,还是它总是败给下一个功能? 预防性工作(在测试安全网下重构、保持依赖项更新、加固脆弱区域)是成本最低的维护方式,因为它让变更成本曲线保持平稳,而不是任其攀升。它也是最容易被推迟的,因为跳过它在本季度看起来是免费的,账单会在之后以一个更慢、更有风险的系统的形式到来。一个具体的机制会有所帮助:设立一项常设配额,许多强大的团队会保护大约五分之一的产能,使其不会在每个冲刺周期都被讨价还价掉。请带上你们的变更成本趋势作为证据;如果它在上升,说明你们已经投入不足。这种纪律就是现在支付小额的、可见的成本,以避免日后支付巨额的、突如其来的、足以毁掉职业生涯的成本,而这需要能读懂生命周期经济学、而不仅仅是发布日期的领导层。

  3. 你们退役一个系统的计划是什么,你们上一次真正停用一个系统是什么时候? 退役是维护流程中明确的一部分(数据迁移、用户切换、记录保存、安全关停),然而组织却常常背负着已经死掉的、冗余的系统数年之久,因为停用工作既不光鲜,也没有预算。每一个”僵尸系统”仍然在消耗许可证、安全补丁、集成接口,以及本可以投入别处的人的注意力。请带上一份清单,标出没有活跃用户、或已经有完整替代方案上线的系统,然后像对待其他工作一样规划它们的关停:迁移数据、保留法规要求保存的内容,并确认不再有任何东西依赖它们。在政府部门尤其如此,记录保存相关法律会塑造你如何退役一个系统,因此要及早让合规团队参与进来。一个值得跟踪的成熟度信号是:你的组织上一次有意识地关闭某个东西,是什么时候?

  4. 每一次变更中,有多少时间花在动手之前理解系统上,你们在最重要的系统上的”巴士系数”是多少? 程序理解是维护中占比最大的单一活动,其成本取决于你把代码、代码的历史和代码的行为保持得有多易于理解。当理解只存在于少数几个资深人员的脑子里时,每一次人员离职或退休,都会推高未来每一次变更的成本,而一次缺席就可能拖延一个关键修复。请带上证据:近期变更中阅读推理时间与编辑时间的比例、能够安全修改每个核心模块的人数,以及业务规则和决策是随代码一起被记录下来,还是每次都要凭记忆重新拼凑。与之相抗衡的考量是,文档和特征化测试现在需要投入精力,而收益要到以后才会显现,因此很容易被跳过。在企业和政府场景中,系统的寿命往往比其最初作者的职业生涯长上几十年,法定规则被埋藏在一个没有人完全记得清楚的计算引擎里,因此要把已被捕获的理解(架构决策记录、特征化测试、最新文档)当作一项你有意识投入资金的资产,而不是等某人有空时才顺带做的事情。

  5. 究竟是谁在为你们的维护工作配置人手,它的地位和士气是否与其重要性相匹配? 维护占据了生命周期成本的大部分,也是难度最高的一种工程()在安全的前提下修改你并未构建、也可能并未完全理解的系统()然而它却常常被交给经验最少的人,并被塑造成低地位的”维持现状”工作。这种信号具有腐蚀性:你最优秀的工程师会回避这项工作,知识会先集中在少数人身上,然后随他们一起离开公司,而在无人留意的情况下变更成本不断攀升。请带上维护你们寿命最长的系统的人员的资历概况、你们的人员流失和知识留存数据,以及一个诚实的判断:在你们的组织里,维护是一条职业死路,还是一门受尊重的专长。这种张力是真实存在的,因为有抱负的工程师想要构建新东西,而领导者想要庆祝上线,因此尊重维护需要刻意的制度安排。对于一个承载着数十年监管和财务风险的大型企业或公共机构而言,用受人尊敬的资深工程师来配置维护工作,是一项风险管理决策,而任由维护变成一种”惩罚性调岗”,正是制造下一场遗留系统危机的方式。

  6. 你们是否跟踪工作量实际落在四个类别中的哪一个,你们是否把变更成本作为一项领先指标来衡量? 团队常常按照”维护主要是修 bug”的假设来做规划,而实证研究表明增强和适应才是主导,因此一个只为纠正性工作提供资金的项目组合,从一开始范围就定错了。没有类别跟踪,你就看不出一个系统正在被源源不断的监管适应性变更所重塑;没有变更成本指标(变更前置时间、变更失败率、复杂度趋势),你就无法判断你的曲线是平稳的,还是正在悄悄爬向一场危机。请带上你们过去一年实际的类别分布、如果有的话你们的变更成本趋势,以及一个诚实的说明:影响分析究竟是一个真正的步骤,还是在截止日期压力下被跳过的形式主义。与之相抗衡的因素是,度量本身需要投入精力,在系统仍然能用的情况下,这可能显得像是额外负担。在企业和政府的项目组合中,许多团队维护着许多系统,其中任何一个系统上升的成本曲线都是一个值得采取行动的早期预警,共享的类别跟踪和变更成本指标,正是让领导层能在一个模块退化之前、而不是在它当众失效之后就对其进行再工程的东西。

行业视角

初创企业。 只有少数几名工程师、跑道也很短,你负担不起一套重量级的维护流程,但你也负担不起一个没人愿意碰的代码库。要在每个周期中划出一小块常设的份额(大约五分之一的时间)用于预防性工作:给依赖项打补丁,在小缺陷积累之前把它们清理掉,并在现有测试的保护下重构那些你早已心生畏惧的角落。目标是在你不断转型的过程中,让代码保持低成本可变更,这样当你的团队扩张到二十名工程师时,就不会误把被推迟的维护当成一个”遗留系统问题”。

小型企业。 没有专职的维护专家,预算也紧张,应当倾向于购买和托管,而不是自建,这样适应性维护(安全补丁、平台和依赖项更新)在很大程度上就成了别人的工作。在你确实拥有自己代码的地方,要让它保持小巧、朴实、文档齐全,并确保至少有两个人理解业务所依赖的一切。要跟踪那几个你承受不起失去的系统,并为保持它们的更新明确预留一笔不大但真实存在的预算,而不是假装维护是免费的。

企业。 在规模化的场景下,你要维护跨越许多团队的许多长期存续的系统,因此优先事项是一套明确定义、可重复的流程:一条经过记录和分诊的请求流水线,划分为四个类别,常规的影响分析,以及一项受保护、不会被讨价还价掉的常设预防性配额。要把维护当作一流的项目来提供资金,在整个项目组合中衡量变更成本指标,并把一条上升的曲线当作在一个模块变成负债之前对其进行再工程的触发信号。治理和审计方面的期望意味着,类别跟踪和变更记录不是额外负担,而是证明整个资产处于受控状态的证据。

政府。 采购规则、透明度和公共问责制,对维护的塑造不亚于对工程本身的塑造。由法规驱动的适应性维护会伴随着不能延误的、严格的年度截止日期而到来,因此要把维护作为一项无限期的运营成本来做预算,并配置一支稳定的专家团队,来保留那些其制定者早已退休的规则的相关知识。退役工作受到记录保存法律的约束,因此要从一开始就让合规团队参与停用计划,并优先选择那些能让系统保持可维护、可移植的合同和架构,而不是让自己在数十年内被单一供应商困住。

示例

初创企业。 一家刚刚交付了最小可行产品(MVP)的初创企业,很容易把每一个小时都投入到新功能上,但它的创始工程师从第一个月起,就在每个冲刺周期中划出一块常设的份额(大约五分之一的时间)用于维护。这笔预算保持依赖项打好补丁,在小缺陷积累之前把它们清理掉,并重构团队早已心生畏惧的角落,因此即便产品在不断转型,代码库依然保持着低成本可变更。跳过这一步的初创企业,往往在发展到二十名工程师、代码库变得没人愿意碰的时候,才把它误认作一个”遗留系统问题”,而它其实自始至终都是被推迟的维护。

企业。 一家全球性银行运行着一套已投入生产十五年的支付平台。它把维护当作一项永久性的、一流的项目来提供资金,而不是一条剩余预算科目。工作被分诊到四个类别中:一股稳定的适应性变更流用于跟踪新的监管要求和合作银行接口更新;完善性工作用于新增功能和提升吞吐量;纠正性工作按照严格的服务水平协议(SLA)清理缺陷;而一项常设的预防性配额(大约占团队产能的五分之一),则在一套全面的测试套件保护下,通过持续重构来偿还复杂度债务。团队衡量变更前置时间和变更失败率,并把上升的变更成本当作一个早期预警,在一个模块变成负债之前就对其进行再工程。维护人员是受人尊敬的资深工程师,而不是被安置在”维持现状”岗位上的初级员工。

政府。 一家国家税务机关维护着一套已经运行三十多年的系统,每年都要随着税法的变化进行修订。这里占主导地位的类别是由法规驱动的适应性维护,伴随着不能延误的、严格的年度截止日期。该机构在程序理解方面投入巨大:业务规则与代码一起被记录下来,特征化测试固定住了那些原作者早已退休的规则的行为,影响分析是对计算引擎进行任何变更之前的一个正式步骤。由于环境(法律)在持续变化,这个系统永远不可能”完成”,因此该机构把维护作为一项无限期的运营成本来做预算,配置一支稳定的专家团队来保留相关知识,并在核心系统持续运行的同时,对源代码控制、持续集成(CI)和自动化测试等周边的交付实践进行现代化改造。

商业论证:动机、投资回报率与总拥有成本

软件的核心商业事实是:钱真正花在的地方是维护,而不是构建。纵观整个行业和数十年的研究,维护占据了生命周期总成本中明显的大部分,对于存续时间长的系统,常被引用的比例在 60% 到 90% 之间()而在企业和政府领域,大多数系统正属于此类。任何在上线时刻就止步的总拥有成本分析,其误差都会达到数倍之多。认真对待维护的核心商业论证,其实很简单,就是准确性:要为系统的整个生命周期做预算,否则就会一再被账单吓一跳。

投资回报来自于扭转成本曲线。在一个被忽视的系统中,随着复杂度不断累积、理解不断衰减,每一次变更的成本都会随时间上升,直到变更变得慢得令人难以忍受、且风险高昂。而在一个维护良好的系统中,持续的预防性工作(重构、依赖项更新、测试覆盖、文档编写)让这条曲线保持平稳,因此第一千次变更的成本大致与第十次相当。因此,投资于可维护性和预防性维护,不是一项应当被最小化的开支,而是决定一个系统能否始终保持低成本可变更、还是逐渐滑向第 3.6 章所述遗留资产不断攀升的成本和风险、以及第 10.4 章所述可持续性挑战的那根杠杆。要有意识地为维护提供资金,把变更成本作为一项领先指标来衡量,并把一条上升的曲线当作需要采取行动的信号,而不是自然规律。相关经济学在第 10.10 章有更详细的讨论。

反模式与陷阱

  • 把维护当作事后补充。 只为构建做预算、只庆祝构建,却让规模远大得多、持续时间也远长得多的维护阶段陷入资源匮乏。
  • 用经验最少的人来配置维护工作。 把最难的工作(在你并不完全理解的系统上安全地进行变更)交给最没有装备应对它的人,从而暗示维护是低地位的工作。
  • 把维护与修 bug 混为一谈。 只为纠正性工作做规划,而实际上适应和增强才是工作量的主导。
  • 无限期地推迟预防性维护。 从不重构,从不更新依赖项,直到变更债务迫使一场昂贵的危机爆发。
  • 在未做影响分析的情况下修改代码。 做出一个”小修复”,结果却在别处引发了意想不到的连锁故障。
  • 在没有测试安全网的情况下重构。 在无法证明行为得到保留的情况下重新组织代码:那只是充满风险的重写。
  • 任由知识随人流失。 未能记录业务规则和决策,导致每一次人员退休或离职都推高未来每一次变更的成本。
  • 从不退役任何东西。 永远背负着已经死掉的、冗余的系统,因为停用工作既不光鲜,也从未被规划过。

成熟度模型

  • 第 1 级,启动。 维护没有计划也没有资金,由任何有空的人被动地处理。它被视为修 bug,被视为低地位的工作。没有类别跟踪,没有成本估算,知识只存在于少数几个人的脑子里。变更成本在无人察觉的情况下不断上升,直到某次修复陷入停滞,或一场危机迫使人们关注。
  • 第 2 级,发展。 一些团队已经开始记录和分诊维护请求,并设有一条预算科目,但这种做法在组织内并不一致,预算通常只是剩余物。纠正性工作被跟踪,而适应性和完善性工作量却没有被清楚地区分开来。一些角落里存在测试和文档,因此变更部分受到控制,但理解成本在各团队之间仍然高昂且参差不齐。
  • 第 3 级,标准化。 一套(依据 ISO/IEC 14764)明确定义的维护流程已被记录下来,并在全组织范围内强制执行:工作被划分到四个类别中,影响分析和变更管理已成为常规做法,维护在每一份商业论证中都得到明确的估算和资助。预防性维护和重构在一套坚实的测试套件之下成为标准做法,可维护性(可分析性、可修改性、可测试性、模块化)是一项明确的设计需求,而不是某个团队的局部习惯。
  • 第 4 级,管理。 维护工作被对照基线进行度量和控制。变更成本指标(变更前置时间、变更失败率、复杂度和缺陷趋势)按系统被跟踪,四个类别的工作量组合被量化并与预期进行比对,维护工作量比率和参数化估算被对照实际的历史变更成本进行校验。一条上升的成本曲线会被作为领先指标检测出来并触发行动,预防性配额的规模也是根据证据而不是凭猜测设定的。重构、再工程或退役的决策,是依据度量出的阈值、而不是直觉做出的。
  • 第 5 级,协同。 维护在整个组织及其生命周期经济学中被持续改进和整合。生命周期总拥有成本驱动着项目组合的投资,再工程在组件退化之前就被有意识地应用,知识被主动保留下来,退役工作被规划并被常规地执行。组织会随着环境的变化(法规、平台、依赖项)重新平衡维护工作量,维护人员是受人尊敬的资深工程师,整个资产也在不断适应,使变更成本在那些寿命长达数十年的系统中始终保持平稳。

讨论思路

  1. 你们的工程投入中,实际有多大比例花在维护上,你们的预算和人员配置是否反映了这一现实?
  2. 你们能否把维护工作拆分为四个类别,其组合比例是否与你们的假设相符?
  3. 一次典型的变更中,有多少时间花在理解系统上、又有多少花在修改系统上,什么能让理解的成本变得更低?
  4. 你们的变更成本随时间是在上升、持平,还是下降,你们是否在对它进行度量?
  5. 你们的团队是否拥有可靠的测试安全网,使持续重构变得安全,还是重构风险太大以至于无人敢尝试?
  6. 谁在维护你们寿命最长的系统,他们的知识是如何被捕获下来的,这项工作的地位和士气如何?

关键要点

  • 维护占据了软件生命周期成本的大部分(对于长期存续的系统通常在 60% 到 90% 之间),必须被作为一项一流活动来规划、预算和配置人手。
  • 四个类别(纠正性、适应性、完善性、预防性)是各自不同的工作,通常是增强和适应、而不是修 bug 占据主导。
  • 程序理解是维护中占比最大的单一活动;要让代码、历史和行为保持易于理解,从而让每一次变更都保持低成本。
  • 在测试安全网下持续重构,并增量地对退化的组件进行再工程,以保持变更成本平稳。
  • 明确地估算维护成本,并将其输入总拥有成本和经济决策之中。
  • 从一开始就为可维护性而设计(这是整个生命周期中回报最高的投资),并把维护人员当作他们理应成为的资深专业人士来对待。

参考文献与延伸阅读

  • IEEE Computer Society, SWEBOK Guide (Software Engineering Body of Knowledge), Software Maintenance knowledge area
  • ISO/IEC 14764 / IEEE 14764, Software Engineering: Software Life Cycle Processes, Maintenance
  • ISO/IEC 25010, Systems and software Quality Requirements and Evaluation (SQuaRE): maintainability quality characteristics
  • Martin Fowler, Refactoring: Improving the Design of Existing Code
  • Michael Feathers, Working Effectively with Legacy Code
  • Thomas M. Pigoski, Practical Software Maintenance
  • Penny Grubb and Armstrong A. Takang, Software Maintenance: Concepts and Practice
  • Barry Boehm et al., Software Cost Estimation with COCOMO II (maintenance and reuse models)
  • Meir M. Lehman, “Laws of Software Evolution” (on why software must continually change or become less useful)
  • Robert C. Seacord, Daniel Plakosh, and Grace A. Lewis, Modernizing Legacy Systems