在 3 年前端开发中,我在成熟基建团队与小型孵化团队中都主导或深度参与过重构工作,逐步形成了一套面向不同业务阶段的渐进式重构方法论。
重构并非只发生在工程稳定期,而是贯穿软件生命周期:
- 在 MVP / 孵化阶段,重构用于控制因快速试错产生的结构性技术债;
- 在 业务扩张阶段,重构用于解除架构对业务规模与复杂度的限制;
- 在 工程成熟阶段,重构用于提升系统稳定性、研发效率和可观测性。
在前端领域,我总结下来,重构主要分为以下几种:
- 架构层重构
用解耦、分层、集中式管理的思想解决组件间强依赖、状态失控、职责混乱问题。
比如我做过的widget重构,在MVP版本阶段为了快速验证功能,牺牲了架构设计换取速度,积累了功能臃肿的widget技术债,需要将 MVP 阶段的“功能堆叠式组件”重构为可组合的 UI / 业务 / 功能三级组件模型;
在账单支付链路中,随着业务发展,对接的第三方支付渠道不断增加,原有方案的可扩展性逐渐成为瓶颈,因此需要设计一个集中式的收银台抽象,统一账单支付逻辑,提升整体扩展能力。
- 代码层
主要是根据最新的代码规范消除代码里的坏味道,比如命名风格、复杂分支、重构代码,重点控制圈复杂度和重复率,降低维护成本。
- 工程和性能优化
通过依赖升级、Tree Shaking、Code Splitting 等手段,优化构建产物体积与加载性能,以及清理过期 API 与工程债务。
- UI UX表现层
配合产品定位变化,对视觉与交互体系进行系统性重构。
所以什么时候要重构呢?
重构不是为了重构,是由痛点驱动的,痛点的触发信号包括以下几种:
- 代码僵化:改一处动全身
- 脆弱性:改一处bug确在看似无关的地方引发了两个Bug
- 重复性:逻辑散落在各处,每次更新都得全部维护
- 环境依赖:代码与特定环境强依赖,比如微前端的基座和子应用,无法独立运行
当系统出现这些特征的时候,就需要评估重构的必要性。
重构之前要做什么?
首先是梳理背景,包含业务逻辑和现有的代码实现,这两者不一定是一致的,所以还需要和产品和代码维护人协作沟通,还原唯一的source of truth.
对齐目标。目标不是空泛的提高开发体验,提高代码可维护性和稳定性,而是要显性的、可验证的指标。比如我之前做的widget重构,上级的要求是提高widget的灵活性,作为开发,得进一步定义什么是灵活性,就我这个项目来讲,我把灵活性定义为功能上的灵活性和样式配置上的灵活性。如果重构目标的是解耦某块功能,那目标得具体到实现什么层和什么层的解耦,代码质量指标比如圈复杂度、重复率。如果是工程和性能重构,需要给出性能指标,比如加载时间、包体积。
一旦理清了背景,对齐了目标,下面就是开始重构了。
重构就像解题,原则是执行统一规范、合理抽象层级、关注点分离和单一职责、控制反转和单一事实来源。
重构项目的影响面一般很大,所以如何安全进行落地呢?
答案是渐进式重构,不要试图一次性推翻重写,而是新旧代码并存,将流量和功能逐步迁移,最后将移除旧逻辑完整重构闭环。
我在 Widget 重构中,所有新的 Widget 都是重新设计和开发的,并明确划分为三种类型:纯 UI 组件、小业务组件和完整功能组件。通过不同粒度组件的组合,提高业务实现的灵活性,以适配不同租户的多样化需求。
如果资源充分,完整的单元测试也是很有效的落地手段,确保重构不破坏原有功能。
开发好后,就是移交测试验证。
在移交测试前,开发必须准备好以下材料:
- 影响面评估文档
- 改动方式说明
测试人员会根据这两份文档评估测试策略,比如进行端到端测试、回归测试、A/B测试。
在发布策略上,重构后的功能通常采用灰度发布方式,比如按用户比例逐量进行发布。
在发布和重构过程中,尽可能通过配置开关实现新旧逻辑的快速切换,以便在出现问题时无需依赖发布流程即可回滚。同时,需要持续关注实时监控数据,重点观察错误率和性能指标的变化。
最后,开发发起的重构应具备明确的 Owner 意识,对重构的立项、设计、执行、测试和上线全过程负责,确保在工程和业务层面都能兜住底。