SlideShare ist ein Scribd-Unternehmen logo
1 von 71
Downloaden Sie, um offline zu lesen
Who is this guy, anyway?
John Ferguson Smart
Consultant, Trainer, Mentor, Author, Speaker
Specialities:
 Java, Groovy/Grails
 Software Development Lifecycle
 Agile stuff (CI, TDD, BDD,...)
 Open Source
Agenda
What are we discussing today?
What makes a good build script?
Smelly build scripts
Choosing your tools
Maven tips
Ant tips
Introduction
Quality build scripts - why bother
Maintenance costs
Learning curve
Turn-over
Portability
Automation
Build quality - quality builds
What makes a good build script?
Gold Standard
Portable
Reproducible
Standard
Maintainable
Build quality - quality builds
Gold Standard
Reference build process
Reference binaries
Build quality - quality builds
Portable
Runs anywhere
Runs on any OS
No local dependencies
 Environment-specific configurations
 Specially-installed software or databases
 ...
Build quality - quality builds
Reproducible
“Play it again, Sam”
Build quality - quality builds
Standard
Knowing what to expect
Build quality - quality builds
Maintainable
Think of the next dude
Smelly builds
 So 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
Paths
                                                                       ..
                                                                    1/




                                                                            URLs
Smelly builds




                                                                  9.
                                                               c-
                                                             gi
                                                          lo




                                                                                               1
                                                        eb




                                                                                            00



                                                                                                           Passwords
                                                     /w




                                                                                         :7
                                                                                      om
                                                   ea




                                                                                   .c
                                               /b




                                                                                me
                                              C:




                                                                             ac
                                                                          r.
                                                                       ve
                                                                    er
                                                                 ts
                                                              es                                               .>
                                                           /t                                              "..
                                                        :/                                             ger
                                                                                                  "ti
                                                     tp                                       rd=
                The hard coded build




                                                  ht                                     swo
                                                                                   pas
                                                                            tt"
                                                                       sco
                                                                  e="
                                                            nam
                                                      ser
                                                  n u
                                              <sv
                                                                                                                            />
                                                                                                                     M E }"
                                                                                                                S_HO
                                                                                                           JBOS
                                                                                                      env.
                                                                                               = "$ {
                                                                                       alue
                                                                                s" v




                                                                                                         Environment
                                                                        jbos
                                                                 dir.
                                                          me="




                                                                                                          variables
                                                   y na
                                              pert
                                       <pro
Smelly builds
The hard coded build

<target name="checkstyle">
                                           Hard-coded directories
  <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>
Smelly builds
    The hard coded build

    <target name="checkstyle">                Project-relative directory
<property name=”reports.checkstyle.dir”
      <delete dir="./reports" quiet="true" />
          value=”${basedir}/reports”/>
      <mkdir dir="./reports" />                         DRY
      <checkstyle config="./docs/sun_checks.xml">
<target name="checkstyle">
        <formatter type="xml" tofile="./reports/checkstyle.xml"/>
  <delete dir="${reports.checkstyle.dir}" quiet="true" />
  <mkdir<fileset dir="./src" includes="**/*.java"/>
         dir="${reports.checkstyle.dir}" />
      </checkstyle>
  <checkstyle config="./docs/sun_checks.xml">
    <formatter type="xml"
      <style in="./reports/checkstyle.xml"
                tofile="${reports.checkstyle.dir}/checkstyle.xml"/>
    <fileset out="./reports/checkstyle.html"
             dir="./src" includes="**/*.java"/>
             style="checkstyle.xsl"/>
  </checkstyle>

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

</target>
Smelly builds
    The hard coded build
<target name="war" >
  <war destfile="c:/tomcat/jakarta-tomcat-5.0.19/webapps/app.war"
       webxml="${src}/app.xml" basedir="${bin}" />
</target>


                  Hard-coded directories
Smelly builds
    The hard coded build
<property name="wardir"
          location="c:/tomcat/jakarta-tomcat-5.0.19/webapps"/>

<target name="war" >
  <war destfile="${wardir}" webxml="${src}/app.xml"
       basedir="${bin}" />
</target>
                  Still hard-coded
Smelly builds
   The hard coded build




<svn username="scott" password="tiger">
  <checkout url="http://subversion.acme.com/myapp/trunk"
            destPath="${subproject.dir}" />
</svn>

       Hard-coded username/password
Smelly builds
The hard coded build




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




                         Environment variable
Smelly builds
The OS-specific build


<exec command="grep "@" ${build.dir} | wc -l"
      outputproperty="token.count"/>
Smelly builds
The 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.254
  PING %NonExist% -n 1 -w 100 2>NUL | FIND "TTL=" >NUL
  ...
    pause.cmd
Smelly builds
The IDE-only build
Smelly builds
The Magic Machine build



                                         Directories

                           App servers


                Databases


       Configuration files


Environment variables


Installed software or tools
Smelly builds
The Magic Machine build


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

                                         Directories

                           App servers


                Databases


       Configuration files


Environment variables


Installed software or tools
Smelly builds
The Oral Tradition build
Smelly builds
The Nested Build

#! /bin/sh
ANT_HOME=/u01/app/tools/ant-1.7.1
...
$ANT_HOME/ant $1
project/tools/ant.sh
Smelly builds
   The Nested Build

<target name="build-subproject">
  <svn username="scott" password="tiger">
    <checkout url="http://subversion.acme.com/someproject/trunk"
              destPath="${subproject.dir}" />
  </svn>

  <ant dir="${subproject.dir}" target="build-all" />
</target>
build.xml
Smelly builds
The Messy Dependencies build
JAR files in the SCM
Unversioned JAR files
Unclear dependencies
Smelly builds
The DYI build
“Not invented here”
DYI dependencies
DYI deployments
DYI Maven releases
...
Smelly builds
The 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>
Smelly builds
The slow build
Choosing your tools
Flexibility verses Convention
What’s better: flexibility or standards?
It depends what you’re doing...
Choosing your tools
                                                                  Encourage/enforce

       Standards and Conventions              Support standards
                                                                      standards


                                                                                      3
Easy to read




                                                                                      2
                              Make up your
                              own standards




               No standards
Hard to read




Ad-hoc scripting                                      Standards and Conventions
Choosing your tools
         Flexibility and expressiveness
                                          3                      Do whatever you
  Easy to read



                                                                      want


                         2
                 Encourage/enforce
                     standards
  Hard to read




Makes you stick to conventions                Easy to do whatever you want
Choosing your tools
Flexibility verses Convention
Build Scripting Rule 1
    “A build script will tend to reflect the personality of
                        it’s developer”
Choosing your tools
Flexibility verses Convention
Build Scripting Rule 2
     “The more flexible a build script, the more likely it
             is to become unmaintainable”
Choosing your tools
Flexibility verses Convention
Flexibility is great for some jobs:
 Ad-hoc tasks
 Some deployment tasks
 “Out-of-the-box” stuff
Choosing your tools
Flexibility verses Convention
But too much flexibility is hard to maintain
Ant tips
Better Ant scripts
Consistent conventions
Declare your dependencies
Make it readable
Tidy up your mess
Avoid long scripts
Ant tips
Be consistent
Standardize target names
Document your public targets
Ant tips
Declare your dependencies
Use an Enterprise Repository Manager
Several tool choices:
 Maven Ant Tasks
 Ivy
Ant tips
 Using 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>
Ant tips
Make it readable
 Write a build script like your source code...
 Avoid long targets
 Avoid long build scripts
 Use descriptive target names
Ant tips
Tidy up your mess
Always define a ‘clean’ target.
Ant tips
Move to Maven ;-)
Maven tips
Better Maven scripts
Simple
Portable
Reproducible
Clean
Automated
Maven tips
Keep it simple
Use modules
Use an organization-level POM
Maven tips
Keep it portable
No hard-coding
Define sensible defaults for properties and profiles
Avoid resource filtering for production code
Maven tips
Keep it reproducible
Avoid external snapshots
Specify plugin versions
Use consistent environments
Maven tips
Consistent environments
Enforcing 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>
                                       Minimum Maven version
 	 <name>gameoflife</name>
 	 <prerequisites>
 	 	 <maven>2.2.1</maven>
 	 </prerequisites>
Maven tips
Consistent environments
Use 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
Maven tips
Enforcing consistency with the enforcer plugin
Maven version
JDK version
Snapshots
Plugin versions
OS
...
Maven tips
Enforce 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>                      Minimum Maven version
            <configuration>
              <rules>
                <requireMavenVersion>
                  <version>2.2.1</version>
                </requireMavenVersion>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>
Maven tips
Enforce the JDK version
All developers should be using the same JDKs
 Incompatible bytecode
 Different XML parsers
 Different Maven behaviour
Maven tips
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>                      Authorized JDK versions
            <configuration>
              <rules>
                <requireJavaVersion>
                  <version>[1.5.0,1.6.0)</version>
                </requireJavaVersion>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>
Maven tips
Specify your plugin versions
Undeclared version numbers are bad
 Inconsistent builds across different machines
 Non-repeatable builds
 Plugin changes can break the build
 Don’t use SNAPSHOT plugins either
Maven tips
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>               Plugin versions must be defined
            <configuration>
              <rules>
                <requirePluginVersions/>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>
Maven tips
Keep it clean
Keep tabs on your dependencies:
 What dependencies are you actually using?
 What dependencies do you really need?
Maven tips
Dependency list
What dependencies are you actually using?
 $ mvn dependency:list
 [INFO] Scanning for projects...        mvn dependency:list
 [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] ------------------------------------------------------------------------
Maven tips
Dependency tree
Where do they come from?
 $ mvn dependency:tree
 [INFO] Scanning for projects...       mvn dependency:tree
 [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] ------------------------------------------------------------------------
Maven tips
Dependencies in Eclipse
Eclipse has an equivalent screen
Maven tips
Dependency analyse
What dependencies do you really need?
 $ mvn dependency:analyze
 [INFO] Scanning for projects...     mvn dependency:analyse
 [INFO] Searching repository for plugin with prefix: 'dependency'.
 [INFO] ------------------------------------------------------------------------
 [INFO] Building babble-core
 [INFO]    task-segment: [dependency:analyze]
 [INFO] ------------------------------------------------------------------------
 [INFO] Preparing dependency:analyze
 ...                                                  Used but not declared
 [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
                                                       Declared but not used
 [INFO] ------------------------------------------------------------------------
Maven tips
Excluding dependencies
What if you don’t want a dependency?
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring</artifactId>
                                             Don’t include JMS
      <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>
Maven tips
  Standardizing versions
    Use dependencyManagement for consistency

<dependencyManagement>                       Parent pom
  <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>
        <dependencies>                                  Child pom
    </dependency>
          <dependency>
  </dependencies>
           !<groupId>mysql</groupId>
</dependencyManagement>
             <artifactId>mysql-connector-java</artifactId>
          </dependency>
        </dependencies>
Maven tips
Keep it automated
Plan your release strategy
Use a Repository Manager
Automatic snapshot deployments
Automated releases
Maven tips
Maven best practices for CI builds
Use batch mode (-B)
Always check or snapshot updates (-U)
Use a repository per project
Print test failures to stdout (-Dsurefire.useFile=false)
Maven tips
Know when to script it
Groovy or Ant scripting is easy in Maven
Call external scripts when appropriate
Maven tips
Know when to script it
It’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>
     ...
Maven tips
Know when to script it
It’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}"
      }
      ...
   }
 }
Java Power Tools Bootcamp
London - October 13-17 2010
Build Quality Tips from Java Consultant

Weitere ähnliche Inhalte

Andere mochten auch

Ant_quick_guide
Ant_quick_guideAnt_quick_guide
Ant_quick_guideducquoc_vn
 
Java Build Tools
Java Build ToolsJava Build Tools
Java Build Tools­Avishek A
 
Architecting your Frontend
Architecting your FrontendArchitecting your Frontend
Architecting your FrontendRuben Teijeiro
 
Gradle 2.Write once, builde everywhere
Gradle 2.Write once, builde everywhereGradle 2.Write once, builde everywhere
Gradle 2.Write once, builde everywhereStrannik_2013
 
Angular.js
Angular.jsAngular.js
Angular.jsGDG Cali
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More GroovyPaul King
 
4장. Class Loader
4장. Class Loader4장. Class Loader
4장. Class Loader김 한도
 
Tutorial to develop build files using ANT
Tutorial to develop build files using ANTTutorial to develop build files using ANT
Tutorial to develop build files using ANTravireddy76
 
Apache ant
Apache antApache ant
Apache antkoniik
 
Java Build Tool course in 2011
Java Build Tool course in 2011Java Build Tool course in 2011
Java Build Tool course in 2011Ching Yi Chan
 
Automated Frontend Testing
Automated Frontend TestingAutomated Frontend Testing
Automated Frontend TestingNeil Crosby
 
Front-End Testing: Demystified
Front-End Testing: DemystifiedFront-End Testing: Demystified
Front-End Testing: DemystifiedSeth McLaughlin
 
Erlang vs. Java
Erlang vs. JavaErlang vs. Java
Erlang vs. JavaArtan Cami
 

Andere mochten auch (20)

Ant_quick_guide
Ant_quick_guideAnt_quick_guide
Ant_quick_guide
 
Jvm a brief introduction
Jvm  a brief introductionJvm  a brief introduction
Jvm a brief introduction
 
Java Build Tools
Java Build ToolsJava Build Tools
Java Build Tools
 
Architecting your Frontend
Architecting your FrontendArchitecting your Frontend
Architecting your Frontend
 
Gradle 2.Write once, builde everywhere
Gradle 2.Write once, builde everywhereGradle 2.Write once, builde everywhere
Gradle 2.Write once, builde everywhere
 
Angular.js
Angular.jsAngular.js
Angular.js
 
Make Your Builds More Groovy
Make Your Builds More GroovyMake Your Builds More Groovy
Make Your Builds More Groovy
 
Apache maven 2 overview
Apache maven 2 overviewApache maven 2 overview
Apache maven 2 overview
 
4장. Class Loader
4장. Class Loader4장. Class Loader
4장. Class Loader
 
Tutorial to develop build files using ANT
Tutorial to develop build files using ANTTutorial to develop build files using ANT
Tutorial to develop build files using ANT
 
Apache maven 2 overview
Apache maven 2 overviewApache maven 2 overview
Apache maven 2 overview
 
Apache ant
Apache antApache ant
Apache ant
 
Java Classloaders
Java ClassloadersJava Classloaders
Java Classloaders
 
Java Build Tool course in 2011
Java Build Tool course in 2011Java Build Tool course in 2011
Java Build Tool course in 2011
 
Apache Ant
Apache AntApache Ant
Apache Ant
 
Automated Frontend Testing
Automated Frontend TestingAutomated Frontend Testing
Automated Frontend Testing
 
Front-End Testing: Demystified
Front-End Testing: DemystifiedFront-End Testing: Demystified
Front-End Testing: Demystified
 
Apache Ant
Apache AntApache Ant
Apache Ant
 
Erlang vs. Java
Erlang vs. JavaErlang vs. Java
Erlang vs. Java
 
Manen Ant SVN
Manen Ant SVNManen Ant SVN
Manen Ant SVN
 

Ähnlich wie Build Quality Tips from Java Consultant

The Future OS
The Future OS The Future OS
The Future OS Ed Parsons
 
An Introduction To FluidDB - a social database in the cloud
An Introduction To FluidDB - a social database in the cloudAn Introduction To FluidDB - a social database in the cloud
An Introduction To FluidDB - a social database in the cloudNicholas Tollervey
 
Hacker Lab Summary
Hacker Lab SummaryHacker Lab Summary
Hacker Lab SummaryEric Ullrich
 
Hacker Lab Startup Community Hackerspace
Hacker Lab Startup Community HackerspaceHacker Lab Startup Community Hackerspace
Hacker Lab Startup Community HackerspaceGina Lujan
 
Fluidinfo in a Nutshell
Fluidinfo in a NutshellFluidinfo in a Nutshell
Fluidinfo in a NutshellFluidinfo
 
Eduserv OpenID Meeting: OpenID Today
Eduserv OpenID Meeting: OpenID TodayEduserv OpenID Meeting: OpenID Today
Eduserv OpenID Meeting: OpenID TodayDavid Recordon
 
The 21st Century Mapping Agency
The 21st Century Mapping AgencyThe 21st Century Mapping Agency
The 21st Century Mapping AgencyEd Parsons
 
Apache Sling : JCR, OSGi, Scripting and REST
Apache Sling : JCR, OSGi, Scripting and RESTApache Sling : JCR, OSGi, Scripting and REST
Apache Sling : JCR, OSGi, Scripting and RESTCarsten Ziegeler
 
Mirage: extreme specialisation of virtual appliances
Mirage: extreme specialisation of virtual appliancesMirage: extreme specialisation of virtual appliances
Mirage: extreme specialisation of virtual appliancesThe Linux Foundation
 
Xero Advertisment - NZ Accountants Journal November 2007
Xero Advertisment - NZ Accountants Journal  November 2007Xero Advertisment - NZ Accountants Journal  November 2007
Xero Advertisment - NZ Accountants Journal November 2007Xero
 
Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0
Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0
Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0David Recordon
 
Plant hormone and responses
Plant hormone and responsesPlant hormone and responses
Plant hormone and responsesTre Briercliffe
 
H sgp keynot
H sgp keynotH sgp keynot
H sgp keynot114970
 
Airlines 2.0 - How airlines can use Web 2.0 for branding
Airlines 2.0 - How airlines can use Web 2.0 for brandingAirlines 2.0 - How airlines can use Web 2.0 for branding
Airlines 2.0 - How airlines can use Web 2.0 for brandingSimpliFlying
 
Approaching Rich Internet Applications
Approaching Rich Internet ApplicationsApproaching Rich Internet Applications
Approaching Rich Internet ApplicationsDhaval Dalal
 
OpenID Foundation Japan Chapter Announcement
OpenID Foundation Japan Chapter AnnouncementOpenID Foundation Japan Chapter Announcement
OpenID Foundation Japan Chapter AnnouncementDavid Recordon
 
Lincs & notts business Networking presentation
Lincs & notts business Networking presentation Lincs & notts business Networking presentation
Lincs & notts business Networking presentation Malcolm York
 

Ähnlich wie Build Quality Tips from Java Consultant (20)

Zen and-the-art-of-build-script-maintenance
Zen and-the-art-of-build-script-maintenanceZen and-the-art-of-build-script-maintenance
Zen and-the-art-of-build-script-maintenance
 
The Future OS
The Future OS The Future OS
The Future OS
 
An Introduction To FluidDB - a social database in the cloud
An Introduction To FluidDB - a social database in the cloudAn Introduction To FluidDB - a social database in the cloud
An Introduction To FluidDB - a social database in the cloud
 
An Introduction to FluidDB
An Introduction to FluidDBAn Introduction to FluidDB
An Introduction to FluidDB
 
Hacker Lab Summary
Hacker Lab SummaryHacker Lab Summary
Hacker Lab Summary
 
Hacker Lab Startup Community Hackerspace
Hacker Lab Startup Community HackerspaceHacker Lab Startup Community Hackerspace
Hacker Lab Startup Community Hackerspace
 
Fluidinfo in a Nutshell
Fluidinfo in a NutshellFluidinfo in a Nutshell
Fluidinfo in a Nutshell
 
Eduserv OpenID Meeting: OpenID Today
Eduserv OpenID Meeting: OpenID TodayEduserv OpenID Meeting: OpenID Today
Eduserv OpenID Meeting: OpenID Today
 
The 21st Century Mapping Agency
The 21st Century Mapping AgencyThe 21st Century Mapping Agency
The 21st Century Mapping Agency
 
Apache Sling : JCR, OSGi, Scripting and REST
Apache Sling : JCR, OSGi, Scripting and RESTApache Sling : JCR, OSGi, Scripting and REST
Apache Sling : JCR, OSGi, Scripting and REST
 
Mirage: extreme specialisation of virtual appliances
Mirage: extreme specialisation of virtual appliancesMirage: extreme specialisation of virtual appliances
Mirage: extreme specialisation of virtual appliances
 
Drupal Optimization
Drupal OptimizationDrupal Optimization
Drupal Optimization
 
Xero Advertisment - NZ Accountants Journal November 2007
Xero Advertisment - NZ Accountants Journal  November 2007Xero Advertisment - NZ Accountants Journal  November 2007
Xero Advertisment - NZ Accountants Journal November 2007
 
Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0
Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0
Web 2.0 Expo Berlin: OpenID Emerging from Web 2.0
 
Plant hormone and responses
Plant hormone and responsesPlant hormone and responses
Plant hormone and responses
 
H sgp keynot
H sgp keynotH sgp keynot
H sgp keynot
 
Airlines 2.0 - How airlines can use Web 2.0 for branding
Airlines 2.0 - How airlines can use Web 2.0 for brandingAirlines 2.0 - How airlines can use Web 2.0 for branding
Airlines 2.0 - How airlines can use Web 2.0 for branding
 
Approaching Rich Internet Applications
Approaching Rich Internet ApplicationsApproaching Rich Internet Applications
Approaching Rich Internet Applications
 
OpenID Foundation Japan Chapter Announcement
OpenID Foundation Japan Chapter AnnouncementOpenID Foundation Japan Chapter Announcement
OpenID Foundation Japan Chapter Announcement
 
Lincs & notts business Networking presentation
Lincs & notts business Networking presentation Lincs & notts business Networking presentation
Lincs & notts business Networking presentation
 

Mehr von Skills Matter

5 things cucumber is bad at by Richard Lawrence
5 things cucumber is bad at by Richard Lawrence5 things cucumber is bad at by Richard Lawrence
5 things cucumber is bad at by Richard LawrenceSkills Matter
 
Patterns for slick database applications
Patterns for slick database applicationsPatterns for slick database applications
Patterns for slick database applicationsSkills Matter
 
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvmScala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvmSkills Matter
 
Oscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheimOscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheimSkills Matter
 
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...Skills Matter
 
Cukeup nyc ian dees on elixir, erlang, and cucumberl
Cukeup nyc ian dees on elixir, erlang, and cucumberlCukeup nyc ian dees on elixir, erlang, and cucumberl
Cukeup nyc ian dees on elixir, erlang, and cucumberlSkills Matter
 
Cukeup nyc peter bell on getting started with cucumber.js
Cukeup nyc peter bell on getting started with cucumber.jsCukeup nyc peter bell on getting started with cucumber.js
Cukeup nyc peter bell on getting started with cucumber.jsSkills Matter
 
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...Skills Matter
 
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...Skills Matter
 
Progressive f# tutorials nyc don syme on keynote f# in the open source world
Progressive f# tutorials nyc don syme on keynote f# in the open source worldProgressive f# tutorials nyc don syme on keynote f# in the open source world
Progressive f# tutorials nyc don syme on keynote f# in the open source worldSkills Matter
 
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...Skills Matter
 
Dmitry mozorov on code quotations code as-data for f#
Dmitry mozorov on code quotations code as-data for f#Dmitry mozorov on code quotations code as-data for f#
Dmitry mozorov on code quotations code as-data for f#Skills Matter
 
A poet's guide_to_acceptance_testing
A poet's guide_to_acceptance_testingA poet's guide_to_acceptance_testing
A poet's guide_to_acceptance_testingSkills Matter
 
Russ miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-diveRuss miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-diveSkills Matter
 
Simon Peyton Jones: Managing parallelism
Simon Peyton Jones: Managing parallelismSimon Peyton Jones: Managing parallelism
Simon Peyton Jones: Managing parallelismSkills Matter
 
I went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_tI went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_tSkills Matter
 

Mehr von Skills Matter (20)

5 things cucumber is bad at by Richard Lawrence
5 things cucumber is bad at by Richard Lawrence5 things cucumber is bad at by Richard Lawrence
5 things cucumber is bad at by Richard Lawrence
 
Patterns for slick database applications
Patterns for slick database applicationsPatterns for slick database applications
Patterns for slick database applications
 
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvmScala e xchange 2013 haoyi li on metascala a tiny diy jvm
Scala e xchange 2013 haoyi li on metascala a tiny diy jvm
 
Oscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheimOscar reiken jr on our success at manheim
Oscar reiken jr on our success at manheim
 
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
Progressive f# tutorials nyc dmitry mozorov & jack pappas on code quotations ...
 
Cukeup nyc ian dees on elixir, erlang, and cucumberl
Cukeup nyc ian dees on elixir, erlang, and cucumberlCukeup nyc ian dees on elixir, erlang, and cucumberl
Cukeup nyc ian dees on elixir, erlang, and cucumberl
 
Cukeup nyc peter bell on getting started with cucumber.js
Cukeup nyc peter bell on getting started with cucumber.jsCukeup nyc peter bell on getting started with cucumber.js
Cukeup nyc peter bell on getting started with cucumber.js
 
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
Agile testing & bdd e xchange nyc 2013 jeffrey davidson & lav pathak & sam ho...
 
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
Progressive f# tutorials nyc rachel reese & phil trelford on try f# from zero...
 
Progressive f# tutorials nyc don syme on keynote f# in the open source world
Progressive f# tutorials nyc don syme on keynote f# in the open source worldProgressive f# tutorials nyc don syme on keynote f# in the open source world
Progressive f# tutorials nyc don syme on keynote f# in the open source world
 
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
Agile testing & bdd e xchange nyc 2013 gojko adzic on bond villain guide to s...
 
Dmitry mozorov on code quotations code as-data for f#
Dmitry mozorov on code quotations code as-data for f#Dmitry mozorov on code quotations code as-data for f#
Dmitry mozorov on code quotations code as-data for f#
 
A poet's guide_to_acceptance_testing
A poet's guide_to_acceptance_testingA poet's guide_to_acceptance_testing
A poet's guide_to_acceptance_testing
 
Russ miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-diveRuss miles-cloudfoundry-deep-dive
Russ miles-cloudfoundry-deep-dive
 
Serendipity-neo4j
Serendipity-neo4jSerendipity-neo4j
Serendipity-neo4j
 
Simon Peyton Jones: Managing parallelism
Simon Peyton Jones: Managing parallelismSimon Peyton Jones: Managing parallelism
Simon Peyton Jones: Managing parallelism
 
Plug 20110217
Plug   20110217Plug   20110217
Plug 20110217
 
Lug presentation
Lug presentationLug presentation
Lug presentation
 
I went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_tI went to_a_communications_workshop_and_they_t
I went to_a_communications_workshop_and_they_t
 
Plug saiku
Plug   saikuPlug   saiku
Plug saiku
 

Kürzlich hochgeladen

DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 

Kürzlich hochgeladen (20)

DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 

Build Quality Tips from Java Consultant

  • 1.
  • 2.
  • 3. Who is this guy, anyway? John Ferguson Smart Consultant, Trainer, Mentor, Author, Speaker Specialities: Java, Groovy/Grails Software Development Lifecycle Agile stuff (CI, TDD, BDD,...) Open Source
  • 4. Agenda What are we discussing today? What makes a good build script? Smelly build scripts Choosing your tools Maven tips Ant tips
  • 5. Introduction Quality build scripts - why bother Maintenance costs Learning curve Turn-over Portability Automation
  • 6. Build quality - quality builds What makes a good build script? Gold Standard Portable Reproducible Standard Maintainable
  • 7. Build quality - quality builds Gold Standard Reference build process Reference binaries
  • 8. Build quality - quality builds Portable Runs anywhere Runs on any OS No local dependencies Environment-specific configurations Specially-installed software or databases ...
  • 9. Build quality - quality builds Reproducible “Play it again, Sam”
  • 10. Build quality - quality builds Standard Knowing what to expect
  • 11. Build quality - quality builds Maintainable Think of the next dude
  • 12. Smelly builds So 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
  • 13. Paths .. 1/ URLs Smelly builds 9. c- gi lo 1 eb 00 Passwords /w :7 om ea .c /b me C: ac r. ve er ts es .> /t ".. :/ ger "ti tp rd= The hard coded build ht swo pas tt" sco e=" nam ser n u <sv /> M E }" S_HO JBOS env. = "$ { alue s" v Environment jbos dir. me=" variables y na pert <pro
  • 14. Smelly builds The hard coded build <target name="checkstyle"> Hard-coded directories <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>
  • 15. Smelly builds The hard coded build <target name="checkstyle"> Project-relative directory <property name=”reports.checkstyle.dir” <delete dir="./reports" quiet="true" /> value=”${basedir}/reports”/> <mkdir dir="./reports" /> DRY <checkstyle config="./docs/sun_checks.xml"> <target name="checkstyle"> <formatter type="xml" tofile="./reports/checkstyle.xml"/> <delete dir="${reports.checkstyle.dir}" quiet="true" /> <mkdir<fileset dir="./src" includes="**/*.java"/> dir="${reports.checkstyle.dir}" /> </checkstyle> <checkstyle config="./docs/sun_checks.xml"> <formatter type="xml" <style in="./reports/checkstyle.xml" tofile="${reports.checkstyle.dir}/checkstyle.xml"/> <fileset out="./reports/checkstyle.html" dir="./src" includes="**/*.java"/> style="checkstyle.xsl"/> </checkstyle> </target> <style in="${reports.checkstyle.dir}/checkstyle.xml" out="${reports.checkstyle.dir}/checkstyle.html" style="checkstyle.xsl"/> </target>
  • 16. Smelly builds The hard coded build <target name="war" > <war destfile="c:/tomcat/jakarta-tomcat-5.0.19/webapps/app.war" webxml="${src}/app.xml" basedir="${bin}" /> </target> Hard-coded directories
  • 17. Smelly builds The hard coded build <property name="wardir" location="c:/tomcat/jakarta-tomcat-5.0.19/webapps"/> <target name="war" > <war destfile="${wardir}" webxml="${src}/app.xml" basedir="${bin}" /> </target> Still hard-coded
  • 18. Smelly builds The hard coded build <svn username="scott" password="tiger"> <checkout url="http://subversion.acme.com/myapp/trunk" destPath="${subproject.dir}" /> </svn> Hard-coded username/password
  • 19. Smelly builds The hard coded build <property environment="env"/> <property name="dir.jboss" value="${env.JBOSS_HOME}"/> Environment variable
  • 20. Smelly builds The OS-specific build <exec command="grep "@" ${build.dir} | wc -l" outputproperty="token.count"/>
  • 21. Smelly builds The 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.254 PING %NonExist% -n 1 -w 100 2>NUL | FIND "TTL=" >NUL ... pause.cmd
  • 23. Smelly builds The Magic Machine build Directories App servers Databases Configuration files Environment variables Installed software or tools
  • 24. Smelly builds The Magic Machine build <proprerty weblogic.dir="/u01/app/bea/weblogic-9.1"/> Directories App servers Databases Configuration files Environment variables Installed software or tools
  • 25. Smelly builds The Oral Tradition build
  • 26. Smelly builds The Nested Build #! /bin/sh ANT_HOME=/u01/app/tools/ant-1.7.1 ... $ANT_HOME/ant $1 project/tools/ant.sh
  • 27. Smelly builds The Nested Build <target name="build-subproject"> <svn username="scott" password="tiger"> <checkout url="http://subversion.acme.com/someproject/trunk" destPath="${subproject.dir}" /> </svn> <ant dir="${subproject.dir}" target="build-all" /> </target> build.xml
  • 28. Smelly builds The Messy Dependencies build JAR files in the SCM Unversioned JAR files Unclear dependencies
  • 29. Smelly builds The DYI build “Not invented here” DYI dependencies DYI deployments DYI Maven releases ...
  • 30. Smelly builds The 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>
  • 32. Choosing your tools Flexibility verses Convention What’s better: flexibility or standards? It depends what you’re doing...
  • 33. Choosing your tools Encourage/enforce Standards and Conventions Support standards standards 3 Easy to read 2 Make up your own standards No standards Hard to read Ad-hoc scripting Standards and Conventions
  • 34. Choosing your tools Flexibility and expressiveness 3 Do whatever you Easy to read want 2 Encourage/enforce standards Hard to read Makes you stick to conventions Easy to do whatever you want
  • 35. Choosing your tools Flexibility verses Convention Build Scripting Rule 1 “A build script will tend to reflect the personality of it’s developer”
  • 36. Choosing your tools Flexibility verses Convention Build Scripting Rule 2 “The more flexible a build script, the more likely it is to become unmaintainable”
  • 37. Choosing your tools Flexibility verses Convention Flexibility is great for some jobs: Ad-hoc tasks Some deployment tasks “Out-of-the-box” stuff
  • 38. Choosing your tools Flexibility verses Convention But too much flexibility is hard to maintain
  • 39. Ant tips Better Ant scripts Consistent conventions Declare your dependencies Make it readable Tidy up your mess Avoid long scripts
  • 40. Ant tips Be consistent Standardize target names Document your public targets
  • 41. Ant tips Declare your dependencies Use an Enterprise Repository Manager Several tool choices: Maven Ant Tasks Ivy
  • 42. Ant tips Using 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>
  • 43. Ant tips Make it readable Write a build script like your source code... Avoid long targets Avoid long build scripts Use descriptive target names
  • 44. Ant tips Tidy up your mess Always define a ‘clean’ target.
  • 45. Ant tips Move to Maven ;-)
  • 46. Maven tips Better Maven scripts Simple Portable Reproducible Clean Automated
  • 47. Maven tips Keep it simple Use modules Use an organization-level POM
  • 48. Maven tips Keep it portable No hard-coding Define sensible defaults for properties and profiles Avoid resource filtering for production code
  • 49. Maven tips Keep it reproducible Avoid external snapshots Specify plugin versions Use consistent environments
  • 50. Maven tips Consistent environments Enforcing 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> Minimum Maven version <name>gameoflife</name> <prerequisites> <maven>2.2.1</maven> </prerequisites>
  • 51. Maven tips Consistent environments Use 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
  • 52. Maven tips Enforcing consistency with the enforcer plugin Maven version JDK version Snapshots Plugin versions OS ...
  • 53. Maven tips Enforce 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> Minimum Maven version <configuration> <rules> <requireMavenVersion> <version>2.2.1</version> </requireMavenVersion> </rules> </configuration> </execution> </executions> </plugin>
  • 54. Maven tips Enforce the JDK version All developers should be using the same JDKs Incompatible bytecode Different XML parsers Different Maven behaviour
  • 55. Maven tips 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> Authorized JDK versions <configuration> <rules> <requireJavaVersion> <version>[1.5.0,1.6.0)</version> </requireJavaVersion> </rules> </configuration> </execution> </executions> </plugin>
  • 56. Maven tips Specify your plugin versions Undeclared version numbers are bad Inconsistent builds across different machines Non-repeatable builds Plugin changes can break the build Don’t use SNAPSHOT plugins either
  • 57. Maven tips 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> Plugin versions must be defined <configuration> <rules> <requirePluginVersions/> </rules> </configuration> </execution> </executions> </plugin>
  • 58. Maven tips Keep it clean Keep tabs on your dependencies: What dependencies are you actually using? What dependencies do you really need?
  • 59. Maven tips Dependency list What dependencies are you actually using? $ mvn dependency:list [INFO] Scanning for projects... mvn dependency:list [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] ------------------------------------------------------------------------
  • 60. Maven tips Dependency tree Where do they come from? $ mvn dependency:tree [INFO] Scanning for projects... mvn dependency:tree [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] ------------------------------------------------------------------------
  • 61. Maven tips Dependencies in Eclipse Eclipse has an equivalent screen
  • 62. Maven tips Dependency analyse What dependencies do you really need? $ mvn dependency:analyze [INFO] Scanning for projects... mvn dependency:analyse [INFO] Searching repository for plugin with prefix: 'dependency'. [INFO] ------------------------------------------------------------------------ [INFO] Building babble-core [INFO] task-segment: [dependency:analyze] [INFO] ------------------------------------------------------------------------ [INFO] Preparing dependency:analyze ... Used but not declared [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 Declared but not used [INFO] ------------------------------------------------------------------------
  • 63. Maven tips Excluding dependencies What if you don’t want a dependency? <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> Don’t include JMS <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>
  • 64. Maven tips Standardizing versions Use dependencyManagement for consistency <dependencyManagement> Parent pom <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> <dependencies> Child pom </dependency> <dependency> </dependencies> !<groupId>mysql</groupId> </dependencyManagement> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
  • 65. Maven tips Keep it automated Plan your release strategy Use a Repository Manager Automatic snapshot deployments Automated releases
  • 66. Maven tips Maven best practices for CI builds Use batch mode (-B) Always check or snapshot updates (-U) Use a repository per project Print test failures to stdout (-Dsurefire.useFile=false)
  • 67. Maven tips Know when to script it Groovy or Ant scripting is easy in Maven Call external scripts when appropriate
  • 68. Maven tips Know when to script it It’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> ...
  • 69. Maven tips Know when to script it It’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}" } ... } }
  • 70. Java Power Tools Bootcamp London - October 13-17 2010