FREE LESSON · Applications & software architecture · 8 OF 11
Version control, review, and reproducible builds
Version control, review, and reproducible builds: Make a change reconstructable from source through an artifact.
Prerequisites: Files, command-line basics, and testing.
Learning objectives
- Explain commits as snapshots with parent relationships.
- Separate merge conflicts from semantic conflicts.
- Trace source, dependencies, build inputs, and release artifacts.
A commit records a state and its history
Version control represents changes through snapshots and parent relationships. A branch is a movable reference to a commit; a merge records a relationship between histories. The important collaboration question is not merely whether text can be combined. Two independent changes can merge without a textual conflict while disagreeing about the same contract.
Suppose one change renames a JSON field from count to quantity in a producer, while another adds a new consumer expecting count. The edits may occur in different files and merge cleanly. The combined program fails at an interface. Review and integration tests must examine the behavior of the resulting tree. A green result for each branch in isolation is weaker evidence than a green result for their combination.
Trace the artifact's inputs
A build depends on more than application source: compiler version, dependency graph, build flags, generated sources, and sometimes environment-sensitive steps all contribute. Pinning direct dependencies does not necessarily pin transitive ones. A lockfile records a resolved dependency graph, but reproducibility also depends on the package source and toolchain being available and trustworthy.
Imagine two builds of the same commit. One downloads a generated schema from a mutable URL. The other embeds the current date into a bundle. Both can differ despite identical source. A reproducible process makes inputs explicit and controls nondeterminism. Bit-for-bit reproducibility is a precise goal; merely obtaining functionally equivalent outputs is a different one. State which is required.
Keep secrets out of source and build logs. A configuration value embedded into a browser bundle is available to the browser's user, regardless of whether its environment-variable name contains secret. Public client identifiers and server-only credentials have different confidentiality requirements. A build provenance record should identify inputs without disclosing private values.
Review one coherent change
A useful review describes the concrete problem, final behavior, tests performed, and material limitations. A small coherent diff makes assumptions easier to inspect. Mechanical formatting mixed with a behavior change can hide the important line. Small changes still need tests at the relevant boundary; a one-line authorization error can matter more than a large internal refactor.
A release should identify the artifact it deploys. Rebuilding independently during promotion can produce a different artifact from the one tested. Retain checksums or immutable artifact identifiers where the platform supports them, and record the source revision and configuration context. Rollback must also account for data and external effects. Reverting a commit cannot undo an email already sent or restore a column that a migration discarded.
Practice problem
Two branches both pass unit tests. Branch A changes an API field; branch B adds a consumer of the old field. Design a review and CI sequence that detects the combined failure and records which artifact reaches production.
Worked solution
Review the contract change and search its consumers, including the new branch. Merge or construct the candidate combined tree, then run a contract or integration test covering producer and consumer. Build from recorded source, lockfile, toolchain, and configuration inputs. Identify the resulting artifact and promote that tested artifact when possible. Record the release and rollback constraints. Passing isolated unit tests and resolving textual conflicts are insufficient because the semantic disagreement crosses the interface.
Check your understanding
A clean textual merge guarantees what?
- The combined program preserves its contracts.
- No competing text edits required manual resolution.
- The dependency graph is reproducible.
- All consumers were updated.
Explanation
A clean merge describes text combination, not semantic compatibility.
Which build input most directly prevents reproducing an old artifact?
- An immutable compiler image.
- A committed dependency lockfile.
- A schema downloaded from a mutable latest URL.
- A recorded source revision.
Explanation
The mutable URL can supply different bytes for the same source revision.
Primary reading
- Software Engineering at Google: Google, open book
- How to Design Programs: Felleisen et al.