与买桂花同载酒 🌙

共享代码库引发的编译错误排查

共享代码库引发的编译错误排查

一个故事

团队里多个产品共用一套 BeanUI 代码库,就好比几家人共用一间厨房。某天,产品 A 的开发者在自己的 ScreenLoader.cs 里用了厨房里的”老王牌炒锅”(一个叫 XXXViewModel 的类),用得好好的,编译也通过。

过了段时间,产品 B 的开发者来厨房大扫除——把”老王牌炒锅”扔了,换了个”新款炒锅”(YYYViewModel)。他把自己家(产品 B)的菜谱都更新了,用新锅炒菜,编译通过,皆大欢喜。但他不知道产品 A 的菜谱上还写着”用老王牌炒锅”。

又过了一段时间,产品 A 合并了别人的代码,突然编译报错:找不到 XXXViewModel。产品 A 的开发者一脸懵——我的 ScreenLoader.cs 很久没改过了啊,怎么突然编译不过了?

到底发生了什么

这类问题的本质很简单:另一个产品改了共享代码库 BeanUI,改完合并到主干,你的产品就编译不过了。

从 Git 历史上看,报错文件的最后一次改动是很久以前的提交,当时编译没问题。出问题是因为另一个产品的开发者在 BeanUI 里删除或重命名了一个类,更新了自己的调用方,但没管你的产品。等这个改动合并到主干,你的代码就找不到那个类了。

这种情况有个迷惑性:你改的代码没问题,问题出在别人动了你们共同依赖的基础设施。

怎么排查

遇到”以前能编译现在不行,但我的文件没改过”这种情况,思路很简单:

先在整个仓库搜索报错的那个类名,看它定义在哪里。如果搜不到定义,说明它已经被删了。然后用 git log --all --oneline --diff-filter=D -- "**/类名*" 找到是哪个提交删的。接着确认你的项目是否引用了共享代码库(检查 .csproj 中的 ProjectReference)。最后用 git log --oneline --ancestry-path 把删除提交和报错提交之间的历史串起来,就能还原完整的时间线。修复时参考那个删除操作的提交——看它怎么改的,照着同步更新就行了。

怎么预防

最有效的办法就一句话:改共享代码的时候,grep 整个仓库,确认所有用到的地方都更新了。不要只看自己负责的产品目录。

从流程上讲,CI 流水线应该编译整个解决方案而不是单个项目,这样即使开发者本地漏了,CI 也能拦住。代码评审时,如果看到共享代码库中有类被删除或重命名,reviewer 应该主动检查一下有没有其他产品在用。

几点体会

  • Git blame 只能告诉你这行代码谁写的,不能告诉你这行代码为什么编译不过。 编译依赖的是整个代码库的状态,不是单个文件的历史。
  • “当时能编译”不代表”永远能编译”。 代码没变,但共享依赖被别人改了,这是共用代码库架构特有的风险。
  • 共享代码库是隐性耦合的高风险区。 各产品的调用方散落在各自的目录里,改共享代码时很难一眼看到全貌,全靠开发者自觉地全局搜索。