<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Maven on Backend Engineering Strategy Tools</title><link>https://backend-engineering-strategy-tools.github.io/site/tags/maven/</link><description>Recent content in Maven on Backend Engineering Strategy Tools</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 03 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://backend-engineering-strategy-tools.github.io/site/tags/maven/index.xml" rel="self" type="application/rss+xml"/><item><title>Build Systems — Ant, Maven, Gradle, Bazel</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/build-systems/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/build-systems/</guid><description>&lt;p&gt;The Java ecosystem has cycled through several generations of build tooling. Each generation solved real problems with the previous one and introduced new ones of its own.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="ant"&gt;Ant
&lt;/h2&gt;&lt;p&gt;XML-based, imperative. You describe exactly what to do and in what order — compile these files, copy to this directory, package this jar. No conventions, no opinions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strengths&lt;/strong&gt;: total control, predictable, easy to understand what any given build does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weaknesses&lt;/strong&gt;: verbose, no built-in dependency management (Ivy was a separate add-on), and every project reinvents the same targets from scratch. Large Ant builds become hard to maintain.&lt;/p&gt;
&lt;p&gt;Still found in older enterprise Java projects. Worth knowing to read and modify, less worth starting from scratch.&lt;/p&gt;
&lt;p&gt;Used it. It was what it was — at least you always knew exactly what the build was doing.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="maven"&gt;Maven
&lt;/h2&gt;&lt;p&gt;Convention over configuration. If your project follows the standard layout (&lt;code&gt;src/main/java&lt;/code&gt;, &lt;code&gt;src/test/java&lt;/code&gt;, etc.) most of the build is declared, not scripted. Dependency management built in via the POM and central repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maven 1&lt;/strong&gt;: the original. Repository model and POM concept introduced. Plugin system was limited and the build lifecycle was rigid.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maven 2&lt;/strong&gt;: major redesign. The lifecycle phases (validate → compile → test → package → install → deploy) that most people know. Dependency resolution significantly improved. This is the version that won widespread adoption.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Maven 3&lt;/strong&gt;: incremental improvements over Maven 2. Better performance, improved parallel builds, polyglot POM support. Most Maven projects today run on 3.x.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strengths&lt;/strong&gt;: standardised project layout means any Maven project is immediately navigable; dependency management and central repository model that the whole ecosystem built on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weaknesses&lt;/strong&gt;: XML is verbose for expressing logic; the lifecycle is powerful but opaque when things go wrong; plugin configuration gets unwieldy; multi-module builds are better than Ant but still awkward at scale.&lt;/p&gt;
&lt;p&gt;Not a fan. All three weaknesses compound each other: the XML is painful to write, the lifecycle hides what is actually executing and where, and parent POM inheritance chains in multi-module projects make it genuinely hard to answer &amp;ldquo;what does this build actually do?&amp;rdquo; You end up cargo-culting POM snippets from Stack Overflow and hoping the lifecycle does what you think it does.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="gradle"&gt;Gradle
&lt;/h2&gt;&lt;p&gt;Groovy (and later Kotlin) DSL instead of XML. Keeps Maven&amp;rsquo;s dependency management and repository model, drops the rigid lifecycle in favour of a task graph. Incremental builds — only re-runs tasks whose inputs changed.&lt;/p&gt;
&lt;p&gt;Became the default for Android builds and has significant adoption in JVM projects that outgrew Maven.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strengths&lt;/strong&gt;: expressive build scripts; incremental and cached builds make large projects faster; Kotlin DSL gives type safety and IDE support; flexible enough to model non-standard builds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weaknesses&lt;/strong&gt;: the flexibility is also the trap — Gradle builds vary wildly and can be hard to read; the Groovy DSL is easy to write badly; build times on cold caches can be slow; debugging task dependencies is non-trivial.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gradle vs Maven&lt;/strong&gt;: Maven wins on standardisation and predictability; Gradle wins on performance and flexibility. For a standard Java/Kotlin service with no unusual requirements, Maven is often the lower-maintenance choice. For Android, large monorepos, or complex multi-language builds, Gradle.&lt;/p&gt;
&lt;p&gt;Gradle solves the XML problem but introduces a different one: the flexibility makes it very easy to get wrong. Every team ends up with a slightly different Gradle build, and reading someone else&amp;rsquo;s is often just as opaque as Maven&amp;rsquo;s lifecycle — just for different reasons. The problem of &amp;ldquo;what is this build actually doing&amp;rdquo; doesn&amp;rsquo;t go away, it just changes shape.&lt;/p&gt;
&lt;p&gt;The discipline that keeps Gradle manageable: &lt;strong&gt;don&amp;rsquo;t stuff everything into the Gradle build&lt;/strong&gt;. Gradle should compile, test, and package — that&amp;rsquo;s it. Deployment logic, environment setup, Docker builds, release steps — those belong in scripts or other tools that are good at those things. Then wrap the whole thing in a Makefile that gives a single consistent entry point. &lt;code&gt;make build&lt;/code&gt; calls Gradle. &lt;code&gt;make docker&lt;/code&gt; calls a shell script. &lt;code&gt;make deploy&lt;/code&gt; calls Helm. Gradle stays focused and readable; the Makefile is the seam that holds it together.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="sbt"&gt;SBT
&lt;/h2&gt;&lt;p&gt;The Scala Build Tool. Reactive, incremental compilation at the core. Not just a build tool — the REPL and interactive session are part of the workflow.&lt;/p&gt;
&lt;p&gt;Heavy dependency on Scala itself; the build definition is Scala code. Powerful but a significant learning curve for anyone not already in the Scala ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Notes to follow.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="bazel--bazelisk"&gt;Bazel &amp;amp; Bazelisk
&lt;/h2&gt;&lt;p&gt;Originally Google&amp;rsquo;s internal build system (Blaze), open-sourced as Bazel. Hermetic builds — each action declares its inputs and outputs explicitly, no implicit filesystem access. Correctness and reproducibility guaranteed by construction.&lt;/p&gt;
&lt;p&gt;Language-agnostic: rules exist for Java, Go, Python, C++, and others. Built for monorepos at scale — incremental and distributed builds, remote caching, remote execution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bazelisk&lt;/strong&gt;: version manager for Bazel. Pin the Bazel version in &lt;code&gt;.bazelversion&lt;/code&gt;, run &lt;code&gt;bazelisk&lt;/code&gt; instead of &lt;code&gt;bazel&lt;/code&gt; — it downloads and uses the pinned version automatically. Essential for team consistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Strengths&lt;/strong&gt;: genuinely reproducible builds; scales to very large codebases; remote caching makes CI fast once warm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Weaknesses&lt;/strong&gt;: steep learning curve; rules ecosystem outside Google&amp;rsquo;s own languages is less mature; significant setup cost; overkill for anything smaller than a large monorepo.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Opinions to follow.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="choosing"&gt;Choosing
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;/th&gt;
 &lt;th&gt;Small project&lt;/th&gt;
 &lt;th&gt;Standard service&lt;/th&gt;
 &lt;th&gt;Large monorepo&lt;/th&gt;
 &lt;th&gt;Polyglot&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Ant&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Possible&lt;/td&gt;
 &lt;td&gt;Legacy only&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Maven&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Fine&lt;/td&gt;
 &lt;td&gt;Good default&lt;/td&gt;
 &lt;td&gt;Struggles&lt;/td&gt;
 &lt;td&gt;No&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Gradle&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Fine&lt;/td&gt;
 &lt;td&gt;Good&lt;/td&gt;
 &lt;td&gt;Better&lt;/td&gt;
 &lt;td&gt;Partial&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Bazel&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;Overkill&lt;/td&gt;
 &lt;td&gt;Overkill&lt;/td&gt;
 &lt;td&gt;Strong&lt;/td&gt;
 &lt;td&gt;Strong&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both Maven and Gradle have the same core problem: you end up not really knowing what your build is doing. Ant at least was honest about it. If forced to choose, Gradle is the least bad option — the DSL flexibility is a trap but it is a trap you can avoid with discipline, whereas Maven&amp;rsquo;s lifecycle opacity and XML are just the deal regardless. For anything in the JVM ecosystem today the choice is usually made for you by the project or the framework — if you get to choose, Gradle with a simple build file and keep it that way.&lt;/p&gt;</description></item><item><title>Nexus Repository</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/frameworks-tools/nexus/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/frameworks-tools/nexus/</guid><description>&lt;p&gt;Sonatype Nexus Repository Manager is a universal artifact repository. It stores and serves build artifacts — Maven JARs, npm packages, Docker images, Helm charts, PyPI packages, raw binaries — from a single platform. It operates in three modes: hosted (your own artifacts), proxy (a local mirror of an upstream registry), and group (a virtual repository that aggregates hosted and proxy repos behind one URL).&lt;/p&gt;
&lt;h2 id="why-it-exists"&gt;Why it exists
&lt;/h2&gt;&lt;p&gt;Two problems: you want a private registry for internal artifacts (container images, internal libraries), and you want to cache upstream registries to reduce build times, avoid rate limits, and insulate builds from upstream outages. Nexus solves both. Point your build tools at Nexus; Nexus fetches from upstream on first request and caches, or serves from your hosted repos.&lt;/p&gt;
&lt;h2 id="repository-types"&gt;Repository types
&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;# Maven proxy — caches Maven Central
https://nexus.example.com/repository/maven-central/

# Maven hosted — your internal JARs
https://nexus.example.com/repository/maven-releases/
https://nexus.example.com/repository/maven-snapshots/

# Docker hosted — your container images
https://nexus.example.com/repository/docker-hosted/

# npm proxy — caches registry.npmjs.org
https://nexus.example.com/repository/npm-proxy/
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="docker-integration"&gt;Docker integration
&lt;/h2&gt;&lt;p&gt;Nexus can expose a hosted Docker registry on a dedicated port. Configure the Docker daemon to trust the registry, then push and pull normally:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker login nexus.example.com:8082
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker tag myimage:latest nexus.example.com:8082/myimage:latest
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker push nexus.example.com:8082/myimage:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="maven-integration"&gt;Maven integration
&lt;/h2&gt;&lt;p&gt;Point Maven at Nexus by configuring &lt;code&gt;settings.xml&lt;/code&gt; to use the Nexus group repository as a mirror:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;mirrors&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;mirror&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;nexus&lt;span style="color:#f92672"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;mirrorOf&amp;gt;&lt;/span&gt;*&lt;span style="color:#f92672"&gt;&amp;lt;/mirrorOf&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://nexus.example.com/repository/maven-public/&lt;span style="color:#f92672"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;/mirror&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&amp;lt;/mirrors&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All dependency resolution goes through Nexus. Cached. Air-gapped builds are possible by pre-populating the cache.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://help.sonatype.com/repomanager3" target="_blank" rel="noopener"
 &gt;Nexus Repository documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.sonatype.com/products/sonatype-nexus-oss" target="_blank" rel="noopener"
 &gt;Sonatype Nexus OSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>