Chapter 03Lesson 03~90 minutes

Coordinates, Dependencies, Repositories, Metadata, Transitivity, and Version Selection: Configuration, Design Choices, and Tradeoffs

Choose fixed versus dynamic versions, direct declarations versus transitive reliance, conflict-management policy, and repository topology deliberately for reproducibility, security, and maintainability.

Version PolicyRepository PolicyConstraintsReproducibilitySecurity

Learning objectives

  • Choose fixed, ranged/dynamic, and changing version policies based on reproducibility and update requirements.
  • Decide when a dependency should be declared directly rather than inherited transitively.
  • Compare Maven nearest/managed mediation with Gradle conflict resolution and constraints without pretending the models are identical.
  • Design public-repository versus mirror/proxy topology with explicit trust, availability, and dependency-confusion boundaries.
  • Justify a production dependency policy with observable graph and repository evidence.
Version baseline — verified 2026-08-23. Examples use JDK 21 as the common lab runtime, Apache Maven 3.9.16, Apache Maven Wrapper 3.3.4 where a Maven wrapper is already present, Apache Maven Dependency Plugin 3.10.0 for dependency-tree evidence, and Gradle 9.7.1 through the Gradle Wrapper. Maven 4.0.0-rc-6 is still a release candidate and is not required here. The illustrative graph uses org.apache.commons:commons-text:1.10.0, whose published POM declares org.apache.commons:commons-lang3:3.12.0, plus a deliberate direct request for commons-lang3:3.9. Re-check current versions and metadata before reusing these examples in production.

1. Design policy begins with one question: what is allowed to change without a source review?

A dependency policy is a change-control policy. Fixed coordinates constrain version discovery. Dynamic/ranged selectors delegate part of version choice to repository state. Snapshots/changing modules delegate even more because the same coordinate can point to new bytes. Repositories and mirrors decide which authority supplies the metadata used for those decisions.

2. Fixed versions versus ranges and dynamic selectors

Policy Benefit Risk Evidence/control
fixed releases stable, reviewable request identity still depends on repository integrity and transitive graph dependency tree/locks/verification/checksums as appropriate
Maven version range allows compatible version discovery repository/time can change selected version capture resolved versions; govern update window
Gradle dynamic selector such as 3.+ fast integration with family of releases new publication can change graph; cached TTL affects timing dependency locking + controlled update process
SNAPSHOT/changing rapid integration before release same coordinate can yield different bytes short-lived integration only; never confuse with immutable release evidence

Gradle documentation explicitly warns that dynamic/changing dependencies can make builds unreproducible and recommends locking dynamic selections. Locking does not make a changing module immutable; the coordinate can still refer to different bytes.

3. Direct declaration versus “I get it transitively anyway”

If your source directly imports an API, declaring that dependency directly communicates ownership of the contract. Relying on an unrelated library to continue exporting the dependency couples your source to somebody else’s implementation graph. Maven’s own dependency guide recommends explicitly specifying dependencies your source uses directly.

Situation Recommended expression Reason
source imports lang3 API direct project dependency documents compile/runtime contract
library used only inside commons-text implementation leave transitive unless policy requires management project does not own direct API dependency
organization mandates approved family version central management/platform/constraint in later chapters govern version without fake code dependency
unwanted vulnerable transitive module upgrade/constraint/exclusion only after impact analysis removal/replacement can break upstream consumer

4. Maven management and Gradle constraints solve related problems through different models

Maven’s nearest-definition mediation is a graph-path rule. dependencyManagement can centrally control versions when a dependency is encountered and takes precedence over ordinary transitive mediation in the relevant project model. Gradle’s dependency constraints participate in its resolution model and can express required, preferred, rejected, or strict version intent. Platforms/BOMs provide broader centralized governance.

Do not translate mechanically: a Maven managed version is not “the same feature” as every Gradle constraint. Compare the production invariant—what versions may be selected, where policy lives, and how the resolver reports the reason.

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.12.0</version>
    </dependency>
  </dependencies>
</dependencyManagement>
dependencies {
    implementation("org.apache.commons:commons-text:1.10.0")
    constraints {
        implementation("org.apache.commons:commons-lang3:3.12.0") {
            because("approved baseline for this service")
        }
    }
}

5. Public repositories versus controlled mirrors/proxies

Repository topology affects security, availability, performance, and reproducibility. Maven can apply mirrors from settings.xml; a common enterprise pattern mirrors all remote requests through one repository manager. Gradle can centralize dependency repositories in settings and restrict repository content. The dedicated Nexus course will cover repository-manager administration; here the concern is the build-side contract.

Topology Strength Risk/cost Build-side control
direct public Central only simple; fewer moving parts internet availability and direct external trust explicit single repository; immutable versions; verification
multiple public repositories access to ecosystem-specific modules repository sprawl, same-coordinate ambiguity, outage surface minimum repositories + content filters
internal proxy/mirror central cache/policy/audit/availability manager becomes critical dependency Maven mirror/settings or Gradle governed repositories; HA/backup handled elsewhere
internal hosted coordinates + public proxy organization ownership + external access dependency-confusion if namespace ownership unclear content routing/filtering + reserved group namespaces
Dependency-confusion boundary: an internal coordinate should not be silently satisfiable from an untrusted public source. Repository content rules, namespace ownership, and controlled mirrors/proxies are preventive controls; “put our repo first” is not a complete security model.

6. Repository order is observable behavior, but the exact algorithms differ

Maven documents an effective repository order derived from effective settings, local/parent/Super POMs, and dependency-path POMs, with mirrors applied before download. Inspect help:effective-settings and help:effective-pom rather than guessing.

Gradle checks declared repositories during metadata lookup and, once it finds module metadata for a fixed version in a repository, uses that repository for that module’s artifacts. Dynamic version discovery can query multiple repositories to build the candidate set. Do not use generic advice like “first repository always wins” across all cases.

7. Worked decision — production JVM service in a controlled organization

Decision Chosen policy Why Verification
application dependencies fixed releases; source-used APIs direct reviewable graph intent tree/insight in CI
dynamic versions disallowed on protected release branch prevents surprise selections Gradle fail/locking policy; review Maven ranges
snapshots/changing integration branch only; never release evidence same coordinate may change repository policy + graph record
external repositories one governed proxy of approved upstreams central policy, cache, audit effective settings/repository model
internal group IDs served only by controlled internal content route reduces dependency-confusion exposure content filter/repository-manager policy
upgrades explicit dependency-update change with tests makes change reviewable before/after resolved graph + test/artifact evidence

8. Common wrong approaches

  • Using latest, +, ranges, or SNAPSHOTs on release branches without a locking/update policy.
  • Adding more repositories whenever resolution fails instead of fixing the missing coordinate or repository contract.
  • Forcing a lower transitive version without checking the upstream library’s binary/runtime expectations.
  • Assuming Maven nearest-wins and Gradle highest-wins are universal under all management, constraints, ranges, capabilities, and rules.
  • Treating dependency cache contents as an authoritative artifact repository.

Knowledge check

What policy question distinguishes a fixed version from a dynamic selector?

Why declare a library directly when your source imports its API even if it already arrives transitively?

Why is “put the internal repository first” insufficient defense against dependency confusion?

What should accompany a deliberate transitive downgrade?

Does dependency locking solve mutable SNAPSHOT bytes?

Summary

Version syntax, transitivity, conflict policy, and repository topology are change-control decisions. Prefer explicit direct dependencies for APIs you own, immutable release requests, centrally governed version policy, minimal repository surfaces, and evidence that shows both the selected graph and the authority that supplied it.

Next lesson

Diagnose resolution failures without cache superstition

Lesson 4 introduces missing coordinates, metadata/artifact split failures, runtime behavior changes, cache masking, and repository-origin surprises, then applies one repeatable evidence-first sequence.

Official references and version notes

These lessons were finalized against current primary documentation on 2026-08-23. Dependency metadata, plugin versions, repository policies, Gradle resolution behavior, and Maven/Gradle releases are version-sensitive. Verify the exact tool versions and repository policy used by your project and CI before applying production controls.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.