15、软件系统构建与测试的最佳实践

软件系统构建与测试的最佳实践

1. 构建简单系统

一个设计良好的系统,其关键在于简单性。我们只需构建真正需要的部分,这样就能更轻松地确保所构建的内容正确无误。当重组代码能带来显著价值,比如让当前工作更简便、更安全时,就可以进行代码重组。一旦发现“破窗”(问题),应立即修复。

2. 管理技术债务

技术债务是指我们遗留在系统中未解决的问题。如同大多数金融债务一样,系统会对技术债务收取“利息”。这可能表现为为维持系统运行而进行的持续手动变通工作;也可能是在更清晰的架构下本可简单完成的更改,却花费了额外的时间;还可能是为用户提供了不可靠或难以使用的服务。

软件开发的一项重要原则是避免技术债务。我们应养成发现问题和缺陷就立即修复的习惯,最好是在问题产生时就解决,而不是抱有“目前这样就够了”的不良想法。

不过,这是一个有争议的观点。有些人不喜欢用技术债务来比喻实施不佳的系统,因为这意味着像为创业借钱那样是一种故意且负责任的决策。但值得注意的是,存在不同类型的债务。糟糕地实施某件事就像用发薪日贷款去度假,极有可能让你陷入破产的风险。Martin Fowler提出了技术债务象限,区分了故意与无意的技术债务,以及鲁莽与谨慎的技术债务。

3. 管理重大基础设施变更

在交付大型且可能具有破坏性的变更时,每次只进行一个小变更的工程实践可能会面临挑战。例如,要完全替换像用户目录服务这样的关键基础设施,可能需要数周甚至数月才能让新服务正常运行并通过测试。如果将旧服务替换为尚未正常工作的新服务,会给用户和我们自身带来严重问题。

以敏捷方式交付复杂工作的关键是将其分解为小变更。每个变更都应具有潜在的实用性,至少要能让某人尝试并看到效果,即使它还不适合投入生产使用。用能力的角度来思考会很有帮助。例如,与其定义一个任务为“实现对ssh的监控检查”,不如定义为“确保当服务器上的sshd不可用时能收到通知”。对于大型项目,团队可以根据能力来定义进展。

以下是一些逐步对生产系统进行重大变更的技术:
- 进行小的、非破坏性的变更 :逐步替换旧功能。例如,可以选择服务器的一个元素,编写清单(或配方、剧本等)来管理它,然后随着时间的推移,逐步添加更多的配置元素。
- 对用户隐藏变更 :以替换用户目录服务为例,可以开始构建新服务并将其部署到生产环境,但同时保留旧服务运行。可以有选择地测试依赖于它的服务。定义一个使用新用户目录的服务器角色,并在生产环境中创建一些这样的服务器,这些服务器不用于关键服务,但可以进行测试。首先选择一些候选服务迁移到新目录,比如基础设施团队使用但最终用户不使用的服务。

重要的是要确保在开发过程中,对任何需要一段时间才能实施的变更进行持续测试。

4. 测试基础设施变更

4.1 测试的目的与现状

测试的目的是帮助我们快速完成工作。但在许多组织中,测试却被视为阻碍工作进度的因素。这通常是因为将质量保证(QA)视为与软件开发或基础设施管理工作分离的功能,而不是将其融入到工作中。

自动化一个有问题的测试过程并不能使其变得更好,但自动化测试确实能让团队更容易真正对所构建的产品质量负责。团队可以持续测试正在进行的工作,从而对工作的可靠性充满信心。这种信心能实现可持续、快速的工作节奏,而这在存在未发现和未解决问题的系统中是无法实现的。

有些QA团队在使用工具自动化测试阶段时会遇到困难。他们无法编写足够的测试脚本来覆盖系统的各个方面,现有的测试也很脆弱,每次新的测试都需要花费大量时间来修复和更新测试脚本。他们原本希望自动化测试工具能让工作更轻松,但实际上却增加了工作量。很多时候,测试人员不得不依靠手动测试列表来维持工作流程。

而另一些团队将自动化测试融入到正常的开发和维护过程中。自动化测试作为持续集成(CI)和持续交付(CD)管道的一部分,全天持续运行。测试不再被视为一个单独团队的领域,而是编写代码和维护基础设施人员的责任。然而,即使是这些团队也会遇到困难。他们希望测试能覆盖100%的代码库,但维护测试却占据了大量精力。系统的每次更改都会触发一系列需要调整的测试,以确保构建通过。测试可能会间歇性失败,原因可能是系统与不可靠的外部系统集成,或者自身系统存在不确定性行为。

不过,也有许多团队能让自动化测试顺利进行。他们偶尔会花时间改进工具的使用方式,但工具不会成为工作的阻碍。他们会根据不同的目的使用多种测试工具,以保持测试的平衡。他们控制测试套件的规模,使其运行速度快,人们无需花费大量时间等待测试完成。进行更改时,可能只需要添加或更新一些测试,工作量不大。

4.2 系统管理员与测试

基础设施团队通常认为测试是一项挑战。典型的系统管理员的QA流程是:1) 进行更改;2)(如果有时间)进行一些临时测试;3) 之后密切关注一段时间。很多QA人员对基础设施了解不够,导致基础设施测试容易被忽视。

4.3 变更咨询委员会(CAB)

一些希望对基础设施进行更严格管理的组织通常会设立变更咨询委员会(CAB)。CAB通过开会审查变更请求来解决基础设施测试问题。这有一定的价值,进行变更的人可以与同事协商,同事可能会提供有用的经验和建议,能发现与其他变更的潜在冲突,也能让相关人员了解变更情况,以便在出现问题时知道与谁沟通。

然而,CAB常常会变成一种官僚程序。人们可能被迫花费时间在没有实际价值的活动上,如填写详细表格、获取橡皮图章式的签字等。在某些情况下,CAB会因为表格未填写完整而拒绝变更请求,导致需要变更的人不得不等待下一次CAB会议,可能需要一周甚至几周的时间。

如果CAB流程变得繁琐,人们会设法绕过它。他们可能学会如何绕过或简化流程,比如将所有变更都变成紧急修复。在许多组织中,人们会复制粘贴变更请求表格,而不关心其中的细节,因为他们知道签字的人并不了解具体情况,甚至有人会完全忽略CAB流程。

4.4 改进CAB方法

重要的是要考虑流程的价值,并找到最有效的方法来实现这些价值。CAB的主要目标通常包括:
- 确保计划的变更得到审查,而不是由个人单独进行;
- 避免与其他正在进行的变更发生冲突;
- 让相关人员了解变更情况,以防受到影响;
- 为任何支持活动(如通知用户)进行规划。

以下是一些可以在不成为瓶颈的情况下实现这些目标的实践:
- 在将变更应用到重要系统之前自动进行测试;
- 让两人一组共同进行变更;
- 通过电子邮件列表等方式向相关技术团队通知计划的变更,以便他们可以提问和提出建议;
- 在变更提交到版本控制系统(VCS)时向技术团队发送提交/差异消息;
- 在将变更应用到生产系统之前,对系统中高度敏感的部分进行代码审查和签字确认。

无论团队选择使用哪些实践,以下原则可以帮助保持工作的有效性:
- 优先审查已实施和测试的变更,而非未经验证的想法 :在将变更应用到生产环境之前,通过良好的测试和暂存系统(如变更管理管道)安全地审查已实施和测试的变更。如果需要,实施内容可以随时修复、改进或放弃。
- 增加审批人员的收益递减 :第二双眼睛的审查非常有价值,邀请广泛的团队成员审查和评论想法或实施内容可以带来不同的观点、经验和技能。但需要审批变更的人越多,流程就越困难,且增加的价值有限。
- 关注变更能力而非阻止变更的能力 :团队应致力于快速发现问题并修复,即平均修复时间(MTTR)。虽然强调质量文化和有效的持续测试过程很重要,但也要权衡成本和收益。快速推向市场的好处可能超过成本较低的风险,特别是当风险可以快速检测和纠正时。
- 小变更降低风险 :小的增量变更能够展示更大的解决方案,且成本低,便于讨论和审查。小变更破坏系统的风险较小,风险评估也更简单。如果出现问题,也更容易追踪和修复,从而可以简化变更流程。

4.5 拥有测试权

敏捷软件开发的一大成果是打破了开发人员和QA之间的隔阂。开发人员和测试人员共同承担质量责任,而不是将质量保证交给一个单独的团队。敏捷团队从编码开始就进行测试,而不是在系统几乎完成时才分配大量时间进行测试。

所有验证工作都应在开发过程中持续进行,这样在最后就几乎没有或很少有工作需要完成。这包括正确性测试、探索性测试、用户测试、性能测试、安全测试、可用性测试、回归测试以及特定系统所需的其他任何测试。

即使在敏捷团队中,对于QA工程师或测试人员的角色仍存在争议。一些团队认为,由于开发人员自己编写自动化测试,因此不需要单独的测试角色。但实际上,即使在高效的团队中,QA人员也能带来有价值的观点、专业知识和发现所构建内容中漏洞的能力。

以下是一些团队管理测试的指导原则:
- 自己构建的内容自己编写测试 :让单独的人员或团队编写自动化测试会产生一些负面影响。首先,交付经过测试的工作需要更长时间,代码交接会有延迟,测试人员需要花费时间理解代码应实现的功能、编写测试,并判断测试失败是因为测试编写错误、代码错误还是工作定义问题。如果开发人员已经开始处理其他任务,这会造成持续的干扰。如果团队中有专门编写自动化测试的人员,他们应该与开发人员合作编写测试。可以在测试阶段与开发人员配对工作,确保开发人员在测试完成和代码正确之前不转移到其他任务。更好的做法是在开发过程中就进行配对,在编写代码的同时编写和运行测试。目标是帮助开发人员能够独立编写自动化测试,专业人员可以继续与团队合作,审查测试代码、帮助寻找和改进测试工具,并推广良好的实践,或者去帮助其他团队。
- 每个人都应能使用测试工具 :一些自动化测试工具采用按用户收费的昂贵许可模式,这导致只有少数人能够运行测试,因为为团队中的每个人购买许可证成本太高。这会导致反馈周期变长,工程师构建好东西后交给测试人员,测试人员运行测试并报告失败,工程师只能盲目地重现和修复错误,无法自己运行失败的测试,从而导致多次“已修复”“仍然失败”“这次呢”“又破坏了其他东西”等循环。实际上,有许多强大的测试自动化工具,有大量的免费和商业支持社区,它们要么是免费的,要么价格便宜,不会给交付过程增加负担。

4.6 为可测试性定义工作

QA人员在项目中带来的一个非常有用的帮助是帮助我们更清晰地定义工作。大多数系统管理员倾向于直接开始实施工作,认为自己对所需做的事情有足够的了解,可以在构建过程中解决其他问题。虽然这种方法在学习和尝试新事物时可能有效,但对于具体任务,明确期望的结果、原因以及如何判断任务是否完成是很有帮助的。

4.6.1 故事语句

敏捷开发中有“用户故事”的概念,这是一个小而具体的工作单元,可以根据其价值和结果进行清晰定义。常用的“故事语句”格式为:“作为(用户),我希望(具备某种能力),以便(实现某种价值)”。不习惯这种方式的基础设施团队通常难以以真正体现这些要素的方式定义故事。有敏捷经验的业务分析师(BA)或QA人员可以帮助团队学习这种定义工作的习惯和技巧。

以下是一些基础设施故事语句的好坏示例:
| 不好的示例 | 好的示例 |
| — | — |
| 作为基础设施架构师,我希望添加nagios内存检查,以便发送警报 | 作为支持团队成员,我希望在服务器即将内存不足时收到警报,以便防止停机 |
| 作为安全审计员,我希望虚拟机安全,以便系统安全 | 作为虚拟机所有者,我希望确保虚拟机上只运行严格必需的进程,以减少虚拟机的攻击面 |

在一些示例中,我们可以看到像“我希望虚拟机安全”这样宽泛、模糊的表述。迫使自己更具体地描述有助于将故事分解为更小、可实现的工作单元。像“使虚拟机安全”这样的一般性故事可能会无限期地处于进行中状态,因为在这个标题下总是有更多的工作可以做。

4.6.2 验收标准

一个好的故事语句有助于明确工作的目标,而验收标准则提供了更详细的信息。验收标准规定了验证是否达到目标的方法,这有助于执行工作的人明确期望,并有助于测试。经典的验收标准格式是“给定(起始条件),当(操作或事件)发生时,那么(结束条件)”。

例如:“给定任何角色的虚拟机,当CPU使用率超过95%持续5分钟以上时,那么发送监控警报”。

软件系统构建与测试的最佳实践

4.7 测试实践总结与展望

在软件系统的构建与测试过程中,我们已经探讨了多个关键方面,从系统构建的简单性原则、技术债务的管理,到重大基础设施变更的处理,以及测试基础设施变更的各种方法和原则。这些实践相互关联,共同构成了一个高效、可靠的软件开发和运维体系。

为了更清晰地展示整个流程,我们可以用一个 mermaid 流程图来概括:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;

    A(构建简单系统):::process --> B(管理技术债务):::process
    B --> C(管理重大基础设施变更):::process
    C --> D(测试基础设施变更):::process
    D --> E(拥有测试权):::process
    E --> F(为可测试性定义工作):::process
    F --> G(持续改进):::process

从这个流程图中可以看出,每个环节都是紧密相连的。构建简单系统是基础,它为后续的技术债务管理和基础设施变更提供了良好的架构基础。管理技术债务可以避免系统因积累过多问题而变得复杂和难以维护。管理重大基础设施变更则确保了系统能够在不断发展的过程中平稳过渡。而测试基础设施变更则是保障系统质量的关键环节,通过有效的测试可以及时发现和解决问题。拥有测试权和为可测试性定义工作则是从人员和工作定义的角度,进一步优化测试流程,提高测试效率。

在实际应用中,我们可以根据这个流程来制定具体的工作计划。例如,在构建新系统时,首先要遵循简单性原则,只构建必要的功能。在开发过程中,及时发现和解决技术债务问题,避免问题积累。当需要进行重大基础设施变更时,按照小变更的原则逐步推进,并在开发过程中持续进行测试。同时,要确保开发人员和测试人员共同承担测试责任,为工作定义明确的可测试目标和验收标准。

未来,随着软件技术的不断发展,我们还需要不断探索和改进这些实践。例如,随着人工智能和机器学习技术的应用,我们可以利用这些技术来自动化测试过程,提高测试的准确性和效率。同时,随着云计算和容器化技术的普及,我们需要进一步优化基础设施变更的管理方法,以适应新的技术环境。

5. 总结

在软件系统的开发和运维过程中,我们面临着各种挑战和问题。通过采用本文介绍的最佳实践,我们可以有效地应对这些挑战,提高系统的质量和可靠性。

首先,构建简单系统是关键。简单性可以降低系统的复杂度,提高系统的可维护性和可测试性。我们应该只构建必要的功能,避免过度设计和冗余代码。

其次,管理技术债务是确保系统长期稳定运行的重要措施。我们要养成及时解决问题的习惯,避免技术债务的积累。同时,要认识到不同类型的技术债务,并采取相应的管理策略。

管理重大基础设施变更是一个复杂的过程,需要我们采用小变更的原则,逐步推进变更,并在开发过程中持续进行测试。通过这种方式,可以降低变更带来的风险,确保系统的平稳过渡。

测试基础设施变更是保障系统质量的重要环节。我们要将测试融入到开发和运维的全过程中,采用自动化测试工具,提高测试的效率和准确性。同时,要打破开发人员和测试人员之间的隔阂,共同承担测试责任。

最后,为可测试性定义工作可以帮助我们更清晰地明确工作目标和验收标准,提高工作的可衡量性和可管理性。我们要采用用户故事和验收标准的方法,将工作分解为小而具体的任务,确保每个任务都有明确的价值和结果。

通过遵循这些最佳实践,我们可以构建出更加可靠、高效的软件系统,满足用户的需求,为企业的发展提供有力支持。

以下是一个总结表格,概括了本文介绍的主要实践和要点:
| 实践领域 | 主要要点 |
| — | — |
| 构建简单系统 | 只构建必要功能,及时重组代码,修复问题 |
| 管理技术债务 | 避免积累,及时解决问题,区分不同类型债务 |
| 管理重大基础设施变更 | 分解为小变更,持续测试,从能力角度定义进展 |
| 测试基础设施变更 | 自动化测试,融入开发过程,解决测试难题 |
| 拥有测试权 | 开发与测试共同负责,确保人人可用测试工具 |
| 为可测试性定义工作 | 使用用户故事和验收标准,明确工作目标和结果 |

总之,软件系统的构建和测试是一个复杂而又关键的过程。我们需要不断学习和实践,采用最佳的方法和技术,才能构建出高质量的软件系统,为企业和用户创造更大的价值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值