This is the presentation I gave in Java.IL at June 19th 2016.
It's targeted for people who have some experience with Maven and want to learn some of the inner workings and how to be more effective with it.
3. What’s it like without a build tool
Part 1 – Build Tools
1.javac -cp ./lib/guava-16.0.jar –d ./target ./src
2.jar cf myService.jar ./target
4. What’s it like without a build tool
Part 1 – Build Tools
But where did those 3rd party jars come from?
And what if I also want to test my code??
And what if I have several modules???
Maybe like 500…
And if my modules depend on each
other????
5. Part 1 – Build Tools
This can get very frustrating, very fast!
6. Some Build tools
Part 1 – Build Tools
C, C++ - Make
Scala - SBT
JavaScript - Grunt, Bower
Java - Ant + Ivy, Maven, Gradle
9. A Dependency Manager
Part 2 - Maven
• Handles internal and external dependencies
• Local cache ~/.m2
• Provides dependencies for compilation and tests
• Maven central includes most common dependencies
guava-13.0
Image Fetching
Service
Images Rest
API
Internal
External
10. A Plugin Execution Framework
Part 2 - Maven
• Executes plugins sequentially
• There are plugins for compilation, testing, creating
jars
11. Maven’s Lifecycles
Part 2 - Maven
A lifecycle is a collection of phases
• clean – Cleaning up stuff…
• site – Creating the project’s site
• deploy – The one you all know and love
12. Phases
Part 2 - Maven
A lifecycle is composed of phases
• clean – A single phase called clean
• deploy – Several phases deploy lifecycle phases
validate
compile
test
package
verify
install
deploy
mvn install
13. Plugins and Goals
Part 2 - Maven
• Plugin examples
• maven-compiler-plugin
• maven-jar-plugin
• To run a plugin - mvn <PluginName>:<Goal>
mvn dependency:tree
maven-dependency-plugin
tree analyze
unpack
15. The Execution Pipeline
Part 2 - Maven
Phases
Plugins & Goals
compile test package
maven-jar-plugin
jar
maven-compiler-plugin
compile
maven-surefire-plugin
test
16. More Than One Plugin In a Phase
Part 2 - Maven
package
maven-jar-plugin
jar
maven-assembly-plugin
tar
18. POM
Part 3 – The POM
• It’s an XML file (ouch!)
• Contains project identifier
GAV - groupId:artifactId:version (com.outbrain:ob1k:1.0.1)
• Build info - steps to run during the build
• Dependencies - the “needs” of my project
• Inheritable
20. The Super POM
Part 3 – The POM
• Ancestor of all POMs, contains defaults
• Used directories (sources, resources, target)
• Plugin versions
• Maven central repository for downloading dependencies
(junit, hibernate, spring etc.)
24. Dependency Conflicts
Part 3 – The POM
guava-13.0 guava-18.0
Image Fetching
Service
Image Resize
Service
Images Rest
API
Images DAL Image Sizes
DAL
25. The dependencyManagement Section
Part 3 – The POM
• Defines dependencies’ versions in a centralized
location
• Helps avoid version conflicts – as long as all child
modules never declare a version
Dependency management Child module
26. The build Section
Part 3 – The POM
• Build enrichment using plugins for
• Compiling other languages
• Creating different types of archives
27. IntelliJ Integration
Part 3 – The POM
• IntelliJ can convert the POM into its own project
model
• Re-import rebuilds IntelliJ’s model
• Completely unrelated to mvn clean install
29. Command Line Options
Part 4 – In Practice
• -pl - build specific project(s)
mvn clean install -pl ImageFetchingService,ImageSizesService
• -am - also build project’s dependencies
mvn clean install -pl ImageFetchingService -am
• -amd - also build dependent projects
mvn clean install -pl ImageFetchingService -amd
• -T – parallel build
mvn clean install -T 1C
• -X – Debug level logging
Image Fetching
Service
Image Resize
Service
Images Rest
API
Images DAL Image Sizes
DAL
30. Running Tests
Part 4 – In Practice
• Run all tests
mvn test
• Run a specific test
mvn test -Dtest=<ClassName>#<TestMethod>
• http://maven.apache.org/surefire/maven-surefire-plugin/index.html
deploy lifecycle phases
validate
compile
test
package
verify
install
deploy
31. Unused Dependencies
Part 4 – In Practice
• The risk of a version conflict increases
• Your applications will become bigger for no reason
• It’s harder to separate projects
32. maven-dependency-plugin
Part 4 – In Practice
• mvn dependency:tree -pl <ModuleName> -Dverbose
• mvn dependency:analyze -pl <ModuleName>
• Other useful goals
• copy-dependencies
• unpack
• http://maven.apache.org/plugins/maven-dependency-plugin/
33. Dependency Conflicts
Part 4 – In Practice
Image Fetching
Service
Image Resize Service
Images Rest API
guava 13.0 guava 18.0
36. Some Points of Difference
Part 5 - Gradle
• Learning curve – Maven is easier
• Flexibility – Gradle’s strength, it’s easier to define
custom behavior.
• Features – incremental building, in-script logging,
self-documenting tasks (gradle tasks)
Editor's Notes
Welcome to the Embrace Maven session.
This presentation is for people who are using maven and want to learn a little more about it in order to be more effective with it.
Yiddish for “מבין”
At the time Maven was created, Ant was the most popular build tool. It was very verbose and it didn’t even have dependency management
Maven’s philosophy - Convention over configuration = reasonable default behavior. A project that has no special needs can be very easily created. Just put your code under src/main/java and your tests under src/test/java etc.. By doing only that with a pom file you get a project that compiles, tests and packages itself.
Opinionated means
There’s a way to do stuff
Doing stuff the wrong way has consequences
Three built-in lifecycles - clean, deploy and site
Clean has to do with cleaning stuff up (duh) – basically deletes your target folder
Site creates the project’s site – htmls, test reports, javadoc
Deploy is the lifecycle we’re using most of the time (compilation, testing etc.)
Clean – has a single phase that cleans the target folder
There are 8 phases in the deploy lifecycle, among them:
compile - compiles java files and puts the classes file under target/classes (maven-compiler-plugin)
tests - runs unit tests (surefire-plugin)
package - creates a jar file, or any other configured package (maven-jar-plugin)
install - installs the packages into the local repository (maven-install-plugin)
Phases are additive so running mvn install will run all phases up to and including the install phase
A plugin is a collection of goals
The maven-dependency-plugin contains several goals, amongst them tree, analyze and unpack
Other plugin examples – maven-compiler-plugin, maven-jar-plugin
This is how you run a plugin with Maven...
Convention over configuration here – most phases have by default plugins that are bound to them
I mentioned that plugins “bind” to a phase, here’s what it looks like during maven’s execution
POM stands for Project Object Model.
The pom contains all info related to the project
What to build
When to do it
Where should the artifacts be located
It’s an XML file – back then XML was considered cool
GAV - The unique identifier of the module. If a module is to be used by another one this is how you would reference it.
Build info - what steps should run during the build, and at what order
Dependencies needed in order to compile the project, test it and run it
The data in the pom can be used by inheriting poms
Here’s a sample project
It has one parent projects and two children that inherit from it
Father of all poms, contains defaults
Used directories (sources, resources, target)
Plugin versions
Maven central repository link
Gav + packaging (Default packaging is JAR)
Properties – key-value items
Dependencies – my project’s needs
Dependency management
Build – plugins to run during the build
Dependencies are what the project needs in order to be compiled tested or run
A dependency is added by adding its GAV to the dependencies section
Dependencies can be scoped according to those needs. Compile is the default scope
Imaginary app…
What happens if the two services depend on conflicting versions of guava?
Maven has a lot of plugins available for many many purposes
Why are superfluous dependencies bad for you?
Because of what’s written above.
This is very important for open-source writers and in general people who release libraries for other people’s usage. You can keep your room filthy, but keep your living room spotless
You don’t want your lib to be the cause for dependency conflicts
dependency:tree – you can see what dependencies you have and where they came from. If you also want to see dependencies that maven did not take you should use –Dverbose
Maven’s way to resolve conflicts is to avoid them - the dependency closest to the built module wins, and if there are two dependencies the same distance the first one declared wins.
If you’re lucky nothing has changes between the versions and everything will work.
If you’re less lucky you’ll get a compilation error (That’s if WebServer is using a transitive dependency of Guava).
If you’re less lucky - it will fail in tests with a NoClassDefFoundError
Even less lucky - it will fail in runtime.
Worst luck - implementation has changed and you’ll get bugs and not know why :(
It’s even possible for something in ImageFetchingService/ImageResizeService to break when running in the context of WebServer because the actual guava version in the classpath is different than the one they were tested with.
That’s why it’s best to use dependency management and have uniform versions.
Learning curve - Gradle is harder to learn. Probably any maven project you clone from github will be compiled by mvn clean install. Gradle is easier to add behavior to which means a person needs to learn your company’s comventions.
Flexibility – adding behavior is very easy in gradle, you simply write a task inside the gradle file. For maven it’s either a new plugin or using ant or groovy plugins. Remember maven is opinionated
Features
Incremental building – Gradle’s is better. It recognized when the inputs/configuration of a task changed and executes that task
Gradle files are code, you can just add logging inside
gradle tasks – shows you the available tasks to run