拓展阅读
Devops-02-Jpom 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件
项目管理平台-01-jira 入门介绍 缺陷跟踪管理系统,为针对缺陷管理、任务追踪和项目管理的商业性应用软件
项目管理平台-01-Phabricator 入门介绍 一套集成的强大工具,帮助公司构建更高质量的软件
软件维护
软件维护(英语:Software maintenance),是指在软件产品发布后,因修正错误、提升性能或其他属性而进行的软件修改[1]。
一般认为软件维护只和修正错误有关。不过有研究指出80%的软件维护工作是用在非纠正性的行动[2]。
软件维护同时包括管理层面及技术层面。管理层面的问题包括:配合客户的优先级、人员配置及费用估计。
技术层面的问题包括:对需求、系统或问题有限的理解、影响分析、测试以及可维护性的量测。
软件维护
软件维护指的是软件交付后的修改过程。
根据IEEE标准软件工程术语词汇表,软件维护是指在软件初始开发和部署后,对软件进行修改和更新的过程,旨在纠正缺陷、提高性能或其他属性、增加新功能以满足不断变化的用户需求,或适应变化的环境。需要强调的是,软件维护涉及许多活动,远不止是修复bug。
软件维护是一个持续的过程,对于软件系统的长寿命至关重要,可以保持其有效性、适应性和在不断发展的技术环境中的相关性。
软件维护的挑战
软件维护通常被认为是技术难度较低、回报较少的工作,因此成为了外包或离岸开发的常见目标。通常,开发软件的团队与负责维护的软件团队不同,开发人员缺乏编写易于维护代码的动力。软件交付时通常是未完成的,几乎总包含一些bug,这些bug需要由维护团队修复。软件维护通常从新增功能的开发开始,但随着产品生命周期的接近结束,维护逐渐减少到最低限度,最终在产品被撤销之前完全终止。
软件维护的流程
每个维护周期通常从一个变更请求开始,该请求通常来自最终用户。该请求会被评估,如果决定实现该变更,程序员将研究现有代码以了解其工作原理,然后实施变更。测试以确保现有功能得以保留并且新增功能得以实现,通常占据了大部分的维护成本。
软件维护的类型
软件维护可以根据是否是预防性或反应性的、是否是为了添加新功能或保持现有功能而进行的,进行以下分类:
- 纠错性维护:这是最常见的维护类型,主要目的是修复软件中的bug。
- 适应性维护:这种维护旨在使软件适应新的环境或技术变化,通常包括适配新操作系统、硬件平台或与其他系统的兼容性。
- 完善性维护:随着用户需求的变化,软件功能可能需要增加或改进。这种维护通常涉及添加新功能或增强现有功能,以确保软件能够继续满足用户的需求。
- 预防性维护:这种维护目的是改善软件的可维护性、可扩展性和可用性,虽然这类维护不会立即解决问题,但通过改善软件结构,可以降低未来发生故障的可能性。
软件维护的长期影响
尽管软件开发通常受到更高关注,但实际上,软件生命周期中的维护阶段常常占据了大部分成本。
研究表明,维护成本通常是开发成本的数倍,因此,如何优化和高效地进行软件维护,依然是软件工程中的一个重要课题。
软件维护的历史
在1970年代初期,公司开始将软件维护与独立的工程团队分离,以解放软件开发团队从支持任务中脱身。
1972年,R.G. Canning发表了《维护冰山》一文,提出软件维护是软件开发的延伸,并增加了一个新输入——现有系统的维护。
此后,软件维护的学科基本没有太大变化。
进入21世纪后,软件维护的一个创新是公司故意发布不完整的软件,并计划在发布后进行完成。
这种变革以及其他扩展功能的做法,通常被称为“软件演化”而不是简单的维护。
发展变化
这一创新标志着软件生命周期的转变,即开发人员开始将部分功能留到发布后再进行完善。
这种做法对于应对快速变化的市场需求和用户反馈尤为重要,同时也促使了“持续交付”和“敏捷开发”理念的兴起,使得软件开发不再是一个线性的过程,而是一个不断演化的周期。
尽管如此,软件维护本身仍然是不可或缺的,它不仅涉及对现有功能的修复,还包括适应新的技术和业务需求,以及对软件进行持续的性能优化和功能扩展。
软件生命周期
尽管软件经过了测试和质量保证,几乎所有的软件系统仍然包含一些无法正常工作的缺陷,因此在发布后维护成为了必不可少的环节,用于修复这些缺陷。
现代软件通常由预先存在的商业现货软件(COTS)和开源组件与定制代码组成。COTS和开源软件会随时间不断更新,这有助于减轻维护负担,但对于这些组件的修改仍然需要在最终产品中进行适配。
与软件开发侧重于满足指定要求不同,软件维护通常是由事件驱动的——如用户请求或缺陷的检测。
它的主要目的是保持软件的有效性,通常是应对变化的需求。
如果将其视为软件开发生命周期的一部分,维护通常是生命周期的最后阶段,并且通常是持续时间最长的阶段,占生命周期成本的80%至90%。
其他模型则将维护视为独立于软件开发的过程,作为“软件维护生命周期”(SMLC)的一部分。
SMLC模型通常包括理解代码、修改代码和重新验证代码等步骤。
从发布到维护再到生命周期结束
软件退休流程图
软件发布后,通常处于不完整的状态。开发者会在资金或时间耗尽时测试产品,因为与超时或超预算相比,发布一个不完美的产品面临的后果较小。
开发团队与维护团队之间的过渡通常低效,缺乏已知问题的列表或验证测试,维护团队很可能需要重新创建这些测试。
发布后,开发团队的成员可能会被重新分配或不再可用,维护团队需要在发布后的第一年内增加额外的资源,以提供技术支持和修复开发过程中遗留下的缺陷。
最初,软件发布后可能会经历一段增强期,期间根据用户反馈添加新功能。最终,企业可能决定不再进行功能改进,而仅提供缺陷修复和紧急更新。随着架构老化或缺乏专业知识,变更变得越来越困难且成本上升。软件不再维护且无法获得任何更新时,某些厂商会尽可能长时间从软件中获取收益,尽管该产品可能变得越来越不受欢迎。最终,软件会从市场上撤下,尽管它仍可能被使用。在这个过程中,软件成为了遗留系统。
变更周期
变更周期的第一步是接收来自客户的变更请求,并对其进行分析,以确认问题并决定是否实施该变更。
这一过程可能需要多个部门的输入,例如,营销团队可以帮助评估该变更是否能带来更多的商业机会。
软件开发的工作量估算是一个困难的问题,尤其是对于维护变更请求,但如果变更请求太昂贵或不可行,它可能会被拒绝。
如果决定实施该请求,它可以分配到计划中的发布版本,并进行实现。尽管敏捷方法论没有维护阶段,变更周期可以以scrum迭代的形式进行。
理解现有代码是修改之前必不可少的步骤。
理解的速度取决于代码库和程序员的技能。
遵循编码规范,如使用清晰的函数和变量名称,使理解过程更加容易。
只有当代码有可能执行多次时,使用条件循环语句,并消除永远不会执行的代码也可以提高代码的可理解性。
经验丰富的程序员能够更容易地理解代码的高层次功能。
有时,软件可视化工具被用来加速这个过程。
代码的修改可以以任何方式进行。一方面,通常会匆忙应用一个快速修复,但没有足够的时间更新代码文档。
另一方面,结构化的迭代增强可以从修改顶层需求文档开始,并将变更传播到系统的下层。
修改通常包括代码重构(改善结构而不改变功能)和重组(在改善结构的同时改进功能)。
与商业软件不同,免费和开源软件的变更周期主要局限于编码和测试,文档较少。开源软件项目通常依赖于邮件列表和大量贡献者来理解代码库并有效修复缺陷。
维护中的额外问题
维护的一个额外问题是,几乎对任何代码的变更都会引入新的缺陷或意外的连锁反应,需要另一次修复。
对于安全关键代码,测试可能会消耗大部分的维护资源,因为在任何变更后都需要重新验证整个软件。
重新验证可能包括代码审查、回归测试(通过一部分单元测试)、集成测试和系统测试。
测试的目的是验证现有功能是否保持不变,并且新功能已被正确添加。
软件维护的类别
软件维护的关键目的是确保产品继续满足可用性要求。
有时,这可能意味着将产品的功能扩展到最初设想的范围之外。
根据ISO/IEC 14764标准,软件维护可以分为以下四种类型:
-
修正性维护(Corrective Maintenance):对软件进行修改,以修复缺陷或其他未满足要求的问题,通常是由最终用户报告的。
-
预防性维护(Preventive Maintenance):在交付后对软件进行前瞻性的修改,以确保软件继续满足需求或修复尚未显现的问题。
这种类型的维护尤其适用于需要高度安全性或可用性的系统。
软件恢复(软件更新、状态清理等)是预防性维护的一种形式,旨在清除状态并防止未来问题的发生。
-
适应性维护(Adaptive Maintenance):对软件进行修改,以确保其在发生环境变化后继续具有可用性或适应不断变化的环境。
-
完美性维护(Perfective Maintenance):对软件进行改进,以提高用户体验、处理效率和可维护性等质量。
完美性维护对于其他类型的维护尤为重要,因为修改现有的代码库会增加复杂性,导致现有结构的恶化。
完美性维护可能包括重写文档、代码重构和性能调优等。
根据一些估算,软件维护中约有80%的工作属于增强性维护(后两类)。
可维护性 (Maintainability)
可维护性是指软件能够在不破坏现有功能的情况下,轻松修改和调整的能力。
根据ISO/IEC 14764规范,确保软件可维护性的活动在发布前也算作软件维护的一部分。
尽管可维护性对软件的长期成本至关重要,但许多软件开发组织在开发过程中忽视了可维护性。
技术债务是指程序员因为急于完成任务或缺乏精力而选择快速而不完善的解决方案,而没有在代码中构建可维护性。
一个常见的原因是对软件开发工作量的低估,导致开发过程中分配的资源不足。
一个重要的方面是拥有大量的自动化软件测试,用于检测变更是否破坏了现有功能。
持续的挑战
可维护性面临的一个挑战是,许多软件工程课程没有强调它,课程设计中通常包含一次性的任务,规格固定且不会改变。
软件工程课程通常也不会涵盖像现实世界中那样复杂的系统。
知道自己不需要负责维护的开发工程师,往往没有动机在代码中构建可维护性。
软件维护人员 (Workforce)
软件维护通常被认为是一个较为低效且缺乏奖励的工作,如果程序员被分配到维护任务上,往往更有可能辞职。
相较于同等的开发工作,维护工作的薪酬通常更低。
维护任务通常分配给临时工或技术水平较低的人员,尽管维护工程师通常比开发工程师年长,部分原因是他们需要熟悉过时的技术。
2008年,美国约有90万软件工程师和程序员从事维护工作,占总数130万的近70%。
随着维护工作被单独分配给专门团队,很多公司将此工作外包给不同的公司,进入21世纪时,维护工作甚至外包到其他国家—无论是作为原公司的一部分,还是独立的实体。
外包的主要来源是美国、英国、日本和澳大利亚等发达国家,目的地通常是中国、印度、俄罗斯和爱尔兰等低成本国家。
外包的原因包括利用较低的劳动成本、提供全天候支持、减少开发人员的时间压力,以及将支持服务靠近产品市场。
外包的缺点包括时间差、组织割裂和文化差异等交流障碍。
尽管许多雇主认为维护工作是低技术工作,最适合外包的开发阶段,维护工作仍然需要与客户紧密沟通并迅速响应,这些都受到交流问题的影响。
维护替代方案 (Alternatives to Maintenance)
在软件工程中,“遗留系统”这一术语并没有固定的定义,但通常指的是较旧的、难以修改且仍然对当前业务需求至关重要的系统。
遗留系统通常使用过时的编程语言编写,缺乏文档,经过多年修改后结构衰退,并且需要专家才能保持其正常运转。
面对这些系统时,随着技术债务的积累,维护变得不再实际或经济。可以选择以下替代方案:
- 冻结—不再对遗留系统进行任何修改。
这种方案可能会被选择,如果供应商希望尽可能长时间提取收入,同时避免维护成本。
-
外包遗留系统的功能—将遗留系统的功能外包给其他公司,尤其是那些不被认为是核心业务功能的系统。
-
废弃现有遗留系统,重新开发新的应用程序—重新开发一个新的应用程序,完成遗留系统的相同功能。然而,这种方法效率低下,因为它需要废弃一个工作正常的系统,并且新系统可能无法适应不断变化的业务需求。
-
为遗留应用程序提供抽象层封装—通过简化过时接口来包装遗留系统。此方案不修改源代码,但新接口使得新应用程序能够访问现有组件。尽管这种方法没有解决维护遗留系统中的问题,但它能简化接口。
-
将遗留系统迁移到新平台—通过重用遗留系统的实现、设计、规范和需求来减少新软件开发的费用。迁移可能需要5至10年,但结果是获得更大的灵活性,并节省长期的维护成本。
其中80%的费用通常用于测试,即确保新系统与旧系统输出一致。
完成新系统后,需要平稳过渡,从旧系统切换到新系统,尽量减少对业务功能的影响。
研究 (Research)
尽管软件维护占用了大部分软件开发资源,但它仍是软件开发中最少研究的阶段。
大部分文献集中于如何从一开始就开发可维护的代码,较少关注如何激励工程师将可维护性作为优先事项。
截至2020年,自动化的代码重构解决方案和机器学习增强的可维护性评估仍是研究的活跃领域。
参考资料
https://zh.wikipedia.org/wiki/%E8%BB%9F%E9%AB%94%E7%B6%AD%E8%AD%B7