开发者工具演进史

2026/3/22

开发者工具构建系统DevOps

开发者工具演进史

从 Make 到 Bazel 再到 Buck2,开发者工具的 50 年演进。


第一代:1970s-1980s - Make

Make

# Makefile(1976)
all: program
program: main.o utils.o
    gcc -o program main.o utils.o

main.o: main.c
    gcc -c main.c

utils.o: utils.c
    gcc -c utils.c

clean:
    rm -f *.o program

特点

  • 简单:声明式,易于理解
  • 依赖管理:文件时间戳自动构建
  • 跨平台:Unix、Windows、macOS

局限

  • 增量构建弱:难以精确追踪
  • 并行构建差:依赖关系处理笨
  • 语言无关:不识别 C、Java、Python

第二代:1990s - Ant, Maven, Rake

Ant(Java)

<!-- build.xml(2000)-->
<project name="myproject" default="compile">
  <target name="compile">
    <javac srcdir="src" destdir="classes"/>
  </target>

  <target name="run" depends="compile">
    <java classname="MyClass" classpath="classes"/>
  </target>
</project>

Maven(Java)

<!-- pom.xml(2004)-->
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>myapp</artifactId>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.3.0</version>
    </dependency>
  </dependencies>
</project>

Rake(Ruby)

# Rakefile(2003)
task :default => [:build]

task :build do
  sh "gcc -o program main.c utils.c"

task :test => [:build] do
  sh "./program test_input"
end

特点

  • 语言感知:Java、Ruby 专用
  • 依赖管理:Maven Central、RubyGems
  • 任务系统:Ant targets、Rake tasks

局限

  • XML 繁琐:Ant 的 XML 配置冗长
  • 全局锁:Maven 的单一版本依赖
  • 缺乏增量:仍然不精确

第三代:2000s-2010s - Gradle, SBT, Leiningen

Gradle(JVM)

// build.gradle(2008)
plugins {
    id 'java'
}

dependencies {
    implementation 'org.springframework:spring-core:5.3.0'
    testImplementation 'junit:junit:4.13.2'
}

tasks.named('test') {
    useJUnitPlatform()
}

SBT(Scala)

// build.sbt(2008)
name := "myproject"
version := "1.0"

libraryDependencies ++= Seq(
  "org.scalatest" %% "scalatest" % "3.2.0" % Test
)

Leiningen(Clojure)

;; project.clj(2009)
(defproject myproject "1.0.0"
  :dependencies [[org.clojure/clojure "1.11.0"]]
  :plugins [[lein-cljsbuild "1.1.7"]])

特点

  • DSL 友好:Groovy、Scala、Clojure
  • 依赖解析灵活:冲突解决更聪明
  • 增量构建:更精确

局限

  • 启动时间:JVM 启动慢
  • 配置复杂:大型项目难维护
  • 远程缓存弱:缺少分布式构建

第四代:2010s-2020s - Bazel, Buck, Gradle Enterprise

Bazel(Google)

# BUILD.bazel(2015)
py_binary(
    name = "main",
    srcs = ["main.py"],
    deps = [":utils"],
)

py_library(
    name = "utils",
    srcs = ["utils.py"],
    deps = ["@numpy//:numpy"],
)
# WORKSPACE(2015)
load("@bazel_tools//tools/builddefs/repo:http.bzl", "http_archive")

http_archive(
    name = "rules_python",
    urls = ["https://github.com/bazelbuild/rules_python/archive/..."],
)

特点

  • 精确依赖:输入哈希,可复现构建
  • 分布式缓存:远程执行和缓存
  • 多语言:Java、C++、Python、Go 等
  • 大规模:Google 内部使用

Buck(Facebook/Meta)

# BUCK(2013)
python_binary(
    name = "main",
    main_module = "main",
    deps = [":utils"],
)

python_library(
    name = "utils",
    srcs = ["utils.py"],
    deps = [
        third_party_lib("numpy"),
    ],
)

特点

  • 快速构建:并行执行和缓存
  • 多语言支持:Java、C++、Python、Objective-C
  • Cell:Facebook 内部分布式执行

Gradle Enterprise

// settings.gradle
plugins {
    id 'com.gradle.enterprise'
}

gradleEnterprise {
    server = "https://gradle.mycompany.com"
}

特点

  • 远程缓存:公司级缓存共享
  • 构建扫描:性能分析
  • 依赖洞察:可视化依赖图

第五代:2020s-2025 - Buck2, Pants, Nix

Buck2(Meta)

# TARGETS(2024)
load("@prebuilt//python:defs.bzl", "python_binary")

python_binary(
    name = "main",
    main_module = "main",
    deps = [":utils"],
)

load("//toolchains/python:toolchains/python:defs.bzl", "toolchain")
toolchain(
    name = "python",
    toolchain_type = "python",
)

Buck2 变化

  • Starlark 2:更好的类型系统
  • 配置继承:减少重复
  • 工具链抽象:统一的工具链管理
  • REPL:交互式查询和构建

Pants(Toolchain)

# BUILD(2020+)
python_sources(
    name = "src",
    sources = ["*.py"],
    deps = [
        "3rdparty/python:requests",
    ],
)

pex_binary(
    name = "app",
    entry_point = "main:main",
)

特点

  • 统一接口:多种语言同一 API
  • 多平台:本地执行、远程缓存、Docker
  • 增量:精确到函数级别
  • Type 驱动:Starlark、Python

Nix(纯函数式)

# shell.nix(2014)
{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
    buildInputs = with pkgs; [
        python3
        python3Packages.numpy
        python3Packages.pandas
    ];
}

特点

  • 纯函数式:可复现,无隐式依赖
  • 多环境:dev、test、prod
  • Rollback:历史可追踪

现代:2025+ - Nx, Turborepo, esbuild

Nx(Monorepo 工具)

// project.json(2020+)
{
  "name": "my-app",
  "sourceRoot": "apps/my-app/src",
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nx/vite:build"
    },
    "test": {
      "executor": "@nx/vite:test"
    }
  }
}

特点

  • Monorepo 原生:跨项目依赖和缓存
  • 分布式缓存:团队共享缓存
  • 可视化图:依赖关系图
  • 代码生成:自动 scaffold

Turborepo

// turbo.json(2021)
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"]
    }
  }
}

特点

  • 零配置:自动推断
  • 增量构建:最小化执行
  • CI 优化:单次运行多个目标

esbuild(JavaScript 打包)

// esbuild.config.mjs(2020)
import esbuild from 'esbuild';

await esbuild.build({
  entryPoints: ['src/index.js'],
  bundle: true,
  outfile: 'dist/bundle.js',
  minify: true,
});

特点

  • 极快:比 Webpack 快 10-100 倍
  • 零配置:简单到极致
  • Tree-shaking:移除未使用代码

对比总结

时代代表工具特点局限
1970sMake简单、依赖管理不语言感知、增量弱
1990sAnt/Maven语言感知、依赖管理XML 繁琐、全局锁
2000sGradle/SBTDSL、增量构建启动慢、配置复杂
2010sBazel/Buck精确依赖、分布式缓存学习曲线陡
2020sPants/Buck2类型驱动、统一接口社区小
2025+Nx/TurborepoMonorepo 原生、可视化限于 Monorepo

选择建议

单项目(< 1000 行)

语言推荐
JavaScript/TypeScriptesbuild、Vite
PythonPoetry + Make
RustCargo
Gogo build

中等项目(1000-10000 行)

语言推荐
JVMGradle
PythonPoetry
C/C++CMake + Ninja
Node.jsNx(如果 Monorepo)

大型项目(> 10000 行)

场景推荐
MonorepoNx、Turborepo
多语言Bazel、Pants
微服务每个独立工具
Google/Meta 风格Bazel、Buck2

趋势

1. 配置即代码

// TypeScript 配置
import { defineConfig } from 'vite';

export default defineConfig({
    plugins: [react()],
    build: {
        rollupOptions: {
            output: {
                assetFileNames: 'assets/[name]-[hash].js',
            },
        },
    },
});

2. 缓存为王

本地缓存 → 远程缓存 → 分布式执行

每层避免 50-90% 重复工作

3. 并行优先

# 自动并行
targets = [
    "build:frontend",
    "build:backend",
    "test:unit",
    "test:integration",
]

# 自动检测依赖,最大化并行

4. 增量构建

函数级别 → 文件级别 → 包级别 → 项目级别

越细粒度,越少的重构建

总结

开发者工具演进 50 年:

  1. 1970s:Make - 简单声明式
  2. 1990s:Ant/Maven - 语言感知
  3. 2000s:Gradle/SBT - DSL 友好
  4. 2010s:Bazel/Buck - 精确依赖、分布式
  5. 2020s:Pants/Buck2 - 类型驱动
  6. 2025+:Nx/Turborepo - Monorepo 原生

核心趋势

  • 从脚本到 DSL
  • 从顺序到并行
  • 从本地到分布式
  • 从单一项目到 Monorepo

“最好的工具是你不需要思考的工具。“


资源

📝 文章反馈