加载中...

本篇要回答的问题:架构为什么会老化?在不轻易动核心系统的前提下,老系统怎么加新功能、怎么做局部优化,又在什么时候、怎样才真正去重构核心系统?

上一讲讲文本处理范式的日常积累。本讲转向另一种日常功夫——应对架构老化。“架构的功夫全在平常”,能力提升靠一点一滴的反思打磨,不能指望突飞猛进。本讲给出一条由轻到重的路径:加新功能 → 局部优化 → 核心系统重构。

架构为什么老化

老化源于:不断加新功能时,功能实现方式逸出当初框架范围,代码散落各处,把系统绞得支离破碎。

老化的标志:添加功能越来越难、迭代效率降低、问题持续不断,解决一个问题又生出好几个新问题。

理想情况下坚持"最小化核心系统 + 多个正交周边系统"就很难老化,但现实中难以避免,常见原因:

原因 说明
工程师能力不足 以功能完成为先,不顾长期维护成本
缺乏架构评审 代码质量缺乏持续有效关注
需求理解不深 最初架构无法满足迭代发展
架构迭代不及时 大量赶时间的补丁式代码

应对老化分两个视角,先做日常高频的"局部",再谈系统性的"重构"。

老系统怎么添加新功能

把新功能定位为周边功能,少给核心系统添麻烦、能少改就少改。但这还不够——周边系统本身也应被看作独立业务系统,要尽量不依赖既有系统。

关键判断(三模块拆法):任何周边系统 B 与核心系统 A,理想结果是三个模块——AB(与 A 无关部分)A 与 B 的桥接代码(与 A 相关部分)。桥接代码虽归属 B,但应尽可能小、且尽可能独立于与核心无关的代码。这样才能保护投资:今天的投入最大保留,未来重构成本也最小。

要不要依赖公司内部基础库?辩证看:成熟度越高越值得依赖,先评估规格成熟度(实现问题靠时间解决),看规格是否符合预期、经过多少用户打磨。

实战范例(电子表格智能填充),几百万行老代码上加新功能:

步骤 做法
① 纯算法模块 输入值矩阵 + 预测个数 → 输出预测矩阵;填充方向在算法中消失(按填充方向构建矩阵,而非屏幕直观矩阵)
② 抽象核心系统两个接口 取一个区域的单元格数据;设置一个单元格的值和格式
③ 对接 Model 层包装所需接口;取区域/设单元格是通用接口,任何既有系统都易实现

思路:尽量与既有系统剥离,从独立业务视角实现,抽象对环境的依赖,最后用最少量对接代码串起来。

架构的局部优化

目标是优化某功能与核心系统的耦合关系。看似收效甚微,但能快速推动,日拱一卒坚持下来效果远超想象。两种做法:

做法 关注点 要点 / 风险
重写(局部重构) 功能本身的实现 彻底移除相关代码重写一份;必须对业务足够了解(如维护过一阵);必须清理干净老代码,不留残余
依赖优化 功能与系统的关系 做"代码搬运工":把散落代码集中,每处修改变成函数 doXXX_yyyy(XXX=功能代号,yyyy=语义命名)

doXXX_yyyy 这个"丑名字"是故意的——作为团队约定,代表"此处待重新考虑边界"(重新考虑的是核心系统的边界,不是当前功能的边界)。

关键判断:如果某处有好几个功能都加了 doXXX_yyyy,就意味着这里需要一个事件机制让它们监听;一旦做了,核心系统就更稳定、不再因加功能而改代码——这正是 OCP 所追求的。

集中代码后,有多少个 doXXX_yyyy,就有多少对系统的"伤害"(参 58 讲伤害值计算):

伤害值 判断
不大 耦合在合理范围,到此为止可接受
过多 站在该功能业务视角看依赖合理性,不合理就推动局部重构

局部重构不应盲目,应依赖基于"伤害值"的客观判断。习惯于不理解就重构很不好——认同他人是重要的能力修炼,事情优先级排列对架构师是第一位的。

核心系统的重构

积弊已久的系统整体重构非常艰难。一上来就重构核心系统风险太高:牵一发动全身、无法保证交付周期,且没人对全局足够了解、过于盲目。正确顺序是先把周边理顺,最后动核心。

确定要重构核心系统,最高优先级是确定它的边界(使用界面/接口)。周边对核心的依赖无非两类:① 核心的功能(DOM 接口);② 核心提供的事件。步骤:

步骤 内容 难度
① 整理事件集合 对所有周边做依赖优化,初步确定核心需暴露的事件
② 实现依赖 → 接口依赖 把周边对核心的依赖全调整为依赖接口(不搬代码,把周边独立出去);此时即便接口不合理,也代表了当前模块边界,理论上可 mock 核心对接
③ 重新设计 DOM 接口 最重要时刻,审视并精炼接口

第③步两个难点:

  • 业务理解要有长足进步:新接口要更精炼、更贴近业务本质,而非换汤不换药,否则要质疑重构必要性。
  • 对周边切换成本有充足预计:从老接口过渡到新接口;虽可让核心同时维护两套 DOM 接口,但过渡期不能太长,否则让人困惑。

完成接口改造后,核心系统与每个周边系统彻底独立、可单独调优。这时"嫌核心太糟就重写"也很轻松——因为要做的事很收敛、不影响大局。而那些边界分解不清的系统,改核心系统的代码?不要命了么?

总结

应对架构老化要"功夫在平常",按由轻到重三步走:加新功能(拆成 A / B / 桥接三模块)→ 局部优化(重写 or 依赖优化,用 doXXX_yyyy + 伤害值客观判断)→ 核心系统重构(先定边界与事件、再实现转接口、最后精炼 DOM 接口)。重构比做全新架构更难,是架构设计 + 资源调度 + 阶段规划 + 韧性毅力的庞大工程。

先把"是什么"回答清楚

概念 一句话说明
架构老化 功能逸出框架、代码散落,导致加功能越来越难
三模块拆法 A、B(无关部分)、A-B 桥接代码,桥接要小要独立
依赖优化 把散落代码集中成 doXXX_yyyy 函数,理清耦合
伤害值 ∑log2(修改行数+1),处数越多伤害越大
核心重构 先定边界/事件,再实现转接口,最后精炼 DOM 接口

一句话速记

应对老化不靠一次性大重构,而靠平常:加功能拆成"核心+周边+小桥接",局部优化用 doXXX_yyyy 集中代码量化伤害值,等周边都理顺了再精炼核心接口——重构要润物细无声。

几条值得记住的判断

  • 桥接代码要尽可能小且独立,这是保护投资、降低未来重构成本的关键。
  • 同处多个 doXXX_yyyy = 需要一个事件机制,这正是 OCP。
  • 重构不能盲目,要靠伤害值客观判断;认同他人、排好优先级是架构师本分。

思考题

打开你手上一个"老化"的模块:把它对核心系统的每处侵入都改写成 doXXX_yyyy 形式后数一数,伤害值是多少?其中是否存在多个功能挤在同一处、其实在呼唤一个事件机制的信号?

公告栏
这是我的个人知识库。
记录技术,也记录生活 —— 读过的、试过的、想明白的,都堆在这儿。
最新文章
网站资讯
文章数目 :
5
已运行时间 :
本站总字数 :
15.7k
本站访客数 :
本站总访问量 :
最后更新时间 :
全局知识图谱
当前页面 已访问 文章 标签
ESC 关闭 · 滚轮缩放 · 拖拽移动 · Ctrl+G 开关