
编译完美无缺,却依然搞坏了账本:一次 COBOL 迁移的教训
代码是完美的。而这正是整个问题所在。
一个电汇程序已经从 COBOL 翻译成了 Java。它能编译。单元测试通过了。它闯过了我们为捕捉错误而搭建的每一道关卡。然后,在用户验收测试中,第一笔交易就触发了数据库的一致性检查,整个系统随之崩溃。
这场事后剖析花的时间比它本应花的更长,因为 Java 里没有任何东西看起来有问题。罪魁祸首是一个名为TRN-LIMIT的变量。翻译工具把它读作一个普通数字,并赋予了它标准的整数类型。但TRN-LIMIT从未在工具所查看的位置被定义。它声明在一个 copybook(一种共享的头文件)中——在执行链中被数千行之前引入——而那个 copybook 带有一个REDEFINES子句:这是一种 COBOL 结构,它允许同一块内存槽根据在完全另一处设置的标志,被读取为两种完全不同的数据类型。在大型机上,那个地址存放的是一个压缩十进制数。新的 Java 代码把损坏的二进制数据写入了数据库列,账本的引用完整性随之崩塌。
代码在语法上无懈可击。故障出在上下文。工具遗漏了一个存在于其视野之外的依赖关系——而在遗留 COBOL 现代化中,钱几乎总是这样消失的。
现代化项目通常不会死在你能看到的代码上,而是死在工具看不到的代码上。
这就是我为什么不再相信更好的翻译才是答案的故事,以及我们在 Veriprajna转而构建了什么。
为什么“粘贴 COBOL,得到 Java”演示时总是效果很好?
如果你在过去两年里参加过任何大型机现代化会议,你一定听过这样的推销:粘贴你的 COBOL,拿回 Java。它很有诱惑力,因为演示总是奏效。有人放进一段整洁的 200 行程序,模型返回干净、地道的 Java,房间里的每个人都松了一口气。终于。
我也曾相信过一段时间。当我的团队第一次着手此事时,我们做了显而易见的事——我们试图让翻译更好。我们给模型喂入更多上下文,针对 COBOL 的怪癖对它们进行调优,对输出质量做基准测试。甚至还有一个专为此打造、名为 XMainframe 的微调开源模型,它在 COBOL 任务上的得分比通用代码模型高出约 30%。翻译变得更干净了,Java 也更易读了。
可它在 UAT 中仍然崩溃。一次又一次,恰恰栽在那种拖垮了那个电汇程序的隐藏依赖上。就在那个月,我意识到我们在打磨错误的东西。翻译的质量从来都不是瓶颈。能编译通过的代码是容易的部分。难的部分是工具看不见的代码。
围绕这一点的数字既残酷又一致:70% 到 80% 的大型机现代化项目未能实现其目标。不是 70% 延期——而是 70%失败。通常的诊断归咎于低估的测试或混乱的数据迁移,这些确实存在。但在几乎所有这些之下,都是我刚刚亲眼目睹的同一个根本原因:工具把代码库当作需要转换的文本,而它实际上是一套需要理解的拓扑结构。
“粘贴 COBOL,得到 Java”看不见什么

一旦你开始留意上下文盲区,就会到处都看到它。有三种模式最常把我们击垮,而它们没有一个能在翻译器盯着的源文件里被看到。
从我已经描述过的 copybook 问题说起。单个 COBOL 程序可以引用四十多个 copybook,而那些 copybook 又包含其他copybook,所以一个变量的真实定义可能位于引入链中好几层深处。基于文本的工具读取它面前的语句并推断出一个类型。它无从知道,对于一个压缩十进制字段,那个推断悄无声息地错了。
接着是算术运算。COBOL 的COMP-3压缩十进制在 Java 中没有原生的等价物。伸手去用一个double,你就把浮点舍入引入了一个搬运资金的系统。即便是BigDecimal——那个正确的工具——默认也无法与 COBOL 匹配:你必须显式地把它的舍入模式固定为HALF_EVEN,才能镜像 COBOL 的ROUNDED子句。弄错了,你每笔交易就会差一分钱。那一分钱在数百万笔交易中累积,直到几周后,一份对账报告标记出一处无人能解释的差异。
几乎所有人都会忘记的模式,才是真正会拖垮生产的那个:你的 COBOL 并不会自己运行。一个调度器——CA-7 或 TWS——编排着两千到五千个批处理作业,依赖链在其中穿插纵横。作业 A 在凌晨 1 点写入一个数据集,作业 B 在凌晨 2 点读取它。你可以完美无缺地迁移每一行 COBOL,却仍然在午夜把银行搞垮,因为没有人绘制过作业网络。生产图谱从来不在源代码里,它在 JCL 里。
在凌晨 2 点搞垮生产的那个作业,从来不是你正盯着看的那个。
这就是我所说的拓扑结构。真正运行你业务的产物是一张关系之网——程序、copybook、数据集、计划作业、DB2 表、CICS 事务——而 COBOL 源代码只是其中一条丝线。
我为什么不再信任翻译器,转而开始绘制地图

对我们而言,转折点在于认定地图就是产品。
在翻译一行代码之前,我们会为整个代码库构建一张知识图谱——每个程序、每条 copybook 边、每个 JCL 依赖、每次数据集交接、每个 DB2 触点——并解析源文件所隐藏的传递关系。当你能看到一个程序有四十多条 copybook 边,且其中一条带有一个REDEFINES,在两个模块之外,那场TRN-LIMIT灾难根本就不会发生,因为在你敲下 Java 的第一个字符之前,你就已经知道那个字段是压缩十进制了。
我想精确说明这与该领域其他厂商所兜售的东西为何不同,因为这个领域很拥挤,而且其中大多数在它们所解决的那部分上确实做得不错。
IBM 的 watsonx Code Assistant for Z 是最强劲的在位者——一个智能体式系统,配有编排、架构和代码智能体,能处理 COBOL 到 Java,甚至 PL/I 和 IMS,并且能一直深入到 copybook 层面分析 CPU 消耗。它同时也是一笔 200 万美元以上的投入,运行在 z/OS 上,并依赖 IBM 的 ADDI 工具,而这会悄悄地把你锁定在大型机上——就在这场本该把你从大型机中解放出来的迁移过程中。它不做行为等价性测试,也不绘制你的 JCL 作业网络。
接着是重塑了整个市场的那一刻。2026 年 2 月,Anthropic 为 Claude Code 发布了一份 COBOL 现代化操作手册;公告当天 IBM 股价下跌了 13.2%,3 月又跟进了一个价值 1 亿美元的合作伙伴网络。Claude Code 在发现、文档编写和阅读陌生代码方面表现出色——在早期阶段确实很有用。但它是一个通用工具。它没有内置的、用于解析传递依赖的知识图谱,也不假装能解决 JCL 调度、行为等价性,或受监管银行必须产出的审计轨迹。
微软的 Azure 迁移工厂以 Java Quarkus 为目标,并把你的目标平台锁定在 Azure 上。大型系统集成商——拥有专利转换引擎的 DXC、带 MasterCraft 的 TCS、带 Cobalt 的 Infosys、埃森哲——承接 50 万到 500 万美元以上的项目,实施的是供应商工具,而不是构建关于你自己系统的智能;埃森哲主导了澳大利亚联邦银行的核心迁移,耗资约 7.499 亿美元,历时五年。而 Micro Focus 的 Visual COBOL,常被兜售为一个起点,根本算不上现代化——它是重新托管。你的 COBOL 依旧是 COBOL,只是跑在一个新的运行时上。技术债务和人力问题,原封不动地留在你当初留下它们的地方。
这些当中每一个都做了些实实在在的事。它们当中没有一个做到的,是构建出完整的依赖拓扑——JCL、CICS、DB2、copybook,全都包括在内——率先做到,独立于任何目标平台,并把那张地图当作其他一切赖以立足的基础。
大多数厂商卖给你的是一个更好的翻译器。但翻译从来都不是失败的那部分。
无人能停下的时钟
接下来这部分,把它从一个工程问题变成了一场紧急事态。
懂这些系统的人正在离开。美国 COBOL 开发者的平均年龄在 55 岁左右。这支队伍每年大约有 10% 退休,而 85% 的大学早在 1990 年代就把 COBOL 从课程中剔除了,所以几乎没有人来接替他们。如今 60% 的机构表示,找到熟练的 COBOL 开发者是它们最大的单项现代化挑战——而在仍然懂这些技术栈的开发者中,有 58% 说他们正因此考虑辞职。
我曾亲历过一个让我念念不忘的场景:为那个真正懂得批处理窗口的人举办的退休派对。每个人都在微笑,有一块蛋糕,而在我脑海深处,有个声音在说那份知识刚刚走出了大门,而它没有被写在任何地方。知识图谱除了别的用途之外,还是一种在派对之前就捕捉那个人脑中所知的方法——让依赖地图比那些把它记在脑子里的人活得更久。
而且利害关系既不小也不抽象。仍有约 2200 亿行 COBOL 处于活跃的生产运行中。它支撑着 95% 的 ATM 交易,每天清算约 3 万亿美元。43% 的银行系统建立在它之上。美国的技术债务估计高达 1.52 万亿美元,普通企业每年因遗留系统的低效而烧掉约 3.7 亿美元,金融服务公司把 70% 到 75% 的 IT 预算仅仅用于维持老系统的运转。那些把迁移做对了的团队报告了 114% 到 225% 的回报,以及每年约 2500 万美元的节省——但这份收益只存在于一场没有失败的迁移的另一端。这是罕见的一种现代化:在其中,什么都不做才是那个昂贵的选项。
新的 AI 工具难道不会直接解决这个问题吗?
这是我被问得最多的问题,而且这问得有道理,尤其是在 Anthropic 的那份公告让这个问题看起来像是刚刚被宣告解决之后。
我的老实回答是:新工具让发现阶段快了很多,这是实实在在的进步——我自己也在用它们。但智能体式 AI 变得擅长阅读 COBOL,并不会改变真正葬送项目的那件事。Gartner 预计到 2026 年,40% 的企业应用将包含面向特定任务的 AI 智能体;如果更多的智能体全都对同一个 JCL 依赖视而不见,那么它们把代码翻译得更快也无济于事。在错误的问题上求快,只不过是更快地抵达 UAT 并在那里失败。
我被问到的另一个问题是关于监管的,也正是中型银行低估的那个。欧盟的《数字运营韧性法案》——DORA——于 2025 年 1 月生效,要求进行运营韧性和威胁导向的渗透测试,而遗留系统压根就不是为通过这些测试而设计的。FFIEC 和 OCC 的美国审查人员把老化的基础设施视为一个活生生的合规缺口,超过十年的系统,遭到入侵的概率大约要高出三倍。一场无法产出审计轨迹、无法证明新系统行为与旧系统完全一致的迁移,不是现代化——而是一份语法更好的新债务。
这就是为什么行为等价性测试与地图同样重要。这项技术描述起来很简单,做好却很难:从遗留系统捕获真实的输入和输出——一个黄金数据集——然后在新系统上重放它们,直到行为逐个边界情况地完全吻合。那些历经数十年积累起来的边界情况,往往编码着一些监管逻辑,而这些逻辑存在于别无他处——不在规格说明里,不在某个人的脑子里,只在运行中的代码里。我曾见过这个问题咬伤一家保险公司比咬伤一家银行更狠:那条只为 1998 年的一份保单批单才触发的费率规则,那项无人能解释其舍入方式、却又是每次审计都要依赖的理赔准备金计算。悄无声息地弄丢它们,你就会在监管者问起的那一天,才发现哪些是要紧的。
你先抽哪一块砖?
一旦你有了地图,它会告诉你一件任何翻译器都无法告诉你的事:从哪里开始才是安全的。
如今占主导地位的策略——理由很充分——是绞杀榕:不做一次性的大爆炸式重写,而是一次提取一项能力,让新旧并行运行,并把遗留系统保留为一个实时的回退,直到新的部件赢得了信任。但每一个推荐绞杀榕的厂商,都略过了最难的那个问题——你先绞杀哪个模块?挑一个深度耦合的,你就多绕了几步,重新制造出了大爆炸式的风险。
知识图谱直接回答了这个问题。它会浮现出耦合度最低的模块——那些入站依赖最少的模块——这样你就可以提取系统中一个真实的部件,验证方法,并在触碰危险的核心之前建立起组织层面的信心。这张地图不仅仅是防范TRN-LIMIT故障的保险,它还是排序计划。
我们把所有这些——依赖知识图谱、绞杀榕式排序、行为等价性测试框架,全都刻意独立于任何目标平台——构建进了Veriprajna 的遗留 COBOL 现代化实践,直接瞄准那些被 200 万美元起步的在位者和七位数报价的系统集成商视为太小而不屑一顾的中型银行和保险公司。
我坦诚以待的是什么
我不会假装技术能解决一切,因为我见过的代价最昂贵的失败,根本就不是技术层面的。
没有任何工具——包括我们的——能解决组织内部的认同问题,能清理多年积累的糟糕数据,或者能赢得那场说服两百名开发者改变工作方式的政治博弈。这个市场预计将从 2026 年的约 90 亿美元,增长到本十年末的两倍,恰恰是因为如此之多的支出流向了人力和组织层面,而不是编译器。而且世界上没有任何解析器,无论开源还是商业,能完美覆盖 IBM Enterprise COBOL 中的每一种结构——1985 年之前的ALTER语句,以及最深处的REDEFINES。任何告诉你并非如此的人,都是在把那个缺口卖给你。技术是必要的,但它从来都不是充分的。
但技术能够掌控的那部分,它就必须彻底掌控。迁移烧掉数百万美元却一无所获,原因很少是因为有人写了糟糕的 Java,而是因为他们翻译了一个自己从未真正绘制过的系统——转换着一张网上的一根根丝线,而那张网本身始终隐而不见,直到它撕裂的那一夜。
先绘制地图。一个比编写它的人活得更久的系统,不会宽恕一处被遗漏的依赖,而在你能看清什么与什么相连之前,这项工作没有任何一种版本是安全的。我们从一本被一个无人知晓其存在的压缩十进制字段搞垮的账本中,学到了这一点。在那些字段找到你之前,先找到它们。


