团队接手了一个计费模块,但没人完全理解它。这个模块没有任何测试来保护其现有行为。团队提议用一个迭代周期来“清理”它,计划是用新的结构重写核心代码。但没人能保证新版本仍然能正确地向客户收费。
这是一个示例性场景,并非已记录的事件。它描述了重构培训项目需要弥合的差距:工程师们虽然能够看出代码混乱,但却无法制定切实可行的改进方案,也无法证明改进后的代码行为没有改变。
本指南面向工程赋能负责人和工程经理。内容涵盖如何描述性能问题、诊断差距、设计准备和练习、案例分析以及评估技能是否能迁移到实际工作中。它侧重于培训设计。您项目中的代码、测试和规则应由您所在技术的高级工程师进行验证。
什么是重构培训项目?
重构培训项目是对遗留代码进行结构化的工作,其目的是为了提升能力并改进代码。学员会规划一个规模较小、界限清晰的变更,通过测试来保护现有行为,逐步改进设计,并提供证据证明变更并未破坏任何现有功能。代码质量会得到提升,更重要的是,工程师们可以借此机会练习在实际处理技术债务时所需的判断能力。
要闻速览
| 问题 | 简答 |
|---|---|
| 任务是什么? | 制定并验证有界的遗留代码改进方案。 |
| 你得了多少分? | 风险分析,以及现有行为得以保留的证据。 |
| 大幅度重写是一个好的培训项目吗? | 通常不会。它会掩盖正在练习的技能,并使保留下来的行为难以展现。 |
| 一个关于重构模式的测试就足够了吗? | 不。它确认了前提条件,但不能证明工程师是否能够规划和验证变更。 |
| 谁来审核内容? | 一位工程经理和一位了解代码库的高级工程师。 |
| 哪些问题是训练解决不了的? | 缺少测试工具、释放压力、所有权不明确,且没有时间进行维护工作。 |
| 你怎么知道它奏效了? | 一个全新的、从未见过的遗留代码案例,根据既定标准进行评分,并跟进实际工作情况。 |
1. 描述性能问题
首先,任务是:规划并验证一个有界的遗留代码改进方案。“有界”是关键。学习者选择一个足够小的改动方案,以便能够完成,并且能够明确哪些改动属于改进范围,哪些属于范围之外。
准确使用术语很有帮助。Martin Fowler 将重构描述为: 一种用于改进现有代码库设计的受控技术它由一系列小的、保持行为不变的转换组成。“保持行为不变”正是重构与重写的区别所在,也是培训必须阐明的关键所在。技术债务的比喻本身 这个词是由沃德·坎宁安创造的。福勒的讨论也提醒我们,债务可以谨慎而有意识地承担,因此并非每个混乱的模块都是需要纠正的错误。
Michael Feathers 关于遗留代码的书在实践方面也持相同观点。该书出版商的描述称,它教开发人员编写能够确保代码质量的测试。 他们并非无意中改变了应用程序。并且能够在不完全重写的情况下控制现有软件。
用一句话写出性能说明,并让工程经理检查一下:“给定一个遗留模块和一个已定义的目标,工程师提出一个有界变更,添加测试来确定当前行为,分小步进行变更,并证明行为得以保留。”
2. 诊断学习和情境差距
在着手构建任何内容之前,请将所需任务与你当前活动中练习和评估的内容进行比较。通常,有三个问题可以区分培训差距和其他问题:
- 目前的做法是否使用了实际任务? 如果培训内容只是在幻灯片中讲解重构模式,但没有人真正修改过未经测试的代码,那么就没有人实践过保护代码的行为。如果考核方式是针对代码异味的单项选择题,那么它衡量的只是记忆力。
- 认知需求是什么? 在布鲁姆修订后的认知目标分类法中,判断一项变更是否安全属于分析和评价层级,而设计计划和测试则属于创造层级。我们的指南中涵盖了如何将活动与这些层级相匹配。 将学习活动与布鲁姆分类法相匹配.
- 除了技能之外,还有其他因素阻碍了你吗? 检查人员配备、工具和流程。如果构建耗时一小时,就不会有人经常进行测试。如果维护工作从未安排,工程师只会偷偷进行重构。将非培训原因报告给能够解决问题的人员。
3. 设计有目的的准备和练习
一旦你了解培训可以弥补哪些差距,就给每个阶段分配一个明确的任务。
准备。 通过简短的诊断来检查前提条件:测试框架的工作原理、特征分析测试的定义,以及团队如何进行审查和合并。自主学习适合此阶段。回顾性检查仅用于确认前提条件。
实践。 使用结构清晰、系统化的重构项目。先从一个小型、安全的示例开始,然后逐步过渡到你代码库中真实但范围有限的部分。Gilded Rose kata 是一个众所周知的入门示例。它的 README 文件由 Emily Bache 维护, 建议在修改代码之前编写测试。 并将此练习视为循序渐进的实践,通过频繁运行测试并逐步改进设计来实现。每个项目的合理步骤如下:定义目标和边界,编写测试来捕获代码的当前功能,每次只更改一点,每完成一步后运行测试,并记录所学到的知识。
反馈。 将反馈与决策联系起来,而不是与总分联系起来。“你提取了折扣逻辑,但你的测试只涵盖了正常流程,所以你不可能注意到舍入方式的变化”比“5分满分,得3分”更有用。
实时教师指导还是异步复习? 当面临模棱两可的选择时,例如是否应该停止并补上缺失的测试,还是继续进行,实时反馈就显得尤为重要。如果学习者能够将自己的计划和测试与专家标注的版本进行比较,异步复习就足够了。许多团队会采用两种方法:先进行自主学习,然后再针对疑难案例进行辅导。
4. 通过一个实际例子进行分析
举例说明。工程经理在使用前应验证案例和答案标准。
案子。 一个遗留函数负责计算订单总额,包括折扣、税费和运费规则。该函数没有经过任何测试。一个团队提议重构整个计费模块,使其更加“简洁”。
任务。 学习者解释他们将要做什么,列举他们将要收集的证据,并说明他们还需要哪些信息或支持。
第一次尝试。 “我会把模块拆分成三个服务,把逻辑迁移过去,然后在测试环境中检查数据。”这位学员选择了较大的改动,而且是后期手动检查。这样就无法判断新旧版本在处理极端情况时是否一致。
反馈并重试。 审阅者询问,对于空购物车、折扣导致总金额为负数以及四舍五入的情况,该函数目前是如何处理的。重试要求学习者将范围缩小到一种行为,并说明如何证明该行为没有改变。
一次更有力的尝试。 “我暂时不会改动模块结构。我会先测试一下当前订单总额函数针对一系列输入(包括一些特殊情况)的返回值。然后我会把折扣计算提取到一个单独的函数中,完成这一步后再运行测试,然后就停止。我会注意到运费规则存在一些我不理解的行为,在修改之前需要咨询同事。” 请注意,这个回答限定了更改范围,首先保护了现有行为,并指出了未知的部分。
解释每种回应的合理性或不足之处。 评判每项举措都应依据既定标准,而非评审者的个人偏好。第一次尝试或许指明了一个合理的长远方向,但作为计划而言并不完善,因为它缺乏行为保持的证据。更稳健的尝试则规模较小、可验证,并且坦诚面对不确定性。
5. 评估能力并制定转移计划
能力证明是学习者在处理一个之前从未接触过的全新遗留代码案例时的表现。对风险分析和行为保持情况的证据进行评分。一个简单的评分标准是每个标准采用 0 到 2 分的等级:
| 标准 | 可观察的证据 |
|---|---|
| 任务执行 | 计划并验证有界遗留代码改进,并记录该操作及其背后的证据。 |
| 推理 | 解释了限制条件、替代方案和不确定性,并检查了风险以及行为得以保留的证据。 |
| 边界 | 使用经批准的程序,并在信息或权限不足时寻求帮助。 |
评分标准:0 分表示缺失或缺乏支持,1 分表示部分缺失但存在相关遗漏,2 分表示完整且符合既定标准。请单独定义关键错误,例如在没有测试用例能够发现的情况下更改行为,以确保总分不会掩盖此类错误。本评分标准仅为建议,并非已验证的就绪标准:请与工程经理共同进行调整并试用。我们的指南 设计具有实用反馈的互动练习 展示了如何撰写与决策相关的反馈意见。
精心规划工作交接。练习结束后,给每位工程师布置一个实际的小项目,让他们与评审员一起解决,或者对最近一次导致问题出现的变更进行简短的回顾。在充分接触实际工作后,而不是在研讨会结束后立即检查工作交接情况。
互动式教学有助于
交互式格式有助于确保每个人在小组讨论前都能做出承诺。在实时会议中,主持人可以展示一段简短的旧代码片段,要求每位工程师提交他们会做的第一个更改以及如何证明其安全性,然后在讨论前公布结果。同样的提示也可以用于自主学习,以便进行准备。AhaSlides 支持交互式学习,并可在实时和自主学习之间切换。它是一个演示和学习工具,而不是用于运行或分析代码的地方,因此请在您自己的环境中运行重构。请将您计划依赖的任何特定创作、反馈或报告功能与您自己的工作流程进行核对。有关选择格式的指导,请参阅我们关于……的文章。 何时使用自适应、交互式和实时学习.
衡量发生了哪些变化
预先确定哪些指标能够证明工程师胜任这项任务。将风险分析的质量和未见过的案例中行为保持的证据与基准进行比较。明确纳入哪些人员、分母和时间节点。如果结果有所改善,在将功劳归于培训之前,检查同一时期内还有哪些其他变化,例如新的测试工具、更快的构建速度或所有权变更。
可能存在的限制
- 该进行维护保养工作了。 如果债务偿还工作从未被安排,那么受过培训的工程师仍然没有地方运用他们的技能。
- 测试工具。 如果没有可用的测试框架或快速构建方案,小步推进和频繁检查就难以持续。
- 案件承保范围。 一个历史案例展现了几种风险类型。评分并不能反映工程师的整体判断。
- 判断何时不应该重构。 有些代码最好不要改动,而是替换或弃用,而这个决定不仅仅取决于技术。
- 转让。 在模拟演练中的表现与在生产模块交付压力下的表现并不相同。
尽早将这些问题告知赞助商,并制定单独的解决方案。培训可以提升工程师的计划和验证能力,但并不能创造时间或工具。
常见问题
什么是重构培训项目?
这是对遗留代码进行结构化实践的一种方式,工程师们计划进行小的更改,通过测试保护现有行为,逐步更改设计,并证明没有任何问题发生。
完全重写代码是了解技术债务的好方法吗?
通常情况下不会。重写代码规模庞大,难以验证,而且会掩盖你想要培养的技能。而通过测试来捕捉当前行为,进行有限度的更改,则能使逻辑清晰可见。
如何评估工程师能否安全地进行重构?
提供一个新的遗留代码案例,并根据既定标准对风险分析和行为保留情况进行评分。重构模式测验仅用于确认前提条件。
您需要用于培训的示例代码库吗?
你需要一个安全的练习场所。许多团队会先从公开的练习题(kata)入手,然后再过渡到自己代码中限定的练习区域。你的工程经理应该确认这段代码是否合适。
从哪儿开始
选择代码库中一种常见的、小规模的遗留变更。编写性能说明,请工程经理验证该变更及其对应的测试用例(确保行为保持不变),并制定一个包含三个标准的评分细则(0 到 2 分制)以及一份关键错误列表。在正式推广之前,先在一小群人中进行试点。
要了解如何在您自己的团队中实时进行重构决策练习,并在之后以自定进度重复使用,请探索 AhaSlides。








