Why build tools
On This Lesson 11 topics
Lesson Overview
Until now you compiled and ran Java with an IDE button or with a single javac command. That works for one file. Real projects have dozens of source files, test files, and libraries written by other people, and "get it all compiled, tested, and packaged" becomes a chore you must repeat the same way hundreds of times.
A build tool automates that chore. This lesson shows what goes wrong without one, then names what a build tool does about it. We use a recipe card and a kitchen assistant as the picture: the card (a file in your project) lists the ingredients and the steps in order; the assistant (the tool) fetches the ingredients and follows the card exactly, every time, for everyone.
Why this matters: every Java backend job uses a build tool. When a teammate says "just run the build", this is what they mean. This lesson builds on the terminal skills from module BEG-006 and on the JUnit tests from module BEG-045, which until now you ran only from the IDE.
Learning Objectives
By the end of this lesson you will be able to:
- Describe the steps of a build: compile, test, package.
- Explain why typing
javaccommands by hand does not scale to real projects. - Define a dependency and say why managing dependencies by hand is painful.
- State what a build tool does in one sentence, and name the two jobs it adds to your project.
- Name Maven and Gradle and say which one this course uses.
- Explain why "it works on my machine" is a build problem, not only a code problem.
Written Explanation
What "building" means
Source code is not what runs. Before a project is useful, several steps have to happen:
- Compile: turn
.javafiles into.classfiles withjavac. - Test: run the automated tests (module BEG-045) against the compiled classes.
- Package: bundle the classes into one file, usually a JAR (Java ARchive, a zip-like file with the extension
.jar), that can be shared or deployed.
Together these steps are the build. On top of them sits a fourth chore: getting the libraries your code uses.
Libraries and dependencies
Most programs use code written by others: a library that formats dates, talks to a database, or parses JSON. Such a library is a dependency of your project: your code depends on it. A library normally arrives as a JAR, and javac must be told where it is.
Suppose your project uses one class from Apache Commons Lang, a well-known helper library. Compile the file without telling javac about the JAR and you get this (real output):
src\main\java\com\example\Shout.java:3: error: package org.apache.commons.lang3 does not exist
import org.apache.commons.lang3.StringUtils;
^The compiler is not wrong: it has no way to know where that code lives. You must pass the JAR's location on the class path (the list of places where Java looks for compiled classes) with -cp. And when you run the program, Java needs the class path again. Real output without it:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtilsThe manual way
Here is what the full manual routine looks like for a tiny project with one library (paths shortened for readability):
javac -cp "libs/commons-lang3-3.21.0.jar" -d out src/main/java/com/example/*.java
java -cp "out;libs/commons-lang3-3.21.0.jar" com.example.ShoutOn Windows the class path separator is ;, on Linux and macOS it is :. Already a command that works on one teammate's laptop fails on another's. Now imagine the real case.
Why it does not scale
Count what a real project asks of you:
- Many libraries. A library often depends on other libraries (its own dependencies), which depend on others. A project with ten direct libraries can easily need dozens of JARs on the class path. You would list each one by hand.
- Manual downloads. You find each JAR on a website, download it, keep it in a folder, and copy that folder to every machine. You also have to check that two libraries do not want different versions of a third.
- Long, fragile commands. One missing path, one wrong separator, one forgotten source folder, and the build fails or, worse, builds the wrong thing.
- No repeatable steps. Compile, then compile the tests with the test library on the class path, then run the tests, then create the JAR: four commands that each person remembers a little differently.
- No shared truth. Which version of the library did the project use last month? The answer lives in somebody's download folder.
A shell script could hide some of this, but then every team writes its own scripts, and nobody can join a new team and know how its project builds.
What a build tool does
A build tool reads a description of the project and runs the build steps for you, in a fixed order, the same way on every machine. In recipe terms, the card is a file that lists the project's name, the Java version, the libraries it needs, and the steps. The assistant is the tool: it fetches the ingredients (downloads libraries) and follows the steps (compile, test, package).
That gives the two jobs from the lecture:
- Run the build steps (compile, test, package) with one short command.
- Manage dependencies: you write down which libraries you need, and the tool downloads them, and the libraries they need, from a public repository.
A bonus follows from these two: because the card is a file in the project, it is committed to Git like source code (module BEG-046), so a new teammate clones the project and builds it with the same command as everyone else.
Maven and Gradle
The two main build tools in the Java world are Apache Maven and Gradle. They solve the same problem with different styles: Maven describes the project in an XML file called pom.xml and follows fixed conventions, while Gradle uses a script file and is more flexible. This course uses Maven: it is very common in backend jobs, and its strict conventions are easier for a beginner to learn. Everything you learn about build tools transfers to Gradle.
Where the analogy stops
A real kitchen assistant understands what you want. A build tool only follows the card. If the card says the wrong library version, Maven will faithfully fetch the wrong one. The card is your responsibility, which is why the next lessons teach you to read and write it.
Examples
Example 1: one file, no problem (simple)
javac Hello.java
java HelloFor a single file with no libraries, javac is perfectly fine, and you do not need a build tool. The trouble starts when the project grows, not before.
Example 2: adding one library by hand (practical)
You want StringUtils.capitalize from Commons Lang. By hand you must:
- Find and download the right JAR (and check the version).
- Put it in a folder such as
libs/. - Add
-cp libs/commons-lang3-3.21.0.jarto the compile command. - Add the same JAR to the class path of the run command.
Real result of the run after that, with the correct class path:
Maven central works
cba(The first line comes from capitalize, the second from reverse("abc").) Four manual steps for one library. With Maven the same project has one block of text in a file, and mvn compile does steps 1 to 3 for you. The next lessons show that block.
Example 3: a ten-library project and a new teammate (realistic)
A team's service uses ten libraries. Maria downloaded them over several months. Omar joins, clones the repository, and finds that the project does not compile: three JARs are missing, and one he downloads is a newer version that changes a method name. It takes him a day to get a working setup. Later the team's automated server, which runs the tests on every change, needs the same setup as well, and someone has to maintain that by hand too.
With a build tool the repository contains the card. Omar types one command and gets the same compile, test, and package as Maria and the server.
Backend Insight
In backend work the build is not only a personal convenience. It is the same recipe used by:
- Teammates, so everyone builds the same way.
- Continuous integration servers, which run the build on every change to catch problems early.
- Deployment: the file that runs in production is usually the JAR the build produced.
Backend frameworks you will meet later assume a build tool: their documentation starts with "add this dependency to your build file". Being comfortable with it is a basic job skill.
Common Mistakes
Mistake 1: Believing a build tool replaces Java or the compiler
A build tool does not compile anything itself. Maven calls javac for you, plus the test runner and the JAR packer. It is the foreman, not the carpenter.
Mistake 2: Copying JARs into the project by hand "just this once"
- Incorrect: downloading a JAR from a random website and putting it in a
libsfolder. - Correct: declare the dependency in the build file so every machine fetches the same version from the same repository.
Mistake 3: Thinking "it runs in my IDE" means the build works
An IDE can hide missing steps with its own settings. The honest check is the command-line build on a clean machine, which is exactly the acceptance rule for this module's lab.
Mistake 4: Skipping the build tool because "my project is small"
Small projects grow. Learning the conventions early costs a few minutes; converting a large project later costs hours.
Exercises
Try each exercise yourself before opening the solutions.
Level A: Foundation
A1. Name the three steps of a build and say what each produces.
Show solution A1
A1. Compile (.class files from .java files), test (a pass or fail result for the automated tests), package (a JAR file bundling the classes).
A2. What is a dependency? Give an example from everyday Java (for example a library you could use to work with dates or JSON).
Show solution A2
A2. A dependency is a library your project uses and therefore needs at compile time or at run time. Examples: a JSON library, a date library, Commons Lang.
A3. Name two build tools for Java. Which one does this course use?
Show solution A3
A3. Maven and Gradle. This course uses Maven.
Level B: Application
B1. A teammate sends you this command and says "it works for me": javac -cp C:\libs\a.jar;C:\libs\b.jar .... Give two reasons it might fail on your machine.
Show solution B1
B1. The libraries may be in a different folder (or missing) on your machine, so the paths are wrong. The separator ; is for Windows only, so the command fails on Linux or macOS. A different version of a JAR in the same folder could also change behavior.
B2. In the recipe analogy, what is the card, what is the assistant, and what are the ingredients?
Show solution B2
B2. The card is the project's build file (the pom.xml in Maven). The assistant is the build tool. The ingredients are the libraries (dependencies) and the source files.
B3. Why is it useful that the build description is a file inside the project, rather than knowledge in a teammate's head?
Show solution B3
B3. Everyone, including new teammates and the automated server, reads and runs the same description, so the build is repeatable. The description is also committed to Git, so its history is tracked like code.
Level C: Challenge
C1. Write a short plan, in plain steps, of everything you would have to do by hand to build and run a project with three libraries and a test suite, with no build tool. Then circle the steps that depend on the operating system.
Show solution C1
C1. Example plan: (1) find and download three JARs and their own dependencies, (2) place them in a folder, (3) write the compile command with all JARs on the class path, (4) compile the main sources, (5) download the test library and its dependencies, (6) compile the tests with a class path that includes the test library, (7) run the tests with a test launcher and the class path, (8) read the results, (9) create the JAR with the jar tool. The class path separator and folder paths depend on the operating system (steps 3, 6, 7).
C2. A friend says: "I'll write a shell script instead of learning Maven." Give one thing the script solves, and two things that remain a problem.
Show solution C2
C2. The script repeats the steps in the same order. It does not download libraries or work out their own dependencies, so you still manage JARs by hand; and the script is written by you alone, so another team must learn your custom conventions instead of a standard one.
Mini Challenge
Take any small Java project you wrote earlier that uses JUnit (for example from module BEG-045). Write, on paper or in a text file, the list of every command a stranger would need to build it and run its tests from the terminal, assuming they only have a JDK installed. Mark each place where they would need to download something by hand. Keep the list: in the last lesson of this module you will replace it with a single command.
Check your work: the list mentions compiling the main code, compiling the tests with the JUnit JARs, running the tests, and at least one manual download.
Summary & Next Lesson
Key takeaways
- A build is compile, test, and package, plus fetching the libraries the project needs.
- Doing this by hand with
javacmeans long class paths, manual downloads, OS-specific commands, and steps nobody can repeat exactly. - A build tool runs the steps in a fixed order from a description file and manages dependencies for you.
- Maven and Gradle are the common Java build tools; this course uses Maven.
- The same build description serves you, your teammates, and the automated servers.
Next lesson
The next lesson, "Project structure and pom.xml", shows the folder layout Maven expects and teaches you to read the card itself: the pom.xml.
Self-check
- Name two jobs of a build tool.
- What is a dependency?
- Why does a manual
javaccommand often fail on a teammate's machine? - Does Maven replace
javac? - Why is "it runs in my IDE" not proof that the build works?
Show answers
- Running the build steps (compile, test, package) and fetching dependencies.
- A library that your project's code uses.
- Library paths, folder layout, and the class path separator differ between machines and operating systems.
- No. Maven calls
javac(and other tools) for you. - The IDE may rely on local settings or files; only a command-line build from a clean state proves that the project's build description is complete.
References
- Apache Maven, Introduction to the Build Lifecycle. Supports the description of compile, test, and package as ordered build steps carried out by plugins.
- Apache Maven, Introduction to the Dependency Mechanism. Supports the idea that Maven reads the POMs of your dependencies and brings in their own dependencies automatically (transitive dependencies).
- The
javacandjavaoutputs shown were produced on JDK 21 with Apache Commons Lang 3.21.0 in a scratch project. The statement that Gradle uses a script file and is more flexible, and the "popular in backend jobs" remark, are general background that I did not verify against a cited page.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.