Skip to the content.

设计取舍

这份文档说明能力边界以及为什么不做得更多。静态分析无法在一般情况下证明 跨模块行为是否变化,如实标注边界比假装完备更有用。

为什么只扫描其他程序

这是产品定义,不是技术限制。

一个工具要回答”我这次改动会影响谁”,如果同时报告自身影响,会出现两个问题:

  1. 噪音淹没信号:仓库内部的调用方动辄上百,真正需要跨团队协调的只有几条
  2. 责任边界模糊:自身影响由改代码的人自己就能看到(IDE 会提示),跨程序影响才是盲区

所以引擎不对自身索引做传播,报告里的模块地图、盲区与计数也全部来自对方程序。

已知边界

场景 现状 为什么
多态 / 接口调用 记录声明方法 + 已知实现的分派边,置信度较低 完整的分派分析需要全程序指针分析,成本远超收益
Spring 依赖注入 按字段/构造器类型解析,不还原 Bean 装配图 装配图在运行期才确定,且可被条件注解改变
反射 / 动态代理 / 代码生成 无法解析,进入盲区清单 静态不可判定
Feign / RestTemplate / OpenAPI 按路径模板匹配,动态拼接的 URL 可能漏报 拼接值在运行期才知道
动态 SQL(<if> 拼接) 解析静态部分,动态部分进入盲区 同上
SELECT * / 列名无法解析 不命中字段级数据库契约,计数并标注「字段盲区」 列清单由运行期表结构决定,静态拿不到
数据库身份 从 JDBC URL / 显式 schema 推断;未知时保留匹配但降低置信度 不连接数据库,也不假设同名表就是同一张表
值语义(如 status 1 → 2) 写入列集合不变时不产生数据库 delta 需要比较赋值表达式与业务契约,首版未做
事务 / 锁 / 提交时机 不分析 需要事务边界解析与并发测试,静态无法证明
配置中心(Nacos/Apollo) 只分析仓库内配置与代码引用 外部配置不在代码里
框架入口(Controller/Listener/定时任务) 由容器调用,仓库内没有静态调用方;单独计数并说明 这不是遗漏,是事实
消息中间件 支持 Spring Kafka / Spring AMQP / RocketMQ;不读取 Broker 真实消息 读 Broker 需要连接生产环境
动态消息目标 Topic/Queue/RoutingKey/Tag 来自运行期参数时进入盲区 不猜测具体值
消息 Schema 支持 JSON DTO 及 Avro/Protobuf 文件;不拉取 Schema Registry 首版范围
Kafka Streams / Spring Cloud Stream 不在范围内 拓扑 DSL 是另一套语义
首次提交(无父提交) 基线为空,所有符号算新增;报告明确标注 没有可比对象

为什么这些取舍是合理的

静态分析的定位

静态分析不能证明“改动无影响”,只能提供”有影响的证据”。 所以本工具的设计目标是:

反过来,追求”精确无噪音”会让工具变成”什么都没发现”,反而更危险。

为什么置信度阈值是 0.15

低于这个值的路径通常已经衰减了 6 层以上,链接可靠度不到 20%。 再往下传,路径长度爆炸但信息量趋近于零。

为什么不自动修复

工具给出的是判断依据,不是补丁。跨程序影响的处置需要业务判断: 这个接口改动是否要通知对方团队?是否要保留兼容层?这些不是静态分析能回答的。

如果要扩展

几个自然的扩展方向,以及各自的代价:

方向 代价
跨仓库合并索引 需要处理同名类冲突,且要持续同步多个仓库的版本
运行时链路数据接入 需要部署探针,但能显著提升置信度
Schema Registry 集成 需要网络访问与凭据管理
增量索引 需要处理缓存失效,收益在大仓库才明显

当前实现选择”每次从快照重建索引”,牺牲一点速度换取”索引永远和代码一致”—— 这个取舍在小到中型仓库上是划算的。