背景
在软件工程中,我们经常面临一个抉择:是一次性大规模重构所有代码,还是采用小步迭代的方式逐步改进?最近在我们项目中,将多个页面的提示信息从旧的 Flash 提示机制迁移到统一的 Toast 组件的经历,给了我深刻的启发------小步重构,往往比大规模重构更稳健、更高效。
我们的实践
让我先回顾一下我们的项目改造过程,看看是如何采用小步重构策略来完成提示信息机制的统一的。
问题
我们项目中有多个管理页面,都有自己独立的提示信息显示方式:
- 有的使用传统的 flash 消息
- 有的使用内联的 status-message DOM 元素
- 有的甚至有自己编写的 toast 组件
这种不一致导致了代码重复、风格不统一,而且维护成本高。
第一步:确立公共组件
我们首先创建了一个统一的 toast 组件,放在公共资源目录中:
++++static/js/toast.js++++
++++static/css/toast.css++++
这个组件提供了统一的 showStatus(message, type) 接口,让所有页面都能使用相同的提示风格。
第二步:逐个页面迁移,每个都是独立的可验证步骤
我们没有一次性修改所有页面,而是一个页面一个页面地进行:
- ++++settings_system.html++++ - 系统参数设置
- ++++settings_review_types.html++++ - 评审类型设置
- ++++settings_checklists.html++++ - 检查清单管理
- ++++settings_benchmark.html++++ - 基准数据管理
- ++++settings_rules.html++++ - 功能点度量与评审规则
- ++++admin_add_company.html++++ - 新增公司
每个页面的修改都遵循相同的步骤:
步骤 1 :引入公共资源
<link rel="stylesheet" href="/static/css/toast.css">
<script src="/static/js/toast.js"></script>
步骤 2 :添加容器元素
<div class="toast-container" id="toastContainer"></div>
步骤 3 :删除旧代码
-
<div class="status-message" id="statusMessage"></div>
-
function showStatus(message, type) {
-
const statusEl = document.getElementById('statusMessage');
-
statusEl.textContent = message;
-
statusEl.className = 'status-message ' + type;
-
...
-
}
步骤 4 :测试并验证
每个页面修改完成后,都立即进行测试,确保功能正常,然后再进行下一个页面。
第三步:额外优化,每次都是小改进
在迁移过程中,我们还发现了一些额外的改进机会:
- ++++settings_checklists.html++++ 中的 saveAndReturn 函数有竞态条件,我们顺便修复了
- ++++admin_add_company.html++++ 我们顺便添加了实时查重功能
- 删除了没有使用的 hasUnsavedChanges 变量
这些小改进都是在迁移过程中顺便完成的,没有专门为了重构而重构。
为什么小步重构更好?
通过这次实践,我深刻体会到了小步重构的优势:
1. 风险可控
每个步骤只修改一个页面,即使出了问题,影响范围也很小,容易定位和修复。
我们修改 admin_add_company.html 时,就遇到了 AJAX 请求识别的问题:
- 前端没有发送 X-Requested-With 头
- 后端返回了 HTML 而不是 JSON
- 导致解析失败,出现 "unexpected tokens" 错误
但因为我们只修改了一个页面,很快就定位了问题并修复了。
2. 即时反馈,快速迭代
每个页面修改完成后,立即可以看到效果,获得即时反馈。如果发现问题,可以及时调整策略。
比如在第一个页面修改完成后,我们发现 toast 组件的图标显示有问题(会重复显示两个图标),我们立即修复了 ++++toast.js++++,后面的页面都受益于这个修复。
3. 学习和优化的机会
在逐步修改过程中,我们对问题的理解会不断深入,后面的修改往往比前面更完善。
比如第一个页面我们只是简单替换,后来发现可以顺便删除无用代码、修复小 bug,甚至添加新功能(如实时查重)。
4. 不影响正常开发
小步重构可以和正常开发并行进行,不会因为大规模重构而阻塞开发进度。我们是在日常工作中,逐个页面修改,没有专门停止开发来做重构。
5. 更容易说服团队
小规模的改动更容易获得团队的认可和支持。如果一开始就提出"重构所有提示信息",可能会因为改动太大而被搁置;但如果说"我们先改一个页面看看效果",往往更容易推进。
大规模重构的风险
相比之下,大规模重构往往面临更多风险:
1. 风险不可控
一次性修改大量代码,一旦出问题,很难定位是哪里的问题。
2. 时间和精力投入大
大规模重构需要投入大量时间和精力,而且往往不能立即看到价值。
3. 容易引入新问题
改动越大,引入新 bug 的概率越高。
4. 容易半途而废
大规模重构往往因为各种原因(时间、资源、新需求等)而半途而废,留下"半吊子"的代码。
小步重构的原则
基于我们的实践,我总结了几个小步重构的原则:
1. 确立目标,但不要过度规划
先确定一个清晰的目标(比如"统一提示信息机制"),但不要一开始就把所有细节都规划好。在实施过程中,我们会发现很多当初没有想到的细节。
2. 每次只改一点
每次只修改一个小部分,确保每个修改都是可验证、可回滚的。
3. 立即测试验证
每次修改完成后,立即测试,确保没有引入新问题。
4. 随时可以停下来
小步重构的好处是,你随时可以停下来,哪怕只完成了一半,也不会留下不可收拾的烂摊子。
5. 边做边学,持续优化
在实施过程中不断学习和调整,后面的修改会比前面更好。
总结
这次从 Flash 提示到 Toast 组件的迁移,让我深刻认识到:重构不是一蹴而就的革命,而是持续改进的演化过程。小步重构,虽然看起来慢,但实际上更稳健、更高效,最终的结果也更好。