Build system design
Build time is paid by every developer on every change, which makes it one of the highest-leverage things to fix. Reproducibility matters equally, since a build that differs between machines makes every failure ambiguous.
Method
- Make builds hermetic. Declared inputs and pinned tools, so the same source produces the same output anywhere (see compilers-and-toolchains).
- Cache aggressively with correct keys. A key including all real inputs is what makes caching safe; a loose key serves stale artefacts silently (see github-actions-workflows).
- Build only what changed. Incremental and dependency-aware builds avoid rebuilding the world for a one-line change (see monorepo-workspaces).
- Parallelise independent work. Most build graphs have substantial parallelism that sequential scripts waste.
- Fail fast on cheap checks. Ordering quick checks before slow ones returns most failures in seconds (see ci-cd).
- Keep local and CI builds identical. Divergence produces the works on my machine class of problem, which is expensive to diagnose.
- Measure and budget build time. A tracked number with a threshold is what prevents gradual decay into a ten-minute build.
Boundaries
Build optimisation has diminishing returns and competes with feature work. Sophisticated build systems have their own learning curve and maintenance. Caching bugs produce confusing failures that are worse than slow builds.