多处使用重复代码是抽出来好还是先不管
重复代码是日常开发里最常见的一种“坏味道”,但要不要立刻抽出来,很多开发者在不同阶段会有不同的判断。有人觉得看到重复就想重构,有人则主张先保证功能上线再说。两种做法都有道理,但真正合适的时机往往取决于重复的程度、代码的稳定性以及项目当前所处的阶段。
先区分重复的类型:结构性重复与偶然相似
表面相近的代码不一定是真正的重复。如果两段代码逻辑上做的事情本质相同,只是参数或初始状态不同,那属于结构性重复,适合抽取。比如订单校验、用户权限判断这类固定流程,散落多处时既增加维护成本,也容易因为某处遗漏修改而产生不一致。
但另一种情况是两段代码只是长得像,实际上分属不同的业务场景,未来可能各自朝着不同方向演化。这时强行合并反而会引入多余的抽象,让调用方为了迁就公共逻辑不得不增加判断分支。遇到这种情形,先保留重复反倒更安全。
在什么阶段适合抽取,什么阶段适合先忍一忍
如果你正处于功能开发的中期,需求还在一轮轮调整中,那么过早抽取重复代码很可能带来返工。高频变动的逻辑被抽成一个方法后,每次调整都需要同时修改抽象和方法内部实现,改一处就要全链路回归,成本反而更高。此时比较务实的做法是保留重复,等需求稳定后再统一整理。
反过来,如果这段重复代码已经稳定运行了一段时日,改动频率很低,而且未来几乎可以确定不会有太大变化,那尽早抽取是划算的。尤其当重复出现三次以上时,直觉上会觉得应该处理,但这里的重点不是“三次”这个数字本身,而是重复是否已经形成了足够的稳定模式。稳定的重复抽出来才能真正减负,不稳定的重复抽出来只会添乱。
抽取时要克制,不要随手做出过度设计
很多人在抽取重复代码时会顺手加上参数开关、扩展点、钩子函数等等,觉得这样更灵活。但这类前瞻性设计往往是凭空猜测需求,实际没有业务支撑,结果就是抽象层越来越厚,调用链越来越长。
抽取的核心目标是减少重复、统一行为,不是制造一个万能框架。一个公共函数或组件,只要能覆盖当前真实的调用场景就够了。等将来真的出现了新差异,再通过参数或扩展去适配,那个时候的调整才是有根据的。保持简单,比盲目追求“优雅”要重要得多。
注意公共逻辑的边界与修改影响面
抽取重复代码还有一个容易踩的坑:公共逻辑被改了一处,会影响所有调用方。因此,抽取前最好确认几件事:所有调用方对这段逻辑的期望是否一致;是否有调用方之前偷偷修过内部细节,依赖了某些“不是明面上表达”的行为;这段代码如果出错,能否通过现有测试或日志快速定位到影响范围。
如果项目里没有相应的测试覆盖,抽取重复代码之前最好先把行为锁定下来,哪怕只是临时写几个断言也比裸重构稳妥。毕竟多个副本并存时,改动风险局限在某一点上;合并成公共逻辑后,一次修改就牵动全局,必要的护栏不能省。
总而言之,遇到重复代码不必有强迫症一般的重构冲动。先判断它是真正的结构性重复,还是暂时的巧合;再观察它正处于频繁变动的阶段,还是已经稳定沉淀;最后评估抽取后维护收益是否大于回归风险。大多数情况下,推荐的做法是:阶段性容忍重复,待需求稳定和模式清晰后再动手抽取。一次恰到好处的抽象,胜过一次过早过度、为了消除重复而制造的更复杂设计。