Wednesday, December 25, 2013

Maven is mysterious, but not in an alluring way

If you work with java, you probably used, struggled with and cursed the existence of maven.  Some love it, many despise it and both sides have good reasons for those opinions.  Maven automates build and release processes using a "simple" configuration to drive complex actions of compilation, packaging, testing and collection of all manner of health stats.   Maven's convention over configuration mindset increases understanding for all builds via common idioms enabling me to step into any maven build and quickly understand the workings.  It also creates a steep Everest styled learn curve.  Maven carries out its work via plugins and some with excellent documentation acting as how-to Sherpas and others that feel like an ice wall with few hand holds and a long drop.

Getting Under The Hood

When faced with a maven "that's not supposed to happen" problem, the spartan nature of maven's project object module (pom) files doesn't show why maven configured a classpath without an essential library or created an empty distribution zip file.  Perhaps, if we knew the convention really well, it would be obvious.  However, making me feel stupid probably isn't maven's design goal so we've got tools to shed light our problem:
  • Effective Pom
  • Debug output "-X"
  • Source code for the plugin


Effective Pom - Discovering Maven's Intent

Prior to building, maven combines your project's pom with its ancestor poms and the default super pom.  We can generate this effective pom and use it to see all the properties and set configuration options.
  
  mvn help:effective-pom  > epom.txt

Maven supports grouping configuration settings into build profiles.  You can activate profiles for any maven command by adding "-P profileId" to the command.  For example, you may have a distribution profile which copies additional content to create an installer.  We'd generate the effective pom thus to capture all of that distribution goodness:
  
  mvn -P distribution help:effective-pom  > epom.txt

The command activates "distribution" profile and runs the "effective-pom" goal for "help" plugin.  Plugins provide goals which maven executes at build time.  You can execute goals for plugins manually by adding <plugin>:<goal> to the command line.

The effective-pom resolves all properties and shows executions of plugin goals.  This information can point to why maven didn't behave as expected and enable you to review pom ancestry to see where a value was set or what properties you need to enable to change build execution.


Debug - Discovering What Maven's Up To

Adding "-X" to a maven command switches on a torrent of debug messages.  Maven produces way too much information but we can tame the flood thus:
  1. Run maven command using standard debugging a direct output to a file:
    mvn install > mvn.log
  2. Run command with debug and direct output to a file:
    mvn -X install > debug.log
  3. Find the area of interest in mvn.log and locate a nice unique looking string 
  4. Search for that string in the debug.log.  Scan back and forward to tease out:
    • Additional properties which control behavior
    • Full text of the command line invocation (e.g., javac tool compiles java source into byte code and debug output shows all options, environment variables and classpath settings  - except when it doesn't)


Review source code for the plugin

Stop: 
If you've got this far you either face a massive challenge or should reconsider your approach.  Extreme difficulty can indicate time for me to rethink my strategy.  Great challenges and/or wrong headed attempts are best done after a short walk, cup of coffee or some other way to disengage mentally.  The re-coupling of my mind to the problem may result in an insight that allows me to side step the intractable problem.

The majority of maven plugins generate a maven web site with documentation and source downloads.  You can download the source, import it into eclipse via  m2e and take a walk through it looking for some of those keyword or properties found in the debug log.  I found this necessary to understand the maven-native-plugin's use of environment and registry settings for windows compilers.  I didn't discover a bug, but I did learn how the plugin interacted with Microsoft tools and eventually found the proper environment variables to set


Afterthoughts

Maven does a good job of providing standard ways to handle build and release complexity.  In the simple case, maven reduces duplication and needless wheel reinvention.  Debug and effective pom help us to crack open maven's encapsulation and deepen our understanding of the problem.   Reading up on maven helped me to better understand the nuances of the convention.


Finally, I create tiny maven projects via maven quickstart archetype so I can test theories.  I work on 100+ project multi-module builds with many plugins and much custom build logic.  If I need to explore how a plugin functions, I want the simplest and quickest environment in which to test.  I can either select a simple project within main build or create a tiny quickstart build.  I want the time from idea to result as short as possible.  A 5 minute loop per idea provides less chances to tinker than a 20 second loop.   I try to choose the path that seems the simplest to create and then iterate through the problem.

I hope this was of use to you.


Note to Maven Haters:

Check out gradle for it holds great promise of combining maven benefits with greater ease of understanding and a nice domain specific language approach.  I'm still getting my head wrapped around it.

No comments:

Post a Comment