包管理即组织架构图
摘要
本文探讨了不同的包管理策略和工具如何反映组织沟通结构,通过单体仓库(monorepos)、工作区(workspaces)、Bazel、Nix、Docker等工具阐述了康威定律。
<p><a href="https://lobste.rs/s/6fmohi/package_management_as_org_chart">评论</a></p>
查看缓存全文
缓存时间: 2026/07/10 22:13
# 包管理就像组织架构图
来源:https://nesbitt.io/2026/07/10/package-management-as-org-chart.html
康威定律指出,组织产出的系统会复制其自身的沟通结构。依赖管理工具是系统的一部分。解析策略是对分歧如何解决的一种看法;清单格式则记录谁可以依赖谁。
**单一版本策略的单一代码库**:树中的每个包都必须对每个依赖的版本达成一致;升级任何东西意味着同时升级所有人。组织架构图被禁止出现在代码中。当有专门的迁移团队负责拖动所有消费者时,这种方式有效。
**带有工作区的单一代码库**:一个仓库,但每个包保留自己的清单,可以锁定自己的版本。一个强大的平台团队,以及认为协调已经在2019年外部会议解决的管理层。
**Git 子模块**:依赖项通过精确的提交 SHA 在单独的仓库中引用,更新是手动两步操作,从未自动化。两个团队同意协作,并记录到提交哈希,精确地说明他们有多不认真。
**Bazel**:构建文件中显式声明目标之间的每个依赖边;没有什么是隐式或推断的。当组织发展到没人能通过询问知道谁依赖谁时,采用 Bazel 来强制执行人类已经失去跟踪的信息。通常只有一个人能看懂,他来自 Google。
**Nix / Guix**:构建是其声明输入的纯函数;推导中未列出的内容在构建时不存在。“在我的机器上能用”这句话在结构上成了不可能,代价是大部分招聘渠道受阻。
**Maven 最近者胜调解**:当树中的两条路径需要同一工件的不同版本时,Maven 选择距离根节点跳数最少的那个,无论哪个更新或满足更多约束。通过距离顶部的接近程度解决冲突,这也是组织解决大多数分歧的方式。
**公共仓库前的 Artifactory,充满分支的私有命名空间**:每次安装都经过组织控制的代理,需要修补的包被分支进来而不是贡献回去。信任由系统而非个人授予,分支来自法律部门赢得的一场争论,此后再未重提。
**用于内部应用的 deb/rpm 包**:应用构建成操作系统包,由系统包管理器安装,发布过程与内核更新走同一道门。运维部门赢了,并一直掌控。发布是带有运行手册的事件,至少有一个人的职位包含“发布”二字。
**Docker**:应用程序自带操作系统的副本,因此部署环境就是开发者在构建时决定的任何东西。开发部门从运维部门分离,带走了操作系统,运维部门无法再拒绝包含其曾经控制的一切的制品。公司在下一次 xz 事件发生时才发现运行了多少个 Debian 副本。
**来自私有仓库的 Terraform 模块**:基础设施被打包成版本化模块,应用团队像使用任何其他依赖一样使用它们。基础设施团队构建了一个接口,以便应用团队停止呼叫他们,现在他们却因接口问题被呼叫。
**模块联邦(https://module-federation.io/)**:分别构建和部署的 JavaScript 包在运行时(浏览器中)协商共享依赖版本。团队向不同的副总裁汇报,他们不愿共享会议,因此版本解析被推迟到最后一刻,在用户的机器上,因为流水线中更早的任何环节都无法达成一致。
**peerDependencies**:包声明对其宿主必须提供的依赖的版本约束,而不提供任何满足该约束的东西。框架团队向应用团队发布政策:你将使用 React 18,我们会检查,满足约束是你的问题。
**供应商依赖**:每个依赖的源代码被复制到仓库并提交;上游可以更改或消失而不受影响。曾被上游伤害过的组织现在扣留人质;代价是永久存在于下一个冲刺中的手动合并。
**没有锁文件,全用 `latest`**:每次安装都从仓库重新解析,依赖集就是那一刻最新的东西。创始人仍然直接提交到主分支,多年前在 `npm-shrinkwrap.json` 上吃过亏,再也不碰锁文件。
**每次合并都执行 semantic-release**:版本号根据 Conventional Commits(https://www.conventionalcommits.org/)前缀计算,每次主分支变更时自动发布。发布成为提交前缀的副作用,因为成为发布者已经变成了一个负担。
**Go MVS**:将每个依赖解析为图中任何地方显式要求的最高版本,绝不更高;仅因为存在较新版本不会升级。由某位看过 SAT 求解器解析并认为问题是自己造成的人设计,它编码了一个组织,其中只有在有人以书面形式提出要求时才会发生变更。
**Brewfile**:开发环境声明为一系列 Homebrew 包,`brew bundle` 按顺序安装。入职仪式:文件在第14行失败,获得可用机器的实际机制是一个名为 `#dev-setup-help` 的 Slack 线程。
---
大多数依赖策略都是为了规避人际协商。工具并未消除分歧,只是默认选择了由谁来输。
相似文章
包管理器中的补丁与分支策略
本文探讨了在上游维护者未能解决漏洞时,针对不同语言包管理器修补和分支依赖项的策略。文章对比了系统包管理器强大的修补能力与语言注册表的局限性,并详细介绍了在各种生态系统中使用 Git 覆盖和分支等变通方法。
将现代包管理引入 Meson 的原生 wrap 生态系统
Collider 扩展了 Meson 的原生 wrap 生态系统,提供现代包管理功能,包括自动依赖解析、锁定文件以及发布/共享能力,完全兼容 WrapDB。
包管理器需要全局钩子
一篇博文,主张包管理器应支持全局钩子,作为当前包安全措施(如注册表或shell包装器)的更安全、更灵活的替代方案。
@LangChain: 如果你想要一个多智能体系统以便一个团队拥有一个智能体,那你实际上是在交付你的组织架构图,而不是在构建最好的产品……
关于多智能体系统与每个品牌一个智能体之间权衡的讨论,强调了组织结构如何影响产品设计。
所有包管理功能已从编译器移至构建系统
Zig将所有包管理功能从编译器移至构建系统,从而减小二进制文件大小,并简化补丁和安全检查。这一架构变化改进了构建服务器协议,并解除了ZLS集成的阻塞。