Checkpoint Lab — Maven Performance, Parallel Builds, Daemon Options, Reproducible Builds, and Troubleshooting
Profile a multi-module Maven build, make one evidence-backed performance improvement, and prove reproducible output across isolated workspaces and local repositories.
This checkpoint accepts a performance change only when its timing evidence is controlled and its output identity survives an isolated rebuild. The lab uses a harmless 600 ms Ant sleep in each of two independent modules to make reactor overlap visible even on a small machine; the plugin goal is currently documented as thread-safe.
Learning objectives
- Capture a baseline reactor graph, versions, cache state, and serial timing.
- Predict which modules can overlap and which cannot before enabling parallelism.
- Make one measured performance improvement without changing required build scope.
- Build the same source in isolated directories/repositories and compare checksums.
- Diagnose any checksum or execution-plan difference before accepting the optimization.
- Produce a verification checklist that a CI reviewer could audit.
1. Checkpoint acceptance contract
The checkpoint passes only if you can show all of the following: exact Maven/JDK identity; the common → {alpha,beta} → app graph; cold and warm baseline context; serial and parallel timings measured under the same warm repository state; no unresolved thread-safety warning; successful required lifecycle; matching expected artifact set; and matching checksums across independent workspaces after reproducibility controls are applied.
“Parallel was faster on my laptop” is not sufficient.
2. Setup and preflight
set -euo pipefail
LAB="$PWD/../maven-perf-checkpoint-a"
mkdir -p "$LAB"/{evidence,.lab/repo}
cp mvnw mvnw.cmd "$LAB/"
cp -R .mvn "$LAB/"
cd "$LAB"
./mvnw -v | tee evidence/maven-version.txt
java -version 2> evidence/java-version.txt
printf '%s
' 'Prediction 1: common runs before alpha/beta; app waits for both.' 'Prediction 2: -T 2 can overlap the 600 ms alpha/beta fixture.' 'Prediction 3: serial and parallel artifacts remain byte-identical.' 'Prediction 4: a second workspace/repository produces the same JAR checksums.' > evidence/predictions.txt
3. Create the graph and the measurable, thread-safe fixture
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.academy</groupId><artifactId>perf-checkpoint</artifactId><version>1.0.0</version><packaging>pom</packaging>
<modules><module>common</module><module>alpha</module><module>beta</module><module>app</module></modules>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.outputTimestamp>2026-08-24T00:00:00Z</project.build.outputTimestamp>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement><dependencies>
<dependency><groupId>dev.academy</groupId><artifactId>common</artifactId><version>${project.version}</version></dependency>
<dependency><groupId>dev.academy</groupId><artifactId>alpha</artifactId><version>${project.version}</version></dependency>
<dependency><groupId>dev.academy</groupId><artifactId>beta</artifactId><version>${project.version}</version></dependency>
</dependencies></dependencyManagement>
<build>
<pluginManagement><plugins>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-clean-plugin</artifactId><version>3.5.0</version></plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>3.5.0</version></plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.15.0</version></plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.5.6</version></plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.5.1</version></plugin>
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-antrun-plugin</artifactId><version>3.2.0</version></plugin>
</plugins></pluginManagement>
</build>
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent><groupId>dev.academy</groupId><artifactId>perf-checkpoint</artifactId><version>1.0.0</version><relativePath>../pom.xml</relativePath></parent>
<artifactId>alpha</artifactId>
<dependencies><dependency><groupId>dev.academy</groupId><artifactId>common</artifactId></dependency></dependencies>
<build><plugins><plugin>
<groupId>org.apache.maven.plugins</groupId><artifactId>maven-antrun-plugin</artifactId>
<executions><execution><id>measurable-work</id><phase>generate-resources</phase><goals><goal>run</goal></goals>
<configuration><target><sleep milliseconds="600"/></target></configuration>
</execution></executions>
</plugin></plugins></build>
</project>
Create beta/pom.xml from the alpha POM by changing only
<artifactId>alpha</artifactId> to
beta. Create common and
app POMs using the same parent/dependency pattern from
Lesson 2. The AntRun run goal in version 3.2.0 is
documented as thread-safe; the <sleep> task
simply creates enough independent wall time to observe overlap.
4. Add deterministic sources and draw three separate views
Reuse the four Java classes from Lesson 2. Before running Maven,
draw these views in evidence/graphs.txt:
- Aggregation: root lists common, alpha, beta, app.
- Dependency graph: common → alpha, common → beta, alpha → app, beta → app.
- Parallel opportunity: alpha and beta can overlap after common; app is the join point.
Do not draw pluginManagement as a reactor ordering
edge; management alone does not instantiate a project relationship.
5. Inspect before timing
./mvnw help:effective-pom -Doutput=evidence/effective-pom.xml
./mvnw org.apache.maven.plugins:maven-artifact-plugin:3.6.1:check-buildplan -Dcheck.buildplan.tasks=verify | tee evidence/buildplan.txt
./mvnw -DskipTests dependency:tree | tee evidence/dependency-tree.txt
Confirm AntRun 3.2.0 is active only in alpha and beta and the other pinned plugin versions are inherited. Preserve any warning rather than filtering it away.
6. Capture cold and warm serial baselines
REPO="$PWD/.lab/repo"
TIMEFORMAT='elapsed=%3R s'
time ./mvnw -Dmaven.repo.local="$REPO" -T 1 clean verify | tee evidence/serial-cold.log
time ./mvnw -Dmaven.repo.local="$REPO" -T 1 clean verify | tee evidence/serial-warm-1.log
time ./mvnw -Dmaven.repo.local="$REPO" -T 1 clean verify | tee evidence/serial-warm-2.log
Use the warm serial runs as the comparator for parallelism because their repository state matches the subsequent parallel run. Keep the cold run as separate evidence of resolver/bootstrap cost.
7. Apply one bounded performance change: -T 2
time ./mvnw -Dmaven.repo.local="$REPO" -T 2 clean verify | tee evidence/parallel-warm-1.log
time ./mvnw -Dmaven.repo.local="$REPO" -T 2 clean verify | tee evidence/parallel-warm-2.log
Expected structural observation: the two 600 ms branch fixtures can
overlap, so -T 2 should usually reduce the portion of
the critical path occupied by alpha and beta. Do not invent a
required percentage; record the actual machine result. If
parallelism is not faster, that is valid evidence—your “improvement”
must then be rejected or replaced by another measured change.
8. Prove the optimization did not skip work
grep -E 'common|alpha|beta|app|Reactor Summary|BUILD SUCCESS|WARNING' evidence/parallel-warm-1.log | tee evidence/parallel-summary.txt
sha256sum common/target/common-1.0.0.jar alpha/target/alpha-1.0.0.jar beta/target/beta-1.0.0.jar app/target/app-1.0.0.jar | tee evidence/workspace-a.sha256
The reactor summary must still contain all four projects. A faster
command that uses a smaller -pl scope is not equivalent
unless the checkpoint explicitly changed its required output
contract.
9. Rebuild in workspace B with a separate repository
cd ..
cp -R maven-perf-checkpoint-a maven-perf-checkpoint-b
find maven-perf-checkpoint-b -type d -name target -prune -exec rm -rf {} +
rm -rf maven-perf-checkpoint-b/evidence maven-perf-checkpoint-b/.lab
mkdir -p maven-perf-checkpoint-b/{evidence,.lab/repo}
cd maven-perf-checkpoint-b
./mvnw -Dmaven.repo.local="$PWD/.lab/repo" -T 1 clean verify | tee evidence/workspace-b.log
sha256sum common/target/common-1.0.0.jar alpha/target/alpha-1.0.0.jar beta/target/beta-1.0.0.jar app/target/app-1.0.0.jar | tee evidence/workspace-b.sha256
Compare the digest values by artifact name, not by absolute path. If any differ, stop the performance sign-off and investigate dynamic resources, plugin versions, JDK identity, generated ordering, line endings, or other undeclared inputs.
10. Add Maven reproducibility evidence
./mvnw -Dmaven.repo.local="$PWD/.lab/repo" org.apache.maven.plugins:maven-artifact-plugin:3.6.1:check-buildplan -Dcheck.buildplan.tasks=verify -Ddiagnose=true | tee evidence/repro-diagnose.txt
This check knows about reproducibility issues in the execution plan and can diagnose the effective output timestamp. It complements—rather than replaces—the independent checksum comparison.
11. Decide whether the change is accepted
Record a one-paragraph decision in
evidence/decision.txt with: median/representative
serial-warm time, parallel-warm time, machine/JDK/Maven identity,
thread count, warnings, artifact checksum result, and whether
-T 2 is accepted. If timing is noisy or no faster,
reject the change; evidence-backed optimization includes
evidence-backed non-adoption.
12. Verification checklist
- Wrapper reports Maven 3.9.16 and expected JDK 21.
- All four modules appear in reactor evidence.
- Graph prediction matches observed ordering constraints.
- Cold/warm repository state is labeled separately.
- Serial and parallel measurements use equivalent goals/project scope.
- No unresolved non-thread-safe plugin warning is ignored.
- Required JARs exist after serial and parallel builds.
- Workspace A and B JAR checksums match by artifact.
-
artifact:check-buildplanevidence is preserved. - No normal user cache, production repository, credential, or signing material was changed.
13. Cleanup and rollback
cd ..
rm -rf maven-perf-checkpoint-a maven-perf-checkpoint-b
Run this only for the exact disposable directories created by the
checkpoint. If you adapted names, verify them first. The rollback
for the production decision is simpler: if -T 2 is not
accepted, remove it from the workflow while leaving the project
model unchanged.
Knowledge check
Why does the checkpoint use a 600 ms fixture in alpha and beta?
It gives the small lab a visible amount of independent work so reactor overlap can be measured. It is a teaching fixture, not a production performance technique.
Why compare parallel-warm against serial-warm rather than serial-cold?
Because otherwise the comparison mixes two variables: repository warmth and reactor concurrency.
If -T 2 is faster but workspace B produces a different app JAR checksum, what is the acceptance decision?
Reject or pause the performance change until the byte difference is explained and repaired; speed does not override reproducibility.
Why is AntRun 3.2.0 acceptable for this synthetic fixture?
Its run goal is currently documented as thread-safe and supports Maven parallel builds, and the configuration writes no shared files; it only sleeps inside each branch module.
What if -T 2 is not faster on the learner machine?
Record that result and do not claim an improvement. The checkpoint rewards evidence, including rejecting an ineffective optimization.
What does the clean-room rebuild prove better than a second warm build in workspace A?
It reduces dependence on prior target outputs, workspace-local state, and the first local repository, making unexplained environmental inputs easier to detect.
14. Production operating model and Chapter 14 bridge
Chapter 13 adds a rule to the build-engineering operating model: performance changes require controlled evidence and artifact invariants. You can now distinguish graph concurrency, process persistence, resolver state, reproducible archive controls, and diagnostic logging instead of treating them as one “Maven speed” feature.
Chapter 14 moves from optimizing the Maven 3 production baseline to evaluating Maven 4 preview behavior, compatibility, Build Consumer POM concepts, and a deliberate migration plan without confusing release-candidate software with the stable path.
Official references and version notes
Version-sensitive statements in this lesson were checked against current Apache Maven primary documentation on 2026-08-24.
- Apache Maven download/current releases — Maven 3.9.16 is recommended; Maven 4 and mvnd 2.x are preview lines; mvnd 1.0.6 is current.
- Maven 3.9.16 release notes — Current Maven 3 behavior and release-specific changes.
- Configuring reproducible builds — project.build.outputTimestamp, build-plan checks, and independent rebuild guidance.
- Maven Daemon — Separate daemon infrastructure and mvnd invocation model.
- Maven multiple-modules guide — Reactor collection, sorting, and selected project behavior.
- Maven Artifact Plugin — Build-plan and reproducibility comparison tools.
- Maven AntRun Plugin 3.2.0 run — The run goal is documented thread-safe and supports parallel builds.
- Maven CLI thread option reference — Maven 3.9.16 exposes the -T/threads CLI option; current core also accepts trimmed values.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.