2. 依赖管理工具:Python的pip与Poetry、Node.js的npm与yarn、Java的Maven与Gradle对比
依赖管理,说白了就是管好你项目里的「第三方库」。
我见过太多团队,因为依赖版本不一致,导致「我机器上能跑,你机器上就崩」的惨案。嗯,这节我们就来聊聊主流的依赖管理工具,看看它们各自的门道。
2.1 Python:pip 与 Poetry
Python 的依赖管理,曾经是个老大难问题。pip 虽然能用,但说实话,它太「原始」了。
2.1.1 pip + requirements.txt
这是最传统的方式。你运行 pip freeze > requirements.txt,把当前环境的包列表导出来。别人拿到这个文件,再 pip install -r requirements.txt 安装。
听起来很简单对吧?但坑不少。
另外,pip 没有「锁文件」的概念。你没法保证两次安装的结果完全一致。这在生产环境里,简直是定时炸弹。
2.1.2 Poetry:现代 Python 依赖管理
Poetry 的出现,算是把 Python 带入了现代依赖管理时代。我个人习惯用 Poetry 来管理新项目。
它有几个核心文件:
pyproject.toml:声明式配置,写清楚你直接依赖了哪些包poetry.lock:锁文件,锁定所有依赖(包括间接依赖)的精确版本
举个例子,初始化项目:
poetry new my-project
cd my-project
poetry add requests
这会自动生成 pyproject.toml 和 poetry.lock。别人克隆项目后,运行 poetry install,就能得到完全一致的依赖环境。
poetry.lock 提交到 Git 仓库。这样大家的环境才能保持一致。
2.2 Node.js:npm 与 yarn
Node.js 的依赖管理,故事就更多了。npm 是官方工具,yarn 是 Facebook 后来推出的替代品。
2.2.1 npm:老牌工具
npm 使用 package.json 记录依赖,package-lock.json 作为锁文件。基本用法:
npm init -y
npm install express
npm 5 之前没有锁文件,那会儿真是「安装靠运气」。后来加了 package-lock.json,情况好多了。
但 npm 有个问题:它的依赖树是嵌套的。你装一个包,它可能把它的依赖装到 node_modules 的子目录里。这会导致同一个包被安装多次,浪费磁盘空间。
2.2.2 yarn:更快的选择
yarn 的出现,就是为了解决 npm 的痛点。它使用 yarn.lock 作为锁文件,安装速度更快,而且有离线缓存功能。
用法也很简单:
yarn init -y
yarn add express
yarn 最大的改进是「确定性安装」。同样的 yarn.lock,在任何机器上安装结果都一样。这一点,npm 后来也学去了。
核心区别:
- npm 用
package-lock.json,yarn 用yarn.lock - yarn 安装速度通常更快
- yarn 有离线缓存,断网也能装
- npm 现在也支持
npm ci命令,实现类似 yarn 的确定性安装
2.3 Java:Maven 与 Gradle
Java 世界的依赖管理,又是另一番景象。Maven 是元老,Gradle 是后起之秀。
2.3.1 Maven:约定优于配置
Maven 使用 XML 文件 pom.xml 管理依赖。它的核心理念是「约定优于配置」——你只要按它的目录结构放代码,它就能自动编译、测试、打包。
一个典型的 pom.xml 片段:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
Maven 没有锁文件,但它有「依赖仲裁」机制。如果同一个包出现多个版本,Maven 会按「最短路径优先」原则选择一个。这有时候会出问题——你明明想用 2.0 版本,结果被一个间接依赖拉到了 1.0。
2.3.2 Gradle:灵活高效
Gradle 使用 Groovy 或 Kotlin DSL 来写构建脚本,比 Maven 的 XML 灵活得多。它也有锁文件的概念,叫 gradle.lockfile。
Gradle 的依赖声明:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web:2.7.0'
testImplementation 'junit:junit:4.13.2'
}
Gradle 最大的优势是「增量构建」——只重新编译有变化的部分。大型项目里,这能省下大量时间。
2.4 工具对比总结
说了这么多,我们来个直观的对比:
| 特性 | pip | Poetry | npm | yarn | Maven | Gradle |
|---|---|---|---|---|---|---|
| 锁文件 | 无 | poetry.lock | package-lock.json | yarn.lock | 无 | gradle.lockfile |
| 配置文件 | requirements.txt | pyproject.toml | package.json | package.json | pom.xml | build.gradle |
| 依赖仲裁 | 无 | 自动解决 | 自动解决 | 自动解决 | 最短路径优先 | 最新版本优先 |
| 离线缓存 | 无 | 有 | 有 | 有 | 有 | 有 |
| 构建速度 | 慢 | 中等 | 中等 | 快 | 慢 | 快 |
2.5 我的选择建议
你想想看,选工具其实就是在选「团队协作的规范」。我个人习惯这样选:
- Python 项目: 新项目用 Poetry,老项目用 pip + requirements.txt + pip-tools
- Node.js 项目: 团队小用 npm,团队大用 yarn(确定性安装更可靠)
- Java 项目: 新项目用 Gradle,老项目用 Maven(别折腾迁移,不值得)
核心原则: 不管用哪个工具,一定要把锁文件提交到 Git 仓库。这是保证「我机器上能跑,你机器上也能跑」的最简单方法。
嗯,这节就到这里。下一节我们会深入聊聊「语义化版本号」——为什么 2.1.0 和 2.1.1 可能不兼容?为什么 3.0.0 升级要谨慎?到时候见。