zen and-the-art-of-build-script-maintenance

69
ZEN and the art of Build Script Maintenance An Inquiry into Build Automation Quality Tuesday, 22 June 2010

Upload: wakaleo-consulting

Post on 20-Aug-2015

2.294 views

Category:

Technology


0 download

TRANSCRIPT

ZENand the art of

Build Script Maintenance

An Inquiry into Build Automation Quality

Tuesday, 22 June 2010

John Ferguson SmartWakaleo Consulting

Web: http://www.wakaleo.comEmail: [email protected]: wakaleo

Tuesday, 22 June 2010

AgendaWhat are we discussing today?What makes a good build script?

Smelly build scripts

Choosing your tools

Maven tips

Ant tips

Tuesday, 22 June 2010

IntroductionQuality build scripts - why botherMaintenance costs

Learning curve

Turn-over

Portability

Automation

Tuesday, 22 June 2010

Build quality - quality buildsWhat makes a good build script?Gold Standard

Portable

Reproducible

Standard

Maintainable

Tuesday, 22 June 2010

Build quality - quality buildsGold StandardReference build process

Reference binaries

Tuesday, 22 June 2010

Build quality - quality buildsPortableRuns anywhere

Runs on any OS

No local dependencies

Environment-specific configurations

Specially-installed software or databases

...

Tuesday, 22 June 2010

Build quality - quality buildsReproducible“Play it again, Sam”

Tuesday, 22 June 2010

Build quality - quality buildsStandardKnowing what to expect

Tuesday, 22 June 2010

Build quality - quality buildsMaintainableThink of the next dude

Tuesday, 22 June 2010

Smelly buildsSo what makes a poor build script?

1) The hard coded build

2) The OS-specific build

3) The IDE-only build

4) The Magic Machine build

5) The Oral Tradition build

6) The Nested build

7) The Messy Dependencies build

8) The DYI build

9) The untrustworthy build

10) The slow build

Tuesday, 22 June 2010

Smelly buildsThe hard coded build

C:/bea/weblogic-9.1/..

Paths

http://testserver.acme.com:7001

URLs

<svn username="scott" password="tiger"...>Passwords

<property name="dir.jboss" value="${env.JBOSS_HOME}"/>

Environment variables

Tuesday, 22 June 2010

Smelly buildsThe hard coded build

<target name="checkstyle">

<delete dir="./reports" quiet="true" /> <mkdir dir="./reports" /> <checkstyle config="./docs/sun_checks.xml"> <formatter type="xml" tofile="./reports/checkstyle.xml"/> <fileset dir="./src" includes="**/*.java"/> </checkstyle>

<style in="./reports/checkstyle.xml" out="./reports/checkstyle.html" style="checkstyle.xsl"/>

</target>

Hard-coded directories

Tuesday, 22 June 2010

Smelly buildsThe hard coded build

<target name="checkstyle">

<delete dir="./reports" quiet="true" /> <mkdir dir="./reports" /> <checkstyle config="./docs/sun_checks.xml"> <formatter type="xml" tofile="./reports/checkstyle.xml"/> <fileset dir="./src" includes="**/*.java"/> </checkstyle>

<style in="./reports/checkstyle.xml" out="./reports/checkstyle.html" style="checkstyle.xsl"/>

</target>

<property name=”reports.checkstyle.dir” value=”${basedir}/reports”/>

<target name="checkstyle"> <delete dir="${reports.checkstyle.dir}" quiet="true" /> <mkdir dir="${reports.checkstyle.dir}" /> <checkstyle config="./docs/sun_checks.xml"> <formatter type="xml" tofile="${reports.checkstyle.dir}/checkstyle.xml"/> <fileset dir="./src" includes="**/*.java"/> </checkstyle>

<style in="${reports.checkstyle.dir}/checkstyle.xml" out="${reports.checkstyle.dir}/checkstyle.html" style="checkstyle.xsl"/>

</target>

Project-relative directory

DRY

Tuesday, 22 June 2010

Smelly buildsThe hard coded build

<property environment="env"/><property name="dir.jboss" value="${env.JBOSS_HOME}"/>

Environment variable

Tuesday, 22 June 2010

Smelly buildsThe OS-specific build

<exec command="grep \"@\" ${build.dir} | wc -l" outputproperty="token.count"/>

Tuesday, 22 June 2010

Smelly buildsThe OS-specific build

...CALL PAUSE.CMD...

build.cmd

...:: Check for a non-existent IP address:: Note: this causes a small extra delay!IF NOT DEFINED NonExist SET NonExist=10.255.255.254PING %NonExist% -n 1 -w 100 2>NUL | FIND "TTL=" >NUL...

pause.cmd

Tuesday, 22 June 2010

Smelly buildsThe IDE-only build

Tuesday, 22 June 2010

Smelly buildsThe Magic Machine build

Directories

App servers

Databases

Configuration files

Environment variables

Installed software or tools

Tuesday, 22 June 2010

Smelly buildsThe Magic Machine build

Directories

App servers

Databases

Configuration files

Environment variables

Installed software or tools

<proprerty weblogic.dir="/u01/app/bea/weblogic-9.1"/>

Tuesday, 22 June 2010

Smelly buildsThe Oral Tradition build

Tuesday, 22 June 2010

Smelly buildsThe Nested Build

#! /bin/shANT_HOME=/u01/app/tools/ant-1.7.1...$ANT_HOME/ant $1project/tools/ant.sh

Tuesday, 22 June 2010

The Messy Dependencies buildJAR files in the SCM

Unversioned JAR files

Unclear dependencies

Smelly builds

Tuesday, 22 June 2010

The DYI build“Not invented here”

DYI dependencies

DYI deployments

DYI Maven releases

...

Smelly builds

Tuesday, 22 June 2010

Smelly buildsThe untrustworthy build<junit fork="yes" haltonfailure="false" dir="${basedir}"> <classpath refid="test.class.path" /> <classpath refid="project.class.path"/> <formatter type="plain" usefile="true" /> <formatter type="xml" usefile="true" /> <batchtest fork="yes" todir="${logs.junit.dir}"> <fileset dir="${test.unit.dir}"> <patternset refid="test.sources.pattern"/> </fileset> </batchtest></junit>

Tuesday, 22 June 2010

Smelly buildsThe slow build

Tuesday, 22 June 2010

Choosing your toolsFlexibility verses ConventionWhat’s better: flexibility or standards?

It depends what you’re doing...

Tuesday, 22 June 2010

Choosing your toolsStandards and Conventions

No standards

Make up your own standards

Support standards

Encourage/enforce standards

Standards and ConventionsAd-hoc scripting

Eas

y to

rea

dH

ard

to

rea

d

23

Tuesday, 22 June 2010

Choosing your toolsFlexibility and expressiveness

Eas

y to

rea

dH

ard

to

rea

d

Easy to do whatever you wantMakes you stick to conventions

3

Encourage/enforce standards

Do whatever you want

2

Tuesday, 22 June 2010

Choosing your toolsFlexibility verses ConventionBuild Scripting Rule 1

“A build script will tend to reflect the personality of it’s developer”

Tuesday, 22 June 2010

Choosing your toolsFlexibility verses ConventionBuild Scripting Rule 2

“The more flexible a build script, the more likely it is to become unmaintainable”

Tuesday, 22 June 2010

Choosing your toolsFlexibility verses ConventionFlexibility is great for some jobs:

Ad-hoc tasks

Some deployment tasks

“Out-of-the-box” stuff

Tuesday, 22 June 2010

Choosing your toolsFlexibility verses ConventionBut convention pay off in lower maintenance costs

Tuesday, 22 June 2010

Ant tipsBetter Ant scriptsConsistent conventions

Declare your dependencies

Make it readable

Tidy up your mess

Avoid long scripts

Tuesday, 22 June 2010

Ant tipsBe consistent

Standardize target names

Document your public targets

Tuesday, 22 June 2010

Ant tipsDeclare your dependencies

Use an Enterprise Repository Manager

Several tool choices:

Maven Ant Tasks

Ivy

Tuesday, 22 June 2010

Ant tipsUsing the Maven Ant Tasks

Declare dependencies

Deploy to a Maven Enterprise Repository

<artifact:dependencies pathId="dependency.classpath"> <dependency groupId="junit" artifactId="junit" version="3.8.2" scope="test"/> <dependency groupId="javax.servlet" artifactId="servlet-api" version="2.4" scope="provided"/></artifact:dependencies>

Tuesday, 22 June 2010

Ant tipsMake it readable

Write a build script like your source code...

Avoid long targets

Avoid long build scripts

Use descriptive target names

Tuesday, 22 June 2010

Ant tipsTidy up your mess

Always define a ‘clean’ target.

Tuesday, 22 June 2010

Ant tipsMove to Maven ;-)

Tuesday, 22 June 2010

Maven tipsBetter Maven scriptsSimple

Portable

Reproducible

Clean

Automated

Tuesday, 22 June 2010

Maven tipsKeep it simpleUse modules

Use an organization-level POM

Tuesday, 22 June 2010

Maven tipsKeep it portableNo hard-coding

Define sensible defaults for properties and profiles

Avoid resource filtering for production code

Tuesday, 22 June 2010

Maven tipsKeep it reproducibleAvoid external snapshots

Specify plugin versions

Use consistent environments

Tuesday, 22 June 2010

Maven tipsConsistent environmentsEnforcing a minimum Maven version

<?xml version="1.0"?><project...> <modelVersion>4.0.0</modelVersion> <groupId>com.ciwithhudson.gameoflife</groupId> <artifactId>gameoflife</artifactId> <version>0.0.1-SNAPSHOT</version> <name>gameoflife</name> <prerequisites> <maven>2.2.1</maven> </prerequisites>

Minimum Maven version

Tuesday, 22 June 2010

Maven tipsConsistent environmentsUse the same version of Maven

Use a “standard” Maven installation across the organization

Use a global settings.xml file

Store a copy in SCM

Enforce a minimum Maven version in your projects

Tuesday, 22 June 2010

Maven tipsEnforcing consistency with the enforcer pluginMaven version

JDK version

Snapshots

Plugin versions

OS

...

Tuesday, 22 June 2010

Maven tipsEnforce the Maven version

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-beta-1</version> <executions> <execution> <id>enforce-maven-version</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireMavenVersion> <version>2.2.1</version> </requireMavenVersion> </rules> </configuration> </execution> </executions> </plugin>

Minimum Maven version

Tuesday, 22 June 2010

Maven tipsEnforce the JDK versionAll developers should be using the same JDKs

Incompatible bytecode

Different XML parsers

Different Maven behaviour

Tuesday, 22 June 2010

Enforce the JDK version

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-beta-1</version> <executions> <execution> <id>enforce-jdk-version</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireJavaVersion> <version>[1.5.0,1.6.0)</version> </requireJavaVersion> </rules> </configuration> </execution> </executions> </plugin>

Maven tips

Authorized JDK versions

Tuesday, 22 June 2010

Maven tipsSpecify your plugin versionsUndeclared version numbers are bad

Inconsistent builds across different machines

Non-repeatable builds

Plugin changes can break the build

Don’t use SNAPSHOT plugins either

Tuesday, 22 June 2010

Specify your plugin versions

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-beta-1</version> <executions> <execution> <id>enforce-versions</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requirePluginVersions/> </rules> </configuration> </execution> </executions> </plugin>

Maven tips

Plugin versions must be defined

Tuesday, 22 June 2010

Maven tipsKeep it cleanKeep tabs on your dependencies:

What dependencies are you actually using?

What dependencies do you really need?

Tuesday, 22 June 2010

Maven tipsDependency list What dependencies are you actually using?$ mvn dependency:list[INFO] Scanning for projects...[INFO] Searching repository for plugin with prefix: 'dependency'.[INFO] ------------------------------------------------------------------------[INFO] Building babble-core[INFO] task-segment: [dependency:list][INFO] ------------------------------------------------------------------------[INFO] [dependency:list][INFO] [INFO] The following files have been resolved:[INFO] antlr:antlr:jar:2.7.6:compile...[INFO] commons-collections:commons-collections:jar:2.1.1:compile[INFO] commons-logging:commons-logging:jar:1.0.4:compile[INFO] dom4j:dom4j:jar:1.6.1:compile[INFO] javax.persistence:persistence-api:jar:1.0:compile[INFO] javax.transaction:jta:jar:1.0.1B:compile[INFO] junit:junit:jar:4.5:test[INFO] net.sf.ehcache:ehcache:jar:1.2:compile[INFO] org.hamcrest:hamcrest-all:jar:1.1:compile[INFO] org.hibernate:hibernate:jar:3.2.0.ga:compile[INFO] org.hibernate:hibernate-annotations:jar:3.2.0.ga:compile[INFO] [INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESSFUL[INFO] ------------------------------------------------------------------------

mvn dependency:list

Tuesday, 22 June 2010

Maven tipsDependency tree Where do they come from?$ mvn dependency:tree[INFO] Scanning for projects...[INFO] Searching repository for plugin with prefix: 'dependency'.[INFO] ------------------------------------------------------------------------[INFO] Building babble-core[INFO] task-segment: [dependency:tree][INFO] ------------------------------------------------------------------------[INFO] [dependency:tree][INFO] com.sonatype.training:babble-core:jar:1.0-SNAPSHOT[INFO] +- org.hibernate:hibernate:jar:3.2.0.ga:compile[INFO] | +- net.sf.ehcache:ehcache:jar:1.2:compile[INFO] | +- javax.transaction:jta:jar:1.0.1B:compile[INFO] | +- commons-logging:commons-logging:jar:1.0.4:compile[INFO] | +- asm:asm-attrs:jar:1.5.3:compile[INFO] | +- dom4j:dom4j:jar:1.6.1:compile[INFO] | +- antlr:antlr:jar:2.7.6:compile[INFO] | +- cglib:cglib:jar:2.1_3:compile[INFO] | +- asm:asm:jar:1.5.3:compile[INFO] | \- commons-collections:commons-collections:jar:2.1.1:compile[INFO] +- org.hibernate:hibernate-annotations:jar:3.2.0.ga:compile[INFO] | \- javax.persistence:persistence-api:jar:1.0:compile[INFO] +- junit:junit:jar:4.5:test[INFO] \- org.hamcrest:hamcrest-all:jar:1.1:compile[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESSFUL[INFO] ------------------------------------------------------------------------

mvn dependency:tree

Tuesday, 22 June 2010

Maven tipsDependencies in EclipseEclipse has an equivalent screen

Tuesday, 22 June 2010

Maven tipsDependency analyse What dependencies do you really need?$ mvn dependency:analyze[INFO] Scanning for projects...[INFO] Searching repository for plugin with prefix: 'dependency'.[INFO] ------------------------------------------------------------------------[INFO] Building babble-core[INFO] task-segment: [dependency:analyze][INFO] ------------------------------------------------------------------------[INFO] Preparing dependency:analyze...[INFO] [dependency:analyze][WARNING] Used undeclared dependencies found:[WARNING] javax.persistence:persistence-api:jar:1.0:compile[WARNING] Unused declared dependencies found:[WARNING] org.hibernate:hibernate-annotations:jar:3.2.0.ga:compile[WARNING] org.hibernate:hibernate:jar:3.2.0.ga:compile[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESSFUL[INFO] ------------------------------------------------------------------------

mvn dependency:analyse

Used but not declared

Declared but not used

Tuesday, 22 June 2010

Maven tipsExcluding dependenciesWhat if you don’t want a dependency? <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.5.5</version> <exclusions> <exclusion> <groupId>javax.jms</groupId> <artifactId>jms<artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-jms_1.1_spec</artifact> <version>1.1</version> </dependency> <dependencies>

Don’t include JMS

Tuesday, 22 June 2010

Maven tipsStandardizing versionsUse dependencyManagement for consistency

<dependencyManagement> <dependencies> <dependency> ! <groupId>mysql</groupId> ! <artifactId>mysql-connector-java</artifactId> ! <version>5.1.6</version> </dependency> <dependency> ! <groupId>postgres</groupId> ! <artifactId>postgres</artifactId> ! <version>7.3.2</version> </dependency> </dependencies></dependencyManagement>

<dependencies> <dependency> !<groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency></dependencies>

Parent pom

Child pom

Tuesday, 22 June 2010

Maven tipsKeep it automatedPlan your release strategy

Use a Repository Manager

Automatic snapshot deployments

Automated releases

Tuesday, 22 June 2010

Maven tipsMaven best practices for CI buildsUse batch mode (-B)

Always check or snapshot updates (-U)

Use a repository per project

Print test failures to stdout (-Dsurefire.useFile=false)

Tuesday, 22 June 2010

Maven tipsKnow when to script itGroovy or Ant scripting is easy in Maven

Call external scripts when appropriate

Tuesday, 22 June 2010

Maven tipsKnow when to script itIt’s pretty easy in Maven 2...<project> <build> <plugins> <plugin> <groupId>org.codehaus.groovy.maven</groupId> <artifactId>gmaven-plugin</artifactId> <version>1.0-rc-5</version> <executions> <execution> <phase>compile</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> println "Hi there I’m compiling ${project.name}" </source> </configuration> </execution> </executions> </plugin> </plugins> </build> ...

Tuesday, 22 June 2010

Maven tipsKnow when to script itIt’s even easier in Maven 3...project { build { $execute(id: 'compilation-script', phase: 'compile') { println "Hi there I’m compiling ${project.name}" } $execute(id: 'validation-script', phase: 'validate') { println "Hi there I’m validating ${project.name}" } ... }}

Tuesday, 22 June 2010

Thank You

John Ferguson SmartWakaleo Consulting

Web: http://www.wakaleo.comEmail: [email protected]: wakaleo

Tuesday, 22 June 2010