从一次复杂业务重构中,我重新认识了技术探索的价值

编译通过了吗
2025-06-19 15:08
阅读 524

开篇:技术探索不是“玩花样”,而是解决真问题的底气

开篇:技术探索不是“玩花样”,而是解决真问题的底气

写这篇文章的时候,窗外的北京刚下完一场雨。空气里有股凉意,手机电量提醒也亮了起来。这让我想起几个月前那个项目上线的深夜,团队成员几乎都是在公司通宵过的夜。

那是我们一个老项目的重构任务——一个运行超过五年的核心功能模块。原本只是想做一次常规优化,结果随着深入分析,发现底层架构已经严重不适应当前的业务需求。于是我们决定大刀阔斧地进行重构。这个决策本身就很冒险,但最终不仅稳定上线,性能还提升了 60% 以上。

这次经历让我对“技术探索”这个词有了更深的理解。

很多人一听到技术探索,就觉得是搞点新框架、学些前沿概念。其实不然。真正的技术探索,是面对现实中的具体问题时,敢于跳出固有思维,去尝试更合适的解决方案,并承担其中的风险与不确定性。

而我想分享的就是这样一个真实的故事,以及在这过程中我的一些思考和成长。


问题描述:一个“卡脖子”的核心模块

问题描述:一个“卡脖子”的核心模块

我们的产品是一个金融类 App,其中一个核心模块是用户的账单详情页。页面结构看似简单:展示账单明细、分类统计、趋势图等信息。但在过去五年中,它经历了多次迭代、多人维护、各种临时方案叠加,逐渐变成了一块难啃的“骨头”。

当时的痛点包括:

  • 数据加载慢:首次进入页面要加载多项数据源,用户常遇到白屏或闪现
  • 逻辑耦合严重:一个 ViewModel 几乎承载了所有业务逻辑,动一处可能牵连全盘
  • 难以扩展:新增图表类型、增加过滤条件等功能都需要大量改动
  • 测试覆盖率低:几乎没有单元测试覆盖,回归成本极高

而且最要命的是——这个页面是整个 App 的流量入口之一,不能停服也不能灰度发布。任何改动都必须确保万无一失。


解决方案:不是为了新技术而重构,而是为了更好的未来

解决方案:不是为了新技术而重构,而是为了更好的未来

技术选型的权衡过程

在确定要做重构之前,我们开了好几轮会议。当时摆在面前的技术选项有不少:

  1. 继续使用 UIKit + MVC 架构:熟悉、可控,但显然没有解决根本问题
  2. 引入 SwiftUI:响应式 UI 很诱人,但考虑到兼容性、学习成本,加上需要支持 iOS 13 及以下版本,最终放弃
  3. 采用 MVVM + Coordinator 模式重构:这是相对保守但见效快的方向,能明显降低耦合程度
  4. 引入 Combine 或 RxSwift 等响应式框架:提升开发体验,但也增加了调试难度和团队协作门槛

系统架构设计-1

综合评估后,我们选择了第3种方案:基于 MVVM + Coordinator 的架构模式进行重构。虽然听起来有点“传统”,但它是当下最适合团队现状和业务节奏的选择。

同时,我们也做了几个关键设计决策:

1. 分层解耦:真正意义上的职责划分

我们将原来的 ViewController 中的数据处理、网络请求、事件流转全部剥离出来。ViewModel 不再持有视图引用,只负责数据转换;Coordinator 负责路由跳转,不再混杂在业务逻辑中。

class BillDetailCoordinator: Coordinator {
    func navigateToChart(filterType: ChartFilterType) {
        let chartVC = ChartViewController(viewModel: ChartViewModel(filterType))
        navigationController.pushViewController(chartVC, animated: true)
    }
}

技术概念图解-2

这样的分层让代码清晰了不少。每个人都知道应该去哪改什么,谁也不用再对着一堆 @objcSelector 干瞪眼。

2. 数据流标准化:定义统一的数据结构和接口

我们为数据源抽象出了标准的协议:

protocol BillDataSource {
    func loadBillSummary(completion: @escaping (Result<Summary, Error>) -> Void)
    func loadTransactions(completion: @escaping (Result<[Transaction], Error>) -> Void)
}

这样带来的好处是,不管是本地缓存还是远程拉取,对外暴露的接口是一致的,极大提高了可测性和灵活性。

3. 增量重构 + 功能开关控制(Feature Toggle)

为了避免一次性全面重构带来的风险,我们采用了增量重构的方式:

  • 第一天先拆出 Summary 相关模块
  • 第二天替换 Transaction 列表的实现
  • 同时保留旧逻辑作为 fallback 机制

此外,我们还使用了一个简单的 feature toggle 控制器来控制新旧逻辑切换,万一出现问题可以秒级回滚。

if FeatureFlags.isNewBillDetailEnabled {
    presentNewUI()
} else {
    presentLegacyUI()
}

这套机制在后续几次上线中救了我们不止一次。


效果总结:重构之后的变化

重构上线后,我们观察了以下几个指标:

指标 改造前 改造后 提升幅度
页面首屏加载时间 900ms - 1200ms 450ms - 600ms ✅ 平均提升约 55%
逻辑修改所需平均开发时长 2人日 0.5人日 ✅ 缩短至1/4
回归 Bug 数量 上线后平均 3~5 个 上线后 0~1 个 ✅ 稳定性显著提升
新功能接入速度 首次需一周 最快可当天完成 ✅ 扩展性大幅提升

更重要的是,我们通过这次重构,建立起了一套规范的开发流程,也为其他模块的演进提供了模板和参考。


经验分享:技术探索不是为了炫技,而是解决问题

结合这几年的工作经验,特别是这一次项目重构的经历,我想给正在面临类似问题的朋友几点建议:

1. 不要为了新技术而拥抱新技术

我曾经也非常热衷于把项目改成各种“时髦”的技术栈,比如强制全项目上 SwiftUI,或者非要引入某个复杂的函数响应式库。结果往往是前期投入巨大,后期维护困难。

记住一句话:合适的技术 > 最新的技术

技术选型从来不是一个人的英雄主义表演,而是团队协同、可维护性、学习成本、产品节奏的综合权衡。

2. 重构一定要有目标感和阶段性成果

很多重构之所以失败,是因为一开始就追求完美主义,恨不得一口吃成胖子。

正确的做法是:小步快跑,持续交付价值。哪怕只是一个组件、一个接口的规范化,只要能让后续开发变得更轻松,那就是值得的。

3. 学会“讲故事”,让非技术人员也能理解你的技术选择

有时候你在工程层面做出的改进,在产品经理眼里就是“没变化”。这时候你需要讲清楚背后的意义,比如“现在我们可以更快地上新功能”,或者“这次改动会避免未来出现重大故障”。

技术沟通的本质,其实是建立信任

4. 保持开放心态,多听听别人的想法

即使是经验丰富的工程师,也不是永远正确。在那次重构中,我曾坚持某些细节不该妥协,但后来发现年轻同事提出的替代方案反而更优雅、更轻量。

团队的成长来自于每个人的输入,而不是一个人说了算。


尾声:技术人的路,走得越久越敬畏

如今再回想那次重构,我依然觉得它是我职业生涯中很重要的一次实践。不是因为它带来了多么高深的技术突破,而是它让我更加明白:技术探索的核心,不是炫技,而是解决问题的能力

我们每天都在跟设备打交道,跟代码对话。但我们真正的对手,其实是不断变化的业务需求、日益复杂的系统环境,还有——我们自己有限的认知边界。

所以,我想说,作为一名开发者,最重要的是:

别怕犯错,也不要急于求成。技术的精进,是一场耐力赛,而不是百米冲刺。

希望这篇分享,能带给你一点点启发,也希望我们都能成为更冷静、更有判断力的技术人。

如果某一天你也面对一个“该不该重构”的抉择时刻,请记得问问自己:

“这件事,是在为未来铺路,还是仅仅为了解决眼前问题?”

共勉。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝