One self-hosted console to run your entire business — commerce, ERP, HRM, CRM & manufacturing

遗留业务软件的隐性风险:架构师教你不推倒重来也能完成现代化

让老旧业务系统变得危险的十大风险因素、它们带来的日常麻烦、一张简单的“可能性 × 影响”热力图,以及按功能逐步替换遗留系统的绞杀者模式。

Author

Anichur Rahaman

2 个月前10 min read1 views
遗留业务软件的隐性风险:架构师教你不推倒重来也能完成现代化

老系统很少一下子崩掉,它是一点点"拖垮"的。某张报表每个月都比上个月跑得更久;接一个新的支付方式,开发说"得几周";唯一懂库存模块的那位同事一休假,整个团队就只能干等他回来。

老板们往往早在有人说清病因之前,就已经感觉到这些症状了。我作为架构师评审一套老旧业务系统时,要做的就是把这种说不清的不安,变成一份具体的风险清单,逐项打分,再给出一条不影响业务运转的出路。这篇文章分享的正是这套方法。

你会看到:值得逐项排查的十大风险、每一项在日常工作中带来的麻烦、一张简单的风险热力图,以及一种现代化改造思路——绞杀者模式(Strangler Fig)。它不把赌注押在一次推倒重来上,而是把老系统的功能一块一块地替换掉。

"遗留系统"到底指什么

是不是遗留系统,跟年头长短无关。一套用了五年的系统,只要有测试、有文档、跑在仍受支持的软件上,依然可以很"现代";一套才两年的系统,如果没人敢动,也已经成了遗留系统。比较实用的定义是:

遗留系统,就是业务离不开它,却没法安全、快速、低成本地修改它的系统。

按这个定义,要问的不是"它用了多少年",而是"改它有多大风险,不改又有多大风险"。两条路都有代价。

十大风险

按发生可能性与影响程度绘制的十大遗留系统风险热力图
一套运行了十年的电商后台的典型热力图。下一次事故,大概率出在右上角那一格。

1. 运行环境或框架已停止维护

编程语言版本或框架一旦停止维护,安全补丁也就断了。此后每过一个月,已知漏洞和你的防护之间的差距就拉大一点。越往后升级越难,因为各种依赖库都在往前走,早就不再支持你的版本。

日常麻烦:"那个支付网关接不了,它的 SDK 要求更高版本的 PHP。"

2. 系统全靠一个人撑着

只有某一位开发或某个外包知道系统怎么运转,什么都没写下来,人一走,知识也跟着走了。论影响,这往往是最严重的风险,却也是老板们最后才意识到的。

日常麻烦:发版、修 bug,甚至改一条数据,都得等这个人有空。

3. 没有自动化测试

没有测试,每次改动都像赌博,于是团队能不改就不改。问题总是绕着打补丁,而不是从根上解决,代码一年比一年难改。

日常麻烦:"发票的四舍五入修好了,结果折扣报表又不对了。"

4. 一个没有边界的共享数据库

几百张表,应用的每个角落都在读写,有时还有外部脚本插一脚。改一个字段,就可能弄坏一个早被大家忘掉的页面。

日常麻烦:改个简单字段,光排查会影响哪里就要一整周。

5. 越欠越多的安全债

用过时方式存储的密码、写死在代码里的 API 密钥、没有双重认证的管理后台、把数据库信息直接暴露出来的报错页、登录不限制尝试次数……单看每一条都不算大事,加在一起就是一扇敞开的门。

日常麻烦:大客户发来安全调查问卷,谁都不想去填。

6. 数据孤岛,同一件事好几个版本

客户资料在网店、CRM 和一张表格里各有一份;库存数在系统里一个、仓库主管的本子上又一个。数字一旦对不上,大家就哪个都不信了。

日常麻烦:开会的时间全花在争论哪份报表才对。

7. 一碰就断的系统对接

每晚通过 FTP 传的 CSV 文件、去供应商网站抓数据的脚本、密码一过期就悄悄停摆的接口。能用的时候一切正常,一旦停了,好几天都没人发现。

日常麻烦:"快递状态从周二起就没更新过。"

8. 性能天花板

在循环里一条一条地查记录、完全不用缓存、报表动不动就全表扫描。一千个订单时相安无事,到了一百万个订单就苦不堪言。

日常麻烦:月末报表要跑一整夜,跑的时候网店也跟着变慢。

9. 合规与审计的缺口

谁改了价格、工资或库存,没有任何记录;客户要求导出或删除个人数据,系统做不到;用户同意也没有留存。在许多国家和地区,这些都是数据保护法规定的法定义务,而不是锦上添花的功能。

日常麻烦:审计员问一个问题,要花一周才能凑出答案。

10. 被供应商"绑架",受制于授权条款

一套封闭系统:数据能不能导出由供应商说了算,续费时随意涨价,甚至干脆停止产品。有时候,合同本身就是最大的风险。

日常麻烦:"我们想换系统,可就是拿不出能用的数据。"

用一个下午给风险打分

开始这件事不需要请顾问。把用系统的人和维护系统的人叫到一起,按两个维度给每项风险打 1 到 5 分:

  • 可能性:未来 12 个月内,它真正酿成事故的可能性有多大?
  • 影响:真出事了有多严重——丢订单、丢数据、惹上官司,还是损害声誉?

两项分数相乘。15 分及以上的,本季度就要解决;8 到 14 分的,放进改造路线图;8 分以下的,持续观察即可。上面那张热力图就是把这张表画成了图,也是我所知道最能说服董事会为系统改造拨款的一页 PPT。

风险可能性(1–5)影响(1–5)得分处置
运行环境已停止维护5525本季度
系统全靠一个人4520本季度
安全债4520本季度
没有自动化测试4416本季度
一碰就断的对接339路线图
被供应商绑架248路线图

表里的分数只是示例,不是标准答案。你们自己讨论出来的分数会不一样,而这场讨论本身就占了一半价值。

为什么"推倒重来"往往失败

风险一摆上桌,最诱人的答案就是:"干脆从头好好重写一遍吧。"但彻底重写失败的远比成功的多,原因几乎都能预见:

  • 新系统还在写,老系统却一直在变,目标始终在移动。
  • 藏在代码里的规则会丢。十年积累下来的特殊情况都埋在老代码里——某个税种的舍入规则、某个批发客户的专属折扣——从来没人写成文档。
  • 一年甚至更久都交付不出任何东西,用户反馈来得太晚,预算却先花光了。
  • 切换那天就是悬崖。一处出错,处处出错。

绞杀者模式:一次只换一块

绞杀榕会缠着宿主树生长,直到自己能独立站稳。软件里也是一样:新系统围着老系统生长,一项一项地接手功能,直到老核心可以彻底关掉。

绞杀者模式迁移三步走:在前面加一层路由门面、迁出一个功能模块、让老核心退役
一层路由门面让新老系统并行运转,流量按功能逐块切换过去。

第 1 步 — 在前面加一层路由门面(第 0–2 个月)

在老系统前面放一层路由——API 网关或者一个轻量代理。起初它把 100% 的流量都转给老系统。与此同时:

  • 为关键流程编写特征测试,把老系统现在的实际行为原样记录下来,不管它对还是错。
  • 在老数据库里加一个事件发件箱(Event Outbox),让每一个重要变化(订单创建、库存变动)都能可靠地送到新模块。
  • 发现一条隐藏规则,就记下一条。这份文档最终会成为公司最值钱的资料。

第 2 步 — 迁出一个功能模块(第 2–8 个月)

挑一块价值高、边界清楚的功能,比如商品与库存,或者订单。自建新模块或直接采用成熟模块,再把这部分流量路由过去。

  • 防腐层(Anti-corruption Layer)负责在新旧数据模型之间做翻译,不让老系统的各种怪癖渗进新代码。
  • 并行运行:同样的输入同时发给两套系统,比对输出,直到完全一致。
  • 功能开关(Feature Flag):每次只切一个分公司、一家门店或一批客户,并且随时可以一键退回。

第 3 步 — 让老核心退役(第 8 个月以后)

最后一块功能也迁完之后,把历史数据归档到只读存储,关掉剩下的老页面,删掉老代码。数据留下,风险送走。

重构、换平台、替换,还是直接下线?

老系统的每一部分,处理方式不必一样。三个问题就能决定每块功能该走哪条路:

决策树:不再需要的就下线;通用功能就替换;仍受支持且可测试的就重构;否则就迁到新平台
订单、库存、总账、工资这类通用功能,几乎不值得从零开发。
  • 下线已经没人用的部分。这是成本最低的现代化。
  • 替换通用功能——订单、库存、财务、工资、人事——直接用成熟模块。你的竞争优势,很少体现在一张会计分录是怎么过账的。
  • 重构属于你独有、而且仍然健康的部分:补上测试,小步升级。
  • 换平台属于你独有、却被困在已停止维护技术上的部分:在门面之后把业务规则搬到新技术栈。

真实迁移项目里学到的教训

有些经验是课本上没有、只能在项目里学到的:

  • 测试要跑在和生产相同的数据库上。又快又方便的内存测试库,可能掩盖大小写敏感搜索、严格类型比较和约束上的差异。我见过几次最糟糕的意外,测试全部通过,第一个真实请求就崩了。
  • 每个操作都要给出看得懂的提示。迁移期间光秃秃地弹出一个"500 Server Error",比缺任何功能都更伤用户信任。在服务执行之前先校验输入,把失败转换成用户知道下一步该怎么做的提示。
  • 基础数据只初始化一次,并留下记录。每次更新都重跑的初始化脚本,迟早会把某人手工改过的配置冲掉。
  • 迁移前后都要测性能。没有"之前"的数字,你就证明不了新系统更快——而总会有人跳出来说它更慢。
  • 从第一天起就留审计记录。谁在什么时候改了什么,一查便知,迁移中一半的扯皮几分钟就能平息。

StoreConsole 在改造计划中的位置

StoreConsole 由一组相互独立的模块组成——商品、库存、订单、配送、财务、人事、工资、CRM 等等——模块之间只通过事件通信。这让它天然适合"替换"这条路:先在路由门面之后接入一个模块,用老系统的发件箱给它供数,等第一个跑稳了再迁下一个。每个模块都自带操作日志、基于角色的权限和双重认证,上面列出的好几项风险,第一天就能消除。下面的短视频演示了角色权限、双重认证和审计记录。

用户与角色演示(0:47):按角色分配权限、双重认证和完整的审计记录。

你的前 30 天

  1. 第 1 周:组织一次风险研讨,画出你们自己的热力图。
  2. 第 2 周:先解决高分、低成本的问题——开启双重认证、更换泄露的密钥、实际恢复一次备份。
  3. 第 3 周:为最重要的三个业务流程写特征测试。
  4. 第 4 周:选定第一个要迁出的功能,并约定好怎么衡量成功。

要点回顾

  • 遗留系统的意思是"我们没法安全地修改它",而不是"它很旧"。
  • 按可能性和影响给十大风险打分,15 分及以上的本季度就解决。
  • 别推倒重来,用路由门面、事件发件箱和绞杀者模式逐步替换。
  • 通用功能交给成熟模块,定制代码只留给真正让你与众不同的部分。
  • 测试跑在生产同款数据库上,绝不让任何页面只甩出一个错误了事。

Anichur Rahaman 是一名软件架构师,也是 StoreConsole 的创始人。他为成长型企业设计电商与 ERP 系统,尤其关注事件驱动架构、数据准确性,以及在企业自有服务器上运行的系统。

About the Author

Anichur Rahaman

Continue Reading