30 May 2011

One Minute Book Review: Getting To Yes

Today I take a look at a big classic from the field of negotiation: Roger Fisher's and William Ury's
Getting to Yes: Negotiating an agreement without giving in.



Negotiation is really only about one thing: getting what you want. The prize can be anything from the choice of dinner for this evening, to the amount of your next raise or the details of a new strategic partnership. Private or professional life, it doesn't matter. We negotiate all the time and the outcome of our negotiations greatly influences our lives.

And yet, this is a skill most of us in software engineering didn't receive any formal training in. Professionally the matter is even worse. Most of our "opponents", ranging from managers to sales people, have both more practice and better training. This leaves us fighting an uphill battle!

We must stand up and level the playing field!

I found Roger Fisher and William Ury to be powerful allies for this quest.

Getting To Yes makes the case for principled negotiation. The main focus is reaching a mutually satisfying agreement. This implies meeting the needs of both parties, and resisting the urge of trying to "win" against your opponent.

The reason they designed this method, is because most people get stuck bargaining over positions, effectively creating a win-lose situation.

The alternative is to take a step back and understand what your opponent really wants. Once his interests have been uncovered, you can then look whether the pie can be divided or whether new options should be invented for mutual gain. A good way to achieve this is by looking if the pie can not be expanded instead. Adding new elements to the negotiation opens up new scenarios and increases the chances of reaching an agreement.

If the negotiation gets difficult, make sure you focus on the problem and not on the people. You should always insist on objective criterias. And if all that doesn't work, you should have another plan ready: your BATNA (Best Alternative To Negotiated Agreement).

I found this book to be immensely useful. And I am not alone thinking this: they have sold millions of copies!

Highly recommended.

27 May 2011

Continuous Delivery Talk on Parleys

Earlier this month I was at the BeJUG in Leuven to present my Continuous Delivery talk.

It was great fun and I really enjoyed meeting lots of interesting people. But what is extra nice about the BeJUG, is that it is organized by Stephan Janssen of Devoxx and Parleys fame. And so, with the precious help of Daniel De Luca they made the talk available online at Parleys.com as well!

Here are some pictures of the event (more on the BeJUG page):



And here is the presentation on Parleys:



Thank you very much to all the ones that came. It was an absolute pleasure for me. And for all the ones who didn't have the chance to come, enjoy watching it online!

26 May 2011

Environment Detection

One of the key aspects of my Continuous Delivery talks is applications being aware of where they are.

Environment Detection stands for the ability to sense in which environment an application is currently deployed using the simplest means at its disposal.

Once this information is available you can act on it in a number of meaningful ways, such as loading the appropriate configuration or enabling/disabling features for the current environment.

This is powerful and simpler than it sounds. I'll show you a number of ways to implement the detection and then, we'll look at how to integrate it in an application. But always remember: use the simplest technique that works for you.


The most common detection strategies are:
  • IP Address/Range
  • HostName
  • File contents
  • Operating System
  • System Property

Let's have a look at how to implement them in Java.

IP Address/Range

// Assuming 1.2.3.4 is the IP Address of your DEV machine
// and 5.6.7.x is the IP Range of your PROD environment
String ipAddress = InetAddress.getLocalHost().getHostAddress();
if ("1.2.3.4".equals(ipAddress)) {
    // DEV
} else if (ipAddress.startsWith("5.6.7.")) {
    // PROD
}

HostName

// Assuming abc and def are the hostNames of your DEV and PROD servers
String hostName = InetAddress.getLocalHost().getHostName();
if ("abc".equals(hostName)) {
    // DEV
} else if ("def".equals(hostName)) {
    // PROD
}

File contents

import org.springframework.util.FileCopyUtils;

// Assuming /etc/my.env exists
// and contains the name of the environment such as DEV, TEST, PROD, ...
String environment = FileCopyUtils.copyToString(new FileReader("/etc/my.env"));

Operating System

// Assuming DEV is on Windows and PROD on Linux
String operatingSystem = System.getProperty("os.name");
if (operatingSystem.startsWith("Windows")) {
    // DEV
} else {
    // PROD
}

System Property

// Assuming my.env is set
// and contains the name of the environment such as DEV, TEST, PROD, ...
String environment = System.getProperty("my.env");

And that's all there is to it !


Here is a quick example of how to leverage this newly acquired piece of information:

Say we use a framework like Spring and want to easily load the appropriate configuration for the current environment.

We use an EnvironmentDetectionService to detect the environment and store the result in a System Property called my.env. The configuration for each environment is stored in a separate folder.

We can now load the appropriate configuration like this:
<bean id="environmentDetectionService" class="my.pkg.EnvironmentDetectionService"
    init-method="detectEnvironment"/>

<bean
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
    depends-on="environmentDetectionService">
    <property name="location" value="/config/${my.env}/my.properties"/>
</bean>


Environment Detection is a simple, yet very powerful capability. Start using it today and you'll never look back!

05 April 2011

Continuous Delivery Talk at the Rheinjug (in German)

On Thursday I had the pleasure to go and present my Continuous Delivery talk (in German) at the rheinjug in Düsseldorf.

I really enjoyed my visit. The organisation was great, and it drew a large and interesting crowd. We had a great Q&A session, and the conversation continued for a few more hours around some fine beers at the social event.

I've made the slides of the talk available on slideshare:


The video is now online as well:


Thanks to everyone who came. I hope you enjoyed it. I sure did :-)

20 February 2011

One Minute Book Review: Inbound Marketing

Over the Christmas holiday, I finally got around to something I had planned for a while: reading Brian Halligan's and Dharmesh Shah's very popular
Inbound Marketing: Get Found using Google, Social Media, and Blogs


The business world is changing. And it's changing fast. One of the most interesting statistics supporting this does not appear until the last chapter of the book. Here it is:

Between 1955 and 1995, on average, every year there were 20 companies leaving the Fortune 500 and 20 new ones joining. Since 1995 this number doubled to 40. Of the 500 companies in the Fortune 500 in 1995, only 250 remained in 2009!

So why did companies like Amazon, eBay and Google replace other ones likes Toys 'R' Us and Polaroid? The answer to this question is very much related to why Obama defeated McCain in the 2008 US presidential elections.

So what did the Obama campaign have in common with Amazon, eBay and Google?

They realized that throwing the most money at traditional media (television, print) to repeat the same message to as many people as possible as often as possible may not be the most effective anymore.

The point Brian and Dharmesh make is that this 50 year era of outbound marketing is coming to a close. People are getting increasingly better at blocking out these messages.

We are now at the dawn of a new era in the field of marketing: inbound marketing. Instead of focusing on bombarding as many people as possible with a message they don't want to hear, there are new rules that must be mastered on the road to success. Producing remarkable content that people want to read about is the way forward. Turning customers into fans.

And it turns out, we live in an age where it has never been easier. And yet it has never been harder. Google, Facebook, Blogs and Twitter enable anyone to produce great content and get found. Quality trumps dollars. And yet, all of a sudden the competition became global.

How can you and your company stand out and become better at this game?

This book is filled with practical advice on how to get there. Putting Google, Twitter, Facebook , LinkedIn and your blog to use, to achieve a loyal following who will help you spreading the word. And the work they will spread is one about how it is worth their time to be involved with the remarkable things you do!

Highly recommended.

10 February 2011

Maven Releases on Steroids (3): Rounding it up with Jenkins

In Part 2, we looked at what changes where necessary to the Maven POMs to make it all work.

In this final part, we'll put the finishing touch by choosing a version number strategy and integrating what we have so far with Jenkins.

Version Number

A good version number has a number of properties:
  • Natural order: it should be possible to determine at a glance between two versions which one is newer
  • Maven support: Maven should be able to deal with the format of the version number to enfore the natural order
  • Machine incrementable: so you don't have to specify it explicitely every time

Typical candidates can be:
  • build number
  • timestamp (in a suitable format such as yyyy.MM.dd.HH.mm)
  • revision number (SVN only)

We must now find one we can use. Luckily for us, it turns out Jenkins has a very useful feature for this. During each build Jenkins exposes a number of environments variables. A few of these are particularly interesting:

Environment Variable Description
BUILD_NUMBER The current build number, such as "153"
BUILD_ID The current build id, such as "2005-08-22_23-59-59" (YYYY-MM-DD_hh-mm-ss)
SVN_REVISION For Subversion-based projects, this variable contains the revision number of the module. If you have more than one module specified, this won't be set.

In this article, we''ll use the BUILD_NUMBER variable as a version number for our releases. We could have used one of the others as well, but this one fits our need perfectly: a fine machine-incremented number with a natural order supported by Maven.


Jenkins

The first thing to do is to set up a new Maven 2/3 project.

In this project you must
  • configure the SCM URL
  • set the Maven Goals and options to
    clean deploy scm:tag -DVERSION_NUMBER=${BUILD_NUMBER}


And that's it! Every time this job is run, a new release is produced, the artifacts will be deployed and the source code will be tagged. The version of the release will be the BUILD_NUMBER of the Jenkins project. Nice and simple.


A small note for Nexus users:

In order to allow Maven to upload the corrected POMs from Part 2 of this article, you need to set the Deployment Policy of the Releases repository to Allow Redeploy.



Next step

You're now ready to add a build trigger on SCM changes in Jenkins. Once you have this, every commit causing a green build will produce a new release. It's the next step up.


Download

Last, but not least, here is a sample multi-module Maven Project with all the POMs correctly set up available for download.


Conclusion

Looking back at the workflow of the Release Plugin we discussed in Part 1, we have come a long way!

If you're willing to live with 3 simple things:
  • you do NOT depend on SNAPSHOTs, ever.
  • the POM does not contain the version number
  • you ALWAYS build releases from a CI server, and NEVER locally on a developer's machine

you can now enjoy very fast (3x) and robust releases, without the headaches of the Release Plugin.

For reference:
Releases on Steroids Release Plugin
clean/compile/test cycle1 3
POM transformations0 2
commits0 2
SCM revisons1 3


Enjoy ! (You'll never look back :-) )

29 January 2011

Maven Releases on Steroids (2): Preparing the POMs

In Part 1, I wrote about the problems with the Maven Release Plugin and what could be a better way to perform releases with Maven.

In this part, we will make the necessary adjustments to the POMs to make it all work.

Our goal is to have a single command to:
  • Build and Test the SCM revision currently checked out
  • Deploy the binary artifacts to the Artifact Repository
  • Tag the SCM revision with the version number of the artifacts

As we only want one commit instead of 3 per release, the version number can not be contained inside the POM anymore, as this would make it impossible to update it without updating the POM itself.
We have to balance this against the need for a default version number when performing local, non-release builds, as we don't want to pass in a version number for every build.

This means we have the following requirements:
  • Version number settable from outside for release builds
  • Default version number for local, non-release builds

This can be solved by introducing a VERSION_NUMBER property:

Parent POM:
<project ...>
  ...
  <version>${VERSION_NUMBER}</version>
  ...
  <properties>
    ...
    <VERSION_NUMBER>1.0-SNAPSHOT</VERSION_NUMBER>
    ...
  </properties>
  ...

Child POMs:
<project ...>
  ...
  <parent>
    ...
    <version>${VERSION_NUMBER}</version>
    ...
  </parent>
  ...
  <version>${VERSION_NUMBER}</version>
  ...

The VERSION_NUMBER property now determines the version of our project.

By default it is set to 1.0-SNAPSHOT for local, non-release builds.
It can also be set externally using -DVERSION_NUMBER=... for release builds.

And normally, this should be it!

Unfortunately, Maven has a minefield of bugs we need to work around. What it basically boils down to, is that Maven neglects to replace variables in installed (local repo) and deployed (remote repo) POMs. This means our POMs get deployed with <version>${VERSION_NUMBER}</version>, which causes problems at runtime.

We will need to overwrite the broken POMs with a new version that has its variables replaced with their values.

The first thing we need to add (only to our parent POM) is a way to distinguisch between snapshot and release builds:
<project ...>
  ...
  <properties>
    ...
    <releaseRepoUrl>http://my.release.repo</releaseRepoUrl>
    <snapshotRepoUrl>http://my.snapshot.repo</snapshotRepoUrl>
    <deployRepoUrl>${releaseRepoUrl}</deployRepoUrl>
    <isRelease>true</isRelease>
    ...
  </properties>
  ...
  <profiles>
    <profile>
      <id>snapshot-deploy-url-override</id>
      <activation>
        <property>
          <name>!VERSION_NUMBER</name>
        </property>
      </activation>
      <properties>
        <deployRepoUrl>${snapshotRepoUrl}</deployRepoUrl>
        <isRelease>false</isRelease>
      </properties>
    </profile>
  </profiles>
  ...
  <distributionManagement>
    <snapshotRepository>
      <id>snapshots-repo</id>
      <name>Snapshots Repo</name>
      <url>${snapshotRepoUrl}</url>
    </snapshotRepository>
    <repository>
      <id>releases-repo</id>
      <name>Releases Repo</name>
      <url>${releaseRepoUrl}</url>
    </repository>
  </distributionManagement>
  ...

And now comes the real juicy part (only necessary in the parent POM):
  • Fixing the POM by substituting the variables
  • Overwriting the existing POM in the local repo
  • Overwriting the existing POM in the remote repo
<project ...>
  ...
  <build>
    ...
    <plugins>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.4.3</version>
        <executions>
          <execution>
            <id>replace-pom-placeholder</id>
            <phase>package</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <resources>
                <resource>
                  <directory>${basedir}</directory>
                  <includes>
                    <include>pom.xml</include>
                  </includes>
                  <filtering>true</filtering>
                </resource>
              </resources>
              <outputDirectory>${project.build.directory}/pom-install-deploy-fix</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.3.1</version>
        <executions>
          <execution>
            <id>overwrite-pom</id>
            <phase>install</phase>
            <goals>
              <goal>install-file</goal>
            </goals>
            <configuration>
              <packaging>pom</packaging>
              <file>target/pom-install-deploy-fix/pom.xml</file>
              <pomFile>target/pom-install-deploy-fix/pom.xml</pomFile>
              <version>${project.version}</version>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>overwrite-pom</id>
            <phase>deploy</phase>
            <goals>
              <goal>deploy-file</goal>
            </goals>
            <configuration>
              <packaging>pom</packaging>
              <file>target/pom-install-deploy-fix/pom.xml</file>
              <pomFile>target/pom-install-deploy-fix/pom.xml</pomFile>
              <url>${deployRepoUrl}</url>
              <version>${project.version}</version>
              <updateReleaseInfo>${isRelease}</updateReleaseInfo>
              <uniqueVersion>false</uniqueVersion>
            </configuration>
          </execution>
        </executions>
      </plugin>
      ...
    </plugins>
    ...
  </build>
  ...

If you also want to deploy source artifacts, check out the Maven Source Plugin.

So far, so good: we now have taken care of the deployment in the Artifact Repository!



Let's add the final bit to enable SCM tagging...

First add the scm section to your parent POM:
<project ...>
  ...
  <scm>
    <connection>scm:my-provider:my-read-url</connection>
    <developerConnection>scm:my-provider:my-read-write-url</developerConnection>
  </scm>
  ...

And now add the scm plugin to the plugins section of the parent POM:
<plugin>
    <artifactId>maven-scm-plugin</artifactId>
    <version>1.4</version>
    <configuration>
      <tag>${project.artifactId}-${VERSION_NUMBER}</tag>
    </configuration>
  </plugin>

Done!



We can now
  • publish new snapshots using
    mvn clean deploy
  • release and tag new versions using
    mvn clean deploy scm:tag -DVERSION_NUMBER=1.2.3

In Part 3, we conclude our adventure by choosing a version number strategy and looking at Jenkins integration.