依赖地图:防止企业系统崩溃的唯一方法 | 依赖关系映射实战

企业系统崩溃常因一个没人知道的依赖关系。本文用 CrowdStrike 和 Change Healthcare 真实事故,说明为什么代码里的隐藏依赖比运行时更危险,以及如何从最怕改的模块开始画地图。

每次大崩溃都是同一个原因:有人改了个东西,但没人知道还会搞坏什么别的。

这事特别蠢。

你动生产系统之前,第一个问题就应该是:这玩意连着谁?谁靠它干活?它挂了往下传会砸到谁?

但在大多数公司,没人能回答这些问题。不是工程师笨,也不是系统烂。而是组件之间的连接从来没被系统记下来过。就算记过,也早就不准了。地图要么没有,要么是错的。

这就是依赖映射问题。它是企业工程里最老、最没解决的难题之一。现在 AI 改代码太快,系统升级太猛,第三方风险太大,这问题比任何时候都要命。

依赖映射到底指什么

先别急着说“我知道”。很多人以为依赖映射就是看看某个服务引用了哪些软件包。

差远了。

在企业里,依赖映射要搞清楚的是:哪个模块调了哪个模块,哪个程序读了哪个文件或哪张表,哪些批处理任务必须按什么顺序跑,哪些系统互相传数据、往哪个方向传,哪些第三方服务卡在关键业务路径上,还有哪些连接是写在纸面上的、哪些只存在于运行时真实行为里。

现在那些时髦的监控工具能搞定第一类。微服务架构里,服务之间的调用能实时画出来。这有用。但只解决了很小一部分问题。大公司里有攒了几十年的老系统,那才是大头。

真正难的是代码级别的结构依赖。就是那些跟运行时行为没关系、纯粹写在源代码里的关系。比如一个 COBOL 程序调用另一个子程序。一个批处理作业读上一步生成的临时文件。一个数据副本定义被四十个程序共用。数据库表里的某个字段,一个系统往里写,六个系统往外读。这些依赖不会出现在运行日志里。它们只活在代码里。你只能靠读代码才能找到。

大多数公司永远到不了这一步。但恰恰是这一步,导致了最贵的故障。

两个真实事故告诉你没人画地图会多惨

2024年7月,CrowdStrike 给全球 Windows 电脑推了个常规配置更新。这更新直接蓝屏了大约850万台机器。航空、医院、银行、电视台、急救、政府,几十个国家同时停摆。光财富500强企业的损失,保险公司估了54亿美元。

技术上,是一个内容校验文件里有逻辑错误。但系统层面上的原因是:全球关键基础设施的一大块,都带着一个内核级别的依赖,拴在同一个供应商的更新管道上。单个组件的关系大家都懂,但系统之系统的聚合依赖,没人画出来过。

同一年2月,另一场灾难。

Change Healthcare 被勒索软件攻击。这家公司处理美国医疗系统一大部分的交易。它一挂,全美的处方处理、保险资格核验、理赔处理、支付流程全崩了。一个覆盖近1000家医院的调查显示,94%报告财务受损,74%报告直接影响了病人护理。超过一半说影响很严重。

传播这么广的原因很简单:Change Healthcare 是美国医疗系统超过100项关键功能的单点依赖,每年处理150亿笔交易。受害的很多医院和机构,直到业务流程停了,才发现自己多深地依赖着它。依赖一直存在。但没人画过地图。

这两次事故,核心都是没画出来的依赖造成的故障。不是传统意义上的代码bug,也不是靠加密就能防的安全漏洞。是看不见的故障。受害组织根本没有完整的依赖关系图,所以评估不了风险,做不了预案,依赖断了也没法快速响应。

为什么企业依赖地图永远画不全

既然这么重要,为什么大家就是画不全?答案不是态度问题,是结构问题。大公司里,有好几股力量都在跟你作对。

系统是一层一层摞起来的。1995年写的一个核心应用,2004年接了个中间件,2012年包了个API层,2020年连了个云服务。每次集成当时都记了文档。但2004年的文档不可能提到2020年的云服务,因为那东西还不存在。没人会回头去更新老文档。文档永远比系统落后。

依赖是同时在多个层次上产生的。一个系统有基础设施依赖(服务器、网络、数据库),有应用依赖(服务调用、共享库、读数据文件),有流程依赖(任务调度顺序、人工审批步骤、数据推送时机),还有组织依赖(哪个团队负责哪个组件、改东西之前要找谁审批)。大部分依赖映射工作一次只盯一层,把其他的全漏了。只看服务器依赖的地图会漏掉应用层的耦合。只看服务调用的地图会漏掉批处理任务的顺序。完整的地图要跨层整合,而这事大多数公司从来不干。

没记下来的依赖会越积越多。开发赶着修bug的时候,可能会写个绕过方案,结果搞出一个隐式依赖。比如一个进程去读另一个进程正在写的文件,或者一个模块用了非官方接口去调另一个模块。这些非正式依赖在生产环境里跑得好好的。但它们从来没被记下来。架构图上看不到。等哪天有人改了底层的组件,这些没记下来的依赖就会炸,因为没人知道要去检查。

运行时依赖和代码级依赖会分叉。现在的监控工具很擅长抓生产环境里实际发生的行为。但生产行为和代码结构不是一回事。一个只在特定条件下触发的代码依赖,可能永远不会出现在运行日志里。一段三年没执行过的死代码,只要还能被激活,就依然是个真实依赖。代码分析和运行时观察回答的是不同的问题,要看清全貌,两个都得要。

画不全地图实际要花多少钱

漏掉一个依赖的直接代价,就是一次你没想到的故障。但间接代价更大,而且更难算清楚:当没人信任这张地图的时候,每次工程决策都会多出一堆摩擦。

当开发没法可靠地回答“这次改动会搞坏什么”的时候,他们要么放慢速度,每次改动前手动查一遍,要么硬上,然后等故障来了再扛着。两种都不高效。第一种造成工程瓶颈。第二种造成生产事故。两种都会拖垮组织跟上现代业务节奏的能力。

Ken Rubin 说过一句很到位的话:依赖关系在大规模敏捷流程里就是来搞死你的。这话不新鲜。新鲜的是现在的赌注变大了。企业跑的系统比以往任何时候都更互联,要求的变化速度比以往任何时候都快,第三方的依赖链条比以往任何时候都深。

技术债务会放大这个问题。每一次推迟的文档决策,每一次没记下来的集成,每一个在生产环境里跑着但哪儿都没写的非正式依赖,都在给“不知道系统到底在干嘛”这笔组织债务加码。这笔债不会自己待着不动。它会以工程降速、意外故障、以及每次现代化改造越来越高的成本等形式,持续产生利息。

三个领域里画依赖地图最划算

不是所有依赖映射工作的回报都一样高。二十五年泡在企业代码库里的经验告诉我,回报最高的投资集中在三个领域。

1、改共用组件之前
依赖映射最直接、最可量化的价值是:在动手改之前就知道爆炸半径有多大。
如果一个模块被四十个其他程序调用,那改它的接口或行为就意味着四十个潜在故障点。
如果一个数据库字段被六个系统读取,那改它的格式或语义就得协调六个团队。
没有依赖地图,工程师根本不知道自己要改的范围有多大。有了地图,他们就知道。每个改动决策的风险计算就从“猜”变成了“算”。

2、搞现代化改造或迁移之前
迁移项目里最贵的意外,来自那些不在原定范围内的依赖。一个团队承诺把计费模块迁到新平台。干到一半发现,老的计费模块会写一个文件,另外十二个进程都要读这个文件,而这十二个进程都不在原来的迁移计划里。于是项目范围扩大,时间表往后推,预算往上涨。

这个场景在几乎所有没有先做系统依赖分析的大规模迁移中都会上演。研究 consistently 显示,如果不先做依赖映射,迁移决策的结构性后果会被严重低估。

3、应付合规和审计
现在的监管框架越来越要求企业证明自己懂数据是怎么在系统里流的。
GDPR 要求记下来个人数据处理流程,能响应数据主体访问请求。
SOC 2 要求证明访问控制范围合理、敏感数据流被理解。
HIPAA 要求对受保护健康信息有文档化的防护措施。

这些要求,没有一张 reasonably 准确的依赖地图都做不到。通过 API 追踪个人数据,本质上就是一个依赖映射问题。投了依赖文档的组织,合规审计的痛苦程度远低于那些要现画地图的。

严格的依赖映射实操长什么样

大多数公司把依赖映射当项目搞。画个当前状态图,出个图,完事。
这种地图只在画完那一刻是准的,之后越来越不准,因为系统一直在变,地图没跟着变。

严格的依赖映射不是项目。它是一门本体论 ongoing 的功夫,包含三个部分:

1、发现要做到代码级别:网络层和基础设施层的依赖工具要有,但不够。对于有历史的任何企业系统,源代码里的结构依赖才是最完整、最准的真相。

代码级别的发现意味着要解析代码库里所有语言和平台上的源码,追踪每次调用、每个文件引用、每次数据元素访问,然后建一个能真实反映系统依赖图的交叉引用结构。这事不能靠手动干。需要能理解多语言环境的工具,包括 COBOL、PL/I 这些现代分析平台大多不支持的古老语言。

2、持续维护,而不是一次性快照。
一年才更新一次的依赖地图,跟十年前的市区地图差不多有用。系统天天在变。新集成在加。老组件在改。第三方服务在增或换。依赖地图要随着系统变而变,而不是单独搞个定期活动。这意味着要把依赖分析塞进开发和发布流水线里,让代码的每次改动自动更新依赖模型。

3、可视化要做到关系可导航。
依赖地图如果只是一堆原始数据结构,工程师做改动前根本没法用。地图的可视化方式要能让开发从任意组件出发,往上往下追溯依赖关系,不仅要懂谁靠谁,还要懂为什么,并且能在动手改之前模拟影响。交叉引用图,显示出哪些程序引用了哪些数据元素、哪些模块调了哪些子程序、哪些流程喂给哪些下游任务,这才是依赖知识变成工程决策的实操界面。

跟 AI 写代码的关系

还有一个维度越来越急:就是 AI 编码工具。

AI 辅助开发正在加速企业代码库的变动速度。用 Copilot、Claude Code、Amazon Q 的工程师比以往任何时候都能更快地写代码。生产力提升是真的。但当代码生成速度跑赢理解代码连接关系的速度时,风险曲线就变了。

一个帮开发写新集成到老系统的 AI 工具,不知道它正在写的那个数据字段也被其他六个进程在读。不知道它调的那个模块有一个2017年加进来的副作用,当时是为了补偿下游某个系统的问题,而那个问题后来已经修了。不知道代码里那个关于时机的假设,会在三个月后数据量过阈值时跟夜里批处理窗口冲突。

所有这些知识都应该活在依赖地图里。如果不在地图里,AI 辅助开发就会生成技术上正确、但操作上会出事的行为,而且生成速度比以前快得多。

能兑现 AI 辅助开发全部价值的组织,是那些先投钱画依赖地图的。不是给 AI 设限,而是让 AI 用得可靠。AI 可以写代码。但依赖地图告诉 AI,以及审查它输出的人,这代码能不能安全上线。

现在就开始干

任何想补这个窟窿的组织,起点不是选工具。而是诚实地盘点一下,你到底真的知道系统的什么。

值得问的几个问题很简单:你们现在的工程团队,在改动之前会信任并查阅依赖模型的系统,有几个?对那些没有的,你们最老的那个从来没人正经记过依赖的组件是什么?今天你们最不敢改的三个东西是什么,就因为不知道它们连着什么?

这些问题的答案,会告诉你哪里最急着画地图,哪里不画的代价最高。就从那里开始。别搞什么公司级的大项目,就从漏掉依赖会赔最惨的那个具体系统入手。

然后慢慢往外扩。

第一张地图会引出第二组问题;第二组问题会指出下一块工作。组织会一点点地看清自己一直运行着、但从未真正见过的那个东西。

这活儿不 多高深;它不发布新功能,也不体现在迭代速度图表上。但它是“能安全改动”和“只能靠几个老员工脑袋里记着地图才能维持”之间的分界线。

等那几个人走了,地图也跟着走了。