<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Axel Fontaine</title>
  <link href="https://axelfontaine.com/blog/"/>
  <link type="application/atom+xml" rel="self" href="/blog/atom.xml"/>
  <updated>2025-01-14T18:59:47+00:00</updated>
  <id>https://axelfontaine.com/blog/</id>
  <author>
    <name>Axel Fontaine</name>
  </author>

  
  <entry>
    <id>https://axelfontaine.com/blog/dead-burried.html</id>
    <link type="text/html" rel="alternate" href="/blog/dead-burried.html"/>
    <title>Maven Release Plugin: Dead and Buried</title>
    <published>2016-04-15T00:00:00+00:00</published>
    <updated>2016-04-15T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;
        This is the second major update to a very &lt;a href=&quot;/blog/maven-releases-steroids.html&quot;&gt;popular&lt;/a&gt; &lt;a
            href=&quot;/blog/maven-releases-steroids-2.html&quot;&gt;article&lt;/a&gt;
        &lt;a href=&quot;/blog/maven-releases-steroids-3.html&quot;&gt;series&lt;/a&gt; titled &apos;Maven Releases on Steroids&apos; which I originally
        published in 2011. The goal of the
        series was to provide a simple and efficient way to produce releases on a Maven project. Not only that, but
        it did so in a way that is compatible with Continuous Delivery.&lt;/p&gt;

    &lt;p&gt;The original series was written for Subversion.
        By 2013 Git had taken over the market and so I published an update called
        &lt;a href=&quot;/blog/final-nail.html&quot;&gt;Maven Release Plugin: The Final Nail in the Coffin&lt;/a&gt; that integrated both Git
        itself and the improvements it provided into the workflow.&lt;/p&gt;

    &lt;p&gt;With its 3.2.1 release, Maven finally introduced support for &lt;a href=&quot;https://issues.apache.org/jira/browse/MNG-5576&quot;&gt;Continuous Delivery friendly versions&lt;/a&gt;.
    While not perfect, even this minimal implementation warranted this long overdue update to my previous articles.&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;The improvements so far&lt;/h3&gt;

    &lt;p&gt;Maven has traditionally required the version number to be present in the project descriptor (pom.xml). This
        concept permeates through all aspects of the Maven ecosystem, culminating with the monstrosity commonly referred
        to as the Release Plugin.&lt;/p&gt;

    &lt;p&gt;So how big exactly was the improvement of &lt;a href=&quot;/blog/maven-releases-steroids.html&quot;&gt;Releases On Steroids&lt;/a&gt;
        and &lt;a href=&quot;/blog/final-nail.html&quot;&gt;Final Nail&lt;/a&gt; over the Release Plugin? See for yourself:&lt;/p&gt;

    &lt;table class=&quot;table table-bordered&quot;&gt;
        &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;&lt;/th&gt;
            &lt;th&gt;Releases on Steroids&lt;/th&gt;
            &lt;th&gt;Release Plugin&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Clean/Compile/Test cycle&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;POM transformations&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Commits&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;SCM revisons&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;

    &lt;p&gt;The reduction in the number of Clean/Compile/Test cycles alone results in a &lt;strong&gt;3x build time improvement&lt;/strong&gt;!
        And this doesn&apos;t even take into consideration the other adavantages like increased reliability and recoverability. Quite the win indeed!&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Turning it up to 11&lt;/h3&gt;

    &lt;p&gt;Both original article series and the Final Nail update required the use of the &lt;a href=&quot;http://www.mojohaus.org/versions-maven-plugin/&quot;&gt;Versions Maven Plugin&lt;/a&gt;
        to dynamically update the generic version contained in the POM to the new version assigned dynamically for the
        current build. This resulted in the need to run Maven twice: once for updating the version and the again with the
    updated version.&lt;/p&gt;

    &lt;p&gt;With the Maven 3.2.1 release and the newly introduced support for &lt;a href=&quot;https://issues.apache.org/jira/browse/MNG-5576&quot;&gt;Continuous Delivery friendly versions&lt;/a&gt;
        we can now finally eliminate this extra step and get down to a single execution.&lt;/p&gt;

    &lt;p&gt;At its core the purpose of producing a release is nothing more than being able to link a version
        of the software as deployed onto a machine back to the matching revision of the source code in SCM. This is essential
        to reproduce bugs and revert to previous versions deterministically if required.&lt;/p&gt;

    &lt;p&gt;To accomplish this we have to go through a number of steps. At a minimum these include:&lt;/p&gt;
    &lt;ul&gt;
        &lt;li&gt;checking out the software as it is&lt;/li&gt;
        &lt;li&gt;giving it a version so it can be uniquely identified&lt;/li&gt;
        &lt;li&gt;building, testing and packaging it&lt;/li&gt;
        &lt;li&gt;deploying it to an artifact repository where it can then be picked for actual roll out on target machines&lt;/li&gt;
        &lt;li&gt;tagging this state in SCM so it can be associated with the matching artifact&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;Surprisingly simple, isn&apos;t it?&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Eliminating the Versions plugin&lt;/h3&gt;

    &lt;p&gt;Now let&apos;s revisit the ideas presented in &lt;a href=&quot;/blog/final-nail.html&quot;&gt;Final Nail&lt;/a&gt; and see how they can be improved with Maven&apos;s new Continuous Delivery friendly versions support.&lt;/p&gt;

    &lt;p&gt;For this we need to ensure our POM accepts versions set externally. As this will usually only be the case on the CI machine
        (the one and only machine you should ever build releases on), we also need a sane default for local development to avoid having to pass a dummy version for every single local build.&lt;/p&gt;

    &lt;p&gt;Taking that into account our &lt;code&gt;pom.xml&lt;/code&gt; now looks like this:&lt;/p&gt;

    &lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;
    ...
    &amp;lt;version&amp;gt;${revision}&amp;lt;/version&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;!-- Sane default when no revision property is passed in from the commandline --&amp;gt;
        &amp;lt;revision&amp;gt;0-SNAPSHOT&amp;lt;/revision&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;scm&amp;gt;
        &amp;lt;connection&amp;gt;scm:git:&lt;em&gt;&amp;lt;&amp;lt;your-git-repo-url&amp;gt;&amp;gt;&lt;/em&gt;&amp;lt;/connection&amp;gt;
    &amp;lt;/scm&amp;gt;

    &amp;lt;distributionManagement&amp;gt;
        &amp;lt;repository&amp;gt;
            &amp;lt;id&amp;gt;artifact-repository&amp;lt;/id&amp;gt;
            &amp;lt;url&amp;gt;&lt;em&gt;&amp;lt;&amp;lt;your-artifact-repo-url&amp;gt;&amp;gt;&lt;/em&gt;&amp;lt;/url&amp;gt;
        &amp;lt;/repository&amp;gt;
    &amp;lt;/distributionManagement&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-scm-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;1.9.4&amp;lt;/version&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;tag&amp;gt;${project.artifactId}-${project.version}&amp;lt;/tag&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
    ...
&amp;lt;/project&amp;gt;&lt;/pre&gt;

    &lt;p&gt;And that&apos;s it! You can now produce releases on your CI server very easily by invoking:&lt;/p&gt;

    &lt;pre&gt;&lt;strong&gt;mvn deploy scm:tag -Drevision=$BUILD_NUMBER&lt;/strong&gt;&lt;/pre&gt;

    &lt;p&gt;Where &lt;code&gt;BUILD_NUMBER&lt;/code&gt; is the environment variable provided by your CI server to identify the current build number for the project.&lt;/p&gt;

    &lt;p&gt;For services and deliverables consumed by other teams and external parties you can also easily combine this technique with &lt;a href=&quot;http://semver.org/&quot;&gt;sematic versioning&lt;/a&gt; by
        prefixing the version tag in your POM with the correct semantic version. You can then automatically produce releases internally
        and manually updated this semantic version before each external delivery.&lt;/p&gt;

    &lt;p&gt;Example:&lt;/p&gt;

    &lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;version&amp;gt;1.2.34.${revision}&amp;lt;/version&amp;gt;&lt;/pre&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Conclusion&lt;/h3&gt;

    &lt;p&gt;In this article we have taken what was already a gigantic improvement over the Maven Release Plugin and simplified it even further by finally getting it down to a single Maven execution:&lt;/p&gt;

    &lt;table class=&quot;table table-bordered&quot;&gt;
        &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;&lt;/th&gt;
            &lt;th&gt;This article&lt;/th&gt;
            &lt;th&gt;Releases on Steroids&lt;/th&gt;
            &lt;th&gt;Release Plugin&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Clean/Compile/Test cycle&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;POM transformations&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Commits&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;SCM revisons&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Maven Executions&lt;/td&gt;
            &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
            &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;

    &lt;p&gt;This is by far the &lt;strong&gt;simplest and most effective way to produce releases on projects using Maven and
            Continuous Delivery.&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;Along the way, we strongly focused on keeping as much knowledge as possible inside the POM. This keeps the
        release process concise, provides us with sane defaults and minimizes dependencies on specific environments or CI servers.&lt;/p&gt;

    &lt;p&gt;So do yourself a favor and join me in finally &lt;strong&gt;burying the Release Plugin for good. It&apos;s been dead for a while now anyway.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/immutable-infrastructure-and-cloud-talks.html</id>
    <link type="text/html" rel="alternate" href="/blog/immutable-infrastructure-and-cloud-talks.html"/>
    <title>Immutable Infrastructure and Cloud Architecture Talks</title>
    <published>2015-10-17T00:00:00+00:00</published>
    <updated>2015-10-17T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;2015 has proven to be another very busy year so far. I toured quite a bit, giving lots &lt;a href=&quot;/#speaking&quot;&gt;conference talks&lt;/a&gt; and teaching my
        &lt;a href=&quot;/training/continuousdelivery.html&quot;&gt;Architecting for Continuous Delivery and Zero Downtime&lt;/a&gt; course.&lt;/p&gt;
    &lt;p&gt;Here are the slides and the videos of my two latest ones:&lt;/p&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;h3&gt;Immutable infrastructure&lt;/h3&gt;
    &lt;p&gt;App deployment and server setup are complex, error-prone and time-consuming. They require OS installers, package managers, configuration recipes, install and deployment scripts, server tuning, hardening and more. But... Is this really necessary? Are we trapped in a mindset of doing things this way just because that&apos;s how they&apos;ve always done?&lt;/p&gt;

        &lt;p&gt;What if we could start over and radically simplify all this? What if, within seconds, and with a single command, we could wrap our application into the bare minimal machine required to run it? What if this machine could then be transported and run unchanged on our laptop and in the cloud? How do the various platforms and tools like AWS, Docker, Heroku and Boxfuse fit into this picture? What are their strengths and weaknesses? When should you use them?&lt;/p&gt;

        &lt;p&gt;This talk is for developers and architects wishing to radically improve and simplify how they deploy their applications. It takes Continuous Delivery to a level far beyond what you&apos;ve seen today. Welcome to Immutable Infrastructure generation. This is the new black.&lt;/p&gt;

    &lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;58a39a45b30d4d1f9c0a0737035cb928&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;iframe src=&quot;https://player.vimeo.com/video/130993909&quot; width=&quot;770&quot; height=&quot;469&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;&lt;a href=&quot;https://vimeo.com/130993909&quot;&gt;Immutable Server Generation: the new App Deployment - Axel Fontaine&lt;/a&gt; from &lt;a href=&quot;https://vimeo.com/javazone&quot;&gt;JavaZone&lt;/a&gt; on &lt;a href=&quot;https://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Architecture and Deployment of Microservices for the Cloud&lt;/h3&gt;

    &lt;p&gt;The case for running an own datacenter is vanishing rapidly. The cloud seduces with a low barrier of entry and full flexibility. Infrastructure can be spun up almost instantly in a fully automated way through an API. All this with no upfront costs and the ability to decommission it just as fast. But what does this mean for our applications and their architecture? Can we just lift and shift them to the cloud?&lt;/p&gt;

        &lt;p&gt;Everything comes at a price. To be able to fully leverage the potential of the cloud, new challenges must be mastered: from data privacy and security to cost-based architectures, dynamic provisioning, service discovery and efficient deployment models.&lt;/p&gt;

        &lt;p&gt;This talk provides architects and developers clear answers and battle-tested solutions for a successful journey to infrastructure heaven.&lt;/p&gt;
    &lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;412dcee23b0e4157a60e0b878810b277&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;iframe src=&quot;https://player.vimeo.com/video/138957702&quot; width=&quot;770&quot; height=&quot;469&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;&lt;a href=&quot;https://vimeo.com/138957702&quot;&gt;Up in the sky: Architecture and Deployment of Microservices for the Cloud - Axel Fontaine&lt;/a&gt; from &lt;a href=&quot;https://vimeo.com/javazone&quot;&gt;JavaZone&lt;/a&gt; on &lt;a href=&quot;https://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;p&gt;&lt;strong&gt;Enjoy!&lt;/strong&gt;&lt;/p&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/flyway-javaee-hangout.html</id>
    <link type="text/html" rel="alternate" href="/blog/flyway-javaee-hangout.html"/>
    <title>Flyway Java EE Hangout and Voxxed Interview</title>
    <published>2015-02-19T00:00:00+00:00</published>
    <updated>2015-02-19T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;I&apos;ve been quite active lately both doing &lt;a href=&quot;/#speaking&quot;&gt;conference talks&lt;/a&gt; and teaching my
        &lt;a href=&quot;/training/continuousdelivery.html&quot;&gt;Architecting for Continuous Delivery and Zero Downtime&lt;/a&gt; course.&lt;/p&gt;
    &lt;p&gt;In the midst of all this, I also had the pleasure to take time out to give some interviews. These are the two latest ones.&lt;/p&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;h3&gt;Flyway Java EE Hangout&lt;/h3&gt;
    &lt;p&gt;Yesterday &lt;strong&gt;&lt;a href=&quot;http://blog.arungupta.me/database-migrations-in-javaee-flyway-hanginar6/&quot;&gt;Arun Gupta&lt;/a&gt;&lt;/strong&gt;, of Java EE fame,
        and myself hosted a joint Google Hangout about  &lt;strong&gt;Database Migrations in Java EE using Flyway&lt;/strong&gt;.&lt;/p&gt;

    &lt;p&gt;In this hangout you&apos;ll learn how &lt;a href=&quot;http://flywaydb.org/&quot;&gt;Flyway&lt;/a&gt; simplifies database migrations and seamlessly &lt;a href=&quot;http://flywaydb.org/documentation/api&quot;&gt;integrates with your Java EE application&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h5&gt;Topics covered:&lt;/h5&gt;

    &lt;ul&gt;
        &lt;li&gt;Need for database migration tool in a Java EE application&lt;/li&gt;
        &lt;li&gt;Seamless integration with Java EE application lifecycle&lt;/li&gt;
        &lt;li&gt;SQL scripts and Java-based migrations&lt;/li&gt;
        &lt;li&gt;&lt;a href=&quot;http://flywaydb.org/getstarted&quot;&gt;Getting Started guides&lt;/a&gt;&lt;/li&gt;
        &lt;li&gt;Comparison with Liquibase&lt;/li&gt;
        &lt;li&gt;And much more!&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;iframe width=&quot;770&quot; height=&quot;469&quot; src=&quot;https://www.youtube.com/embed/vPwWQvvBWEg&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Voxxed interview on the Mainstreaming of Continuous Deployment&lt;/h3&gt;

    &lt;p&gt;Back at Devoxx in Antwerp, I sat down with &lt;strong&gt;&lt;a href=&quot;https://www.voxxed.com/blog/2014/12/axel-fontaine-mainstreaming-continuous-deployment/&quot;&gt;Lucy Carey&lt;/a&gt;&lt;/strong&gt;, from
        &lt;a href=&quot;https://www.voxxed.com/blog/2014/12/axel-fontaine-mainstreaming-continuous-deployment/&quot;&gt;Voxxed&lt;/a&gt;,
        where we discussed the mainstreaming of Continuous Deployment and my work at Boxfuse.&lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;iframe width=&quot;770&quot; height=&quot;469&quot; src=&quot;https://www.youtube.com/embed/2Ln35uDieUU&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
    &lt;p&gt;&lt;strong&gt;Enjoy!&lt;/strong&gt;&lt;/p&gt;
    &lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/jfokus.html</id>
    <link type="text/html" rel="alternate" href="/blog/jfokus.html"/>
    <title>Jfokus 2014 and Nighthacking interview</title>
    <published>2014-02-11T00:00:00+00:00</published>
    <updated>2014-02-11T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;Last week I had a full week of fun at &lt;a href=&quot;http://www.jfokus.se/jfokus/speakers.jsp#AxelFontaine&quot;&gt;Jfokus&lt;/a&gt;
        in Stockholm. I had a very busy agenda with:&lt;/p&gt;

    &lt;ul&gt;
        &lt;li&gt;a &lt;strong&gt;tutorial&lt;/strong&gt; on monday&lt;/li&gt;
        &lt;li&gt;a &lt;strong&gt;talk&lt;/strong&gt; on wednesday&lt;/li&gt;
        &lt;li&gt;a &lt;strong&gt;sold out&lt;/strong&gt; post-conference &lt;strong&gt;training&lt;/strong&gt; on thursday and friday&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;
        Here are the slides of my talk:
    &lt;/p&gt;

    &lt;p class=&quot;center&quot;&gt;
        &lt;iframe class=&quot;img-polaroid&quot; src=&quot;//www.slideshare.net/slideshow/embed_code/30846081&quot;
                width=&quot;770&quot; height=&quot;469&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;
                allowfullscreen&gt;&lt;/iframe&gt;
    &lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Nighthacking Interview&lt;/h3&gt;

    &lt;p&gt;On wednesday I also had the pleasure to sit down with Stephen Chin of &lt;a href=&quot;http://nighthacking.com/&quot;&gt;Nighthacking.com&lt;/a&gt; and the
        Java Youtube channel for an
        interview about Continuous Delivery. I gave a quick demo of things to come in 2014.
        Check it out and &lt;a href=&quot;https://boxfuse.com&quot;&gt;stay tuned&lt;/a&gt;!&lt;/p&gt;

    &lt;p class=&quot;center&quot;&gt;
        &lt;iframe width=&quot;780&quot; height=&quot;439&quot; src=&quot;//www.youtube.com/embed/RYV3fGnDrAE&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
    &lt;/p&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;h3&gt;Additional Continuous Delivery training in Stockholm&lt;/h3&gt;

    &lt;p&gt;The Jfokus course sold out very quickly, so we decided to run an additional
        &lt;a href=&quot;http://www.jfokus.se/jfokus/training.jsp&quot;&gt;Architecting for Continuous Delivery: from Zero to Hero&lt;/a&gt; training
    in Stockholm on &lt;strong&gt;12-13 March 2014&lt;/strong&gt;. Seats are limited and most are gone already, but there are still a few remaining places. So don&apos;t wait if you want to participate!&lt;/p&gt;

    &lt;p&gt;Looking forward to see you there!&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/ebook.html</id>
    <link type="text/html" rel="alternate" href="/blog/ebook.html"/>
    <title>E-book and JAXenter Interview (in German)</title>
    <published>2013-11-15T00:00:00+00:00</published>
    <updated>2013-11-15T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;This fall I have spoken at a &lt;a href=&quot;/blog/java-magazin.html&quot;&gt;large number of conferences&lt;/a&gt;. Last week at
        &lt;a href=&quot;http://jax.de&quot;&gt;W-JAX&lt;/a&gt; I sat down with Claudia Fröhling from &lt;a
                href=&quot;http://jaxenter.de/java-magazin&quot;&gt;Java Magazin&lt;/a&gt;
        for a brief interview about Continuous Delivery. You can enjoy it in here (in German):&lt;/p&gt;

    &lt;p class=&quot;center&quot;&gt;
        &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/iBss3ouL7cc&quot; frameborder=&quot;0&quot;
                allowfullscreen&gt;&lt;/iframe&gt;&lt;br/&gt;&lt;br/&gt;
    &lt;/p&gt;

    &lt;h3&gt;Java Magazin article as E-book&lt;/h3&gt;

    &lt;p&gt;This week my &lt;a href=&quot;/blog/java-magazin.html&quot;&gt;Architecting for Continuous Delivery article&lt;/a&gt; (in German) for Java Magazin
        has also been published as an &lt;a href=&quot;http://entwickler.de/press/Agilitaet-und-Continuous-Delivery-168511&quot;&gt;E-book&lt;/a&gt;,
        as part of the Shortcuts series from &lt;strong&gt;entwickler.press&lt;/strong&gt;:&lt;/p&gt;

    &lt;p class=&quot;center&quot;&gt;
        &lt;a href=&quot;http://entwickler.de/press/Agilitaet-und-Continuous-Delivery-168511&quot;&gt;&lt;img src=&quot;/assets/agilitaet_und_contious_delivery.jpg&quot;
                                                                              alt=&quot;Agilität und Continuous Delivery&quot;/&gt;&lt;/a&gt;
    &lt;/p&gt;

    &lt;p&gt;If you haven&apos;t read it already, you can now enjoy it both on &lt;a href=&quot;http://www.amazon.de/Agilit%C3%A4t-Continuous-Delivery-Steffen-Schluff-ebook/dp/B00GLXWDQY/ref=sr_1_1?ie=UTF8&amp;qid=1384350382&amp;sr=8-1&amp;keywords=Agilit%C3%A4t%20und%20Continuous%20Delivery&quot;&gt;Kindle&lt;/a&gt; and on
        your &lt;a href=&quot;https://itunes.apple.com/de/book/agilitat-und-continuous-delivery/id743899264?mt=11&quot;&gt;iPad or iPhone&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;Happy reading!&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/java-magazin.html</id>
    <link type="text/html" rel="alternate" href="/blog/java-magazin.html"/>
    <title>Java Magazin article and Fall 2013 speaking tour</title>
    <published>2013-10-10T00:00:00+00:00</published>
    <updated>2013-10-10T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;I have been giving talks about Continuous Delivery over the last three years. During these talks,
        I have had the chance to meet lots of interesting people with whom I had many great conversations.&lt;/p&gt;

    &lt;p&gt;While talks are great as you can interact and really get the message out, they do have one problem:
        reach. You simply can&apos;t pack 20,000 people in one room. I was therefore delighted when Claudia Fröhling,
        the editor-in-chief of &lt;strong&gt;Java Magazin&lt;/strong&gt;, asked me to write the leading article for their upcoming
        &lt;a href=&quot;https://jaxenter.de/magazines/Java-Magazin-1113-167769&quot;&gt;Continuous
            Delivery issue&lt;/a&gt;. Java Magazin is Europe&apos;s largest print magazine about Java and therefore a great
        platform to spread the word!&lt;/p&gt;

    &lt;p&gt;The issue finally got published this week:&lt;/p&gt;

    &lt;p class=&quot;center&quot;&gt;
        &lt;a href=&quot;https://jaxenter.de/magazines/Java-Magazin-1113-167769&quot;&gt;&lt;img src=&quot;/assets/javamagazin.jpg&quot;
                                                                              alt=&quot;Java Magazin&quot;/&gt;&lt;/a&gt;
    &lt;/p&gt;

    &lt;p&gt;It contains both my &lt;strong&gt;article&lt;/strong&gt; titled &lt;strong&gt;&quot;Architecting for Continuous Delivery&quot;&lt;/strong&gt;
        and an &lt;strong&gt;interview with me&lt;/strong&gt; as author of
        the month. The iPad edition also contains a video of my Continuous Delivery talk at JAX 2013 in Mainz.&lt;/p&gt;

    &lt;p&gt;So if you speak German, are interested in Continuous Delivery and haven&apos;t had a chance to attend one of my talks
        yet, make sure to check it out!&lt;/p&gt;

    &lt;h3&gt;Conference speaking tour Fall 2013&lt;/h3&gt;

    &lt;p&gt;I started this year with a spring speaking tour which took me to
        &lt;a href=&quot;http://2013.33degree.org/speaker/show/36&quot;&gt;33rd Degree&lt;/a&gt; in Warsaw,
        &lt;a href=&quot;http://www.devoxx.com/display/FR13/Axel+Fontaine&quot;&gt;Devoxx FR&lt;/a&gt; in Paris,
        &lt;a href=&quot;https://2013.con-fess.com/speakers#25&quot;&gt;Confess&lt;/a&gt; in Vienna and finally
        &lt;a href=&quot;http://jax.de/2013/&quot;&gt;JAX&lt;/a&gt; in Mainz. It was great fun and a good chance to flex my language muscles,
        as I gave talks in French, German and English.&lt;/p&gt;

    &lt;p&gt;After the summer break, the conference season has kicked in again. My speaking tour for the fall 2013 already
        took
        me to Oslo for a Flyway talk at &lt;a href=&quot;http://jz13.java.no/presentation.html?id=4b026c8d&quot;&gt;JavaZone&lt;/a&gt;, and to
        Göttingen for a &lt;strong&gt;sold-out&lt;/strong&gt; &lt;a
                href=&quot;http://www.sourcetalk.de/2013/programm/abstracts/?show=20131002-10-00-trainings-Axel-Fontaine&quot;&gt;Continuous
            Delivery workshop&lt;/a&gt;.&lt;/p&gt;

    &lt;p class=&quot;center logo-list&quot;&gt;
        &lt;a href=&quot;http://jz13.java.no/presentation.html?id=4b026c8d&quot;&gt;&lt;img
                src=&quot;/assets/posts/java-magazin-article/javazone.png&quot; alt=&quot;JavaZone&quot;/&gt;&lt;/a&gt;
        &lt;a href=&quot;http://www.sourcetalk.de/2013/programm/abstracts/?show=20131002-10-00-trainings-Axel-Fontaine&quot;&gt;&lt;img
                src=&quot;/assets/posts/java-magazin-article/sourcetalk.png&quot; alt=&quot;SourceTalk&quot;/&gt;&lt;/a&gt;
    &lt;/p&gt;

    &lt;p&gt;I&apos;m in Kiev in the Ukraine this week, as I will giving the &lt;strong&gt;keynote&lt;/strong&gt; at the
        &lt;a href=&quot;http://xpdays.com.ua/program/#continuous-delivery&quot;&gt;XP Days&lt;/a&gt; conference, as well as giving a
        Flyway talk later that day. After that in November, I will in Munich for &lt;a
                href=&quot;http://jax.de/node/905&quot;&gt;W-JAX&lt;/a&gt;,
        before heading to Antwerp for &lt;a href=&quot;http://www.devoxx.be/dv13-axel-fontaine.html&quot;&gt;Devoxx&lt;/a&gt;
        and finally to Gothenburg,
        where I will return to &lt;a href=&quot;http://www.jdays.se/speakers#AxelFontaine&quot;&gt;jDays&lt;/a&gt;.&lt;/p&gt;

    &lt;p class=&quot;center logo-list&quot;&gt;
        &lt;a href=&quot;http://xpdays.com.ua/program/#continuous-delivery&quot;&gt;&lt;img
                src=&quot;/assets/posts/java-magazin-article/xpdays.png&quot; alt=&quot;XP Days&quot;/&gt;&lt;/a&gt;
        &lt;a href=&quot;http://jax.de/node/905&quot;&gt;&lt;img src=&quot;/assets/posts/java-magazin-article/wjax.png&quot; alt=&quot;W-JAX&quot;/&gt;&lt;/a&gt;
        &lt;a href=&quot;http://www.devoxx.be/dv13-axel-fontaine.html&quot;&gt;&lt;img src=&quot;/assets/posts/java-magazin-article/devoxx.png&quot; alt=&quot;Devoxx&quot;/&gt;&lt;/a&gt;
        &lt;a href=&quot;http://www.jdays.se/speakers#AxelFontaine&quot;&gt;&lt;img src=&quot;/assets/posts/java-magazin-article/jdays.png&quot; alt=&quot;jDays&quot;/&gt;&lt;/a&gt;
    &lt;/p&gt;

    &lt;p&gt;I will then be giving a final talk for this year at the Lightweight Java User Group in Munich to round things
        off.&lt;/p&gt;

    &lt;p&gt;If you are at any of &lt;a href=&quot;/#speaking&quot;&gt;these events&lt;/a&gt;, come and say hello! I&apos;d love to have a chat
        with you!&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/final-nail.html</id>
    <link type="text/html" rel="alternate" href="/blog/final-nail.html"/>
    <title>Maven Release Plugin: The Final Nail in the Coffin</title>
    <published>2013-08-15T00:00:00+00:00</published>
    <updated>2013-08-15T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div class=&quot;well well-small&quot;&gt;&lt;strong&gt;Update:&lt;/strong&gt; I updated this article in 2016 as &lt;a href=&quot;/blog/dead-burried.html&quot;&gt;Maven Release Plugin: Dead and Buried&lt;/a&gt;&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;
    Two and half years ago, I published a very &lt;a href=&quot;/blog/maven-releases-steroids.html&quot;&gt;popular&lt;/a&gt; &lt;a
        href=&quot;/blog/maven-releases-steroids-2.html&quot;&gt;article&lt;/a&gt;
    &lt;a href=&quot;/blog/maven-releases-steroids-3.html&quot;&gt;series&lt;/a&gt; titled &apos;Maven Releases on Steroids&apos;. The goal of the
    series was to provide a simple and efficient way to produce releases on a Maven Project. Not only that, but
    it did so in a way that is compatible with Continuous Delivery.&lt;/p&gt;

&lt;p&gt;Maven has traditionally required the version number to be present in the project descriptor (pom.xml). This
    concept permeates through all aspects of the Maven ecosystem, culminating with the monstrosity commonly referred
    to as the Release Plugin.&lt;/p&gt;

&lt;p&gt;So how big exactly was the improvement of Releases On Steroids over the Release Plugin? See for yourself:&lt;/p&gt;

&lt;table class=&quot;table table-bordered&quot;&gt;
    &lt;tbody&gt;
    &lt;tr&gt;
        &lt;th&gt;&lt;/th&gt;
        &lt;th&gt;Releases on Steroids&lt;/th&gt;
        &lt;th&gt;Release Plugin&lt;/th&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Clean/Compile/Test cycle&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
        &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;POM transformations&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
        &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;Commits&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
        &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;SCM revisons&lt;/td&gt;
        &lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
        &lt;td style=&quot;color: red;&quot;&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;Fast forward to 2013&lt;/h3&gt;

&lt;p&gt;The original article was written in January 2011. Two and a half years have passed, and boy did thing
    change in the
    SCM space! In 2011, CVS was dead and burried, Subversion was well-established and both Git and Mercurial were on
    the rise and battling it out to be the Next Big Thing&amp;trade;.&lt;/p&gt;

&lt;p&gt;And then one thing happened: GitHub&apos;s popularity exploded. It triggered a mass-exodus from Sourceforge, Java.net
    and Google Code. The SCM war had been decided. Git was the new King of the Hill.&lt;/p&gt;

&lt;p&gt;Git then trickled down from its open-source roots into the deep dark SCM alleys of the enterprise, effectively
    relegating Subversion to legacy street.&lt;/p&gt;

&lt;p&gt;This change brings a number of advantages, of which one is of particular interest to us today: massively improved
    initial checkout performance.

    &lt;code&gt;git clone&lt;/code&gt; is orders of magnitude faster than &lt;code&gt;svn checkout&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;The Releases on Steroids process comes from a time where an initial checkout was slow. To keep performance in
    check
    the practice was to update the working copy with the latest changes instead of checking it out fresh every
    time. This meant that for the update to succeed the working copy could not contain local changes, as these would
    cause conflicts.&lt;/p&gt;

&lt;p&gt;The Releases on Steroids process went through great lengths (and worked around many Maven bugs) to ensure
    this.&lt;/p&gt;

&lt;p&gt;But now with the performance of Git, things have changed. And in change lies opportunity. So let&apos;s revisit
    Releases on Steroids and bring it into 2013&apos;s brave new world!&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;Revisiting the Release Process&lt;/h3&gt;

&lt;p&gt;Even though technology has evolved, the purpose of a release hasn&apos;t. What we want is being able to link a version of
    the
    software as deployed onto a machine back to the matching revision of the source code in SCM. This is essential
    to reproduce bugs and revert to previous versions deterministically if required.&lt;/p&gt;

&lt;p&gt;To accomplish this we have to go through a number of steps. At a minimum these include:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;checking out the software as it is&lt;/li&gt;
    &lt;li&gt;giving it a version so it can be uniquely identified&lt;/li&gt;
    &lt;li&gt;building, testing and packaging it&lt;/li&gt;
    &lt;li&gt;deploying it to an artifact repository where it can then be picked for actual roll out on target machines
    &lt;/li&gt;
    &lt;li&gt;tagging this state in SCM so it can be associated with the matching artifact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty simple, isn&apos;t it?&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;Releases with Maven and Git&lt;/h3&gt;

&lt;p&gt;Let&apos;s see what this translates to in a Git and Maven world:&lt;/p&gt;

&lt;ol&gt;
    &lt;li&gt;Checking the software out: &lt;code&gt;git clone&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Giving it a version: &lt;code&gt;mvn versions:set&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Building, testing, packaging and deploying it to an artifact repository: &lt;code&gt;mvn deploy&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;Tagging this state in SCM: &lt;code&gt;mvn scm:tag&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But first, the POM needs some preparation.&lt;/p&gt;

&lt;p&gt;Having the project version come from outside means we can use a simple generic snapshot version for the code
    checking into SCM. Our &lt;code&gt;pom.xml&lt;/code&gt; then looks like this:&lt;/p&gt;

    &lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;
    ...
    &amp;lt;version&amp;gt;0-SNAPSHOT&amp;lt;/version&amp;gt;
    ...
&amp;lt;/project&amp;gt;&lt;/pre&gt;

&lt;p&gt;We can now add our project&apos;s Git and artifact repository urls, as well as some basic plugin configuration:&lt;/p&gt;

    &lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;scm&amp;gt;
    &amp;lt;connection&amp;gt;scm:git:&lt;em&gt;&amp;lt;&amp;lt;your-git-repo-url&amp;gt;&amp;gt;&lt;/em&gt;&amp;lt;/connection&amp;gt;
&amp;lt;/scm&amp;gt;

&amp;lt;distributionManagement&amp;gt;
    &amp;lt;repository&amp;gt;
        &amp;lt;id&amp;gt;artifact-repository&amp;lt;/id&amp;gt;
        &amp;lt;url&amp;gt;&lt;em&gt;&amp;lt;&amp;lt;your-artifact-repo-url&amp;gt;&amp;gt;&lt;/em&gt;&amp;lt;/url&amp;gt;
    &amp;lt;/repository&amp;gt;
&amp;lt;/distributionManagement&amp;gt;

&amp;lt;build&amp;gt;
    &amp;lt;plugins&amp;gt;
        &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;versions-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.1&amp;lt;/version&amp;gt;
        &amp;lt;/plugin&amp;gt;
        &amp;lt;plugin&amp;gt;
            &amp;lt;artifactId&amp;gt;maven-scm-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;1.8.1&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
                &amp;lt;tag&amp;gt;${project.artifactId}-${project.version}&amp;lt;/tag&amp;gt;
            &amp;lt;/configuration&amp;gt;
        &amp;lt;/plugin&amp;gt;
    &amp;lt;/plugins&amp;gt;
&amp;lt;/build&amp;gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s it! Nothing more is required!&lt;/p&gt;

&lt;p&gt;Now let&apos;s take this 11 and integrate it in a CI environment. Jenkins is the absolute
    market leader, so that&apos;s what we&apos;ll use.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;Jenkins integration&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Jenkins with a JDK and Maven configured, and both
    the &lt;em&gt;Git&lt;/em&gt; and the &lt;em&gt;Workspace Cleanup&lt;/em&gt; plugins installed.&lt;/p&gt;

&lt;p&gt;We&apos;re going to start by creating a new Maven job and making sure we have a fresh workspace for every build:&lt;/p&gt;

&lt;img src=&quot;/assets/posts/final-nail/clean.png&quot;/&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;We can now point the job to our Git repository:&lt;/p&gt;

&lt;img src=&quot;/assets/posts/final-nail/git.png&quot;/&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;The next step is to set the version upon checkout. There are two main strategies we can apply:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Create a parametrized build and pass the version in&lt;/li&gt;
    &lt;li&gt;Let Jenkins assign the version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example we&apos;re going to use the latter. A good version number is both unique and chronological. We&apos;re
    going to use the Jenkins BUILD_NUMBER as it fulfills both these criteria wonderfully.&lt;/p&gt;

&lt;p&gt;So let&apos;s set the version in a pre-build step:&lt;/p&gt;

&lt;img src=&quot;/assets/posts/final-nail/version.png&quot;/&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;We are now ready to build, test, package, deploy (to the artifact repository) and tag (the Git repository):&lt;/p&gt;

&lt;img src=&quot;/assets/posts/final-nail/deploy.png&quot;/&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;All that is left now is deciding between&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Triggering the release build manually (the classic way)&lt;/li&gt;
    &lt;li&gt;Polling SCM to release after every commit (the Continuous Delivery way)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy releasing with Jenkins!&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;In this article we&apos;ve followed the footsteps of the Releases on Steroids articles and taken the concepts to their
    natural conclusion: &lt;strong&gt;the simplest and most effective way to create releases on projects using Maven and
        Git.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Along the way, we&apos;ve kept a strong focus on keeping as much knowledge as possible inside the POM. This keeps the
    release process concise and minimizes dependencies on specific environments or CI servers.&lt;/p&gt;

&lt;p&gt;So come with me and &lt;strong&gt;wave the Maven Release Plugin goodbye. This was the final nail in its coffin. Good
    riddance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p class=&quot;small&quot;&gt;P.S.: I&apos;ve published a companion repository on GitHub to get you started easily: &lt;a
        href=&quot;http://github.com/axelfontaine/final-nail&quot;&gt;http://github.com/axelfontaine/final-nail&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/database-popularity.html</id>
    <link type="text/html" rel="alternate" href="/blog/database-popularity.html"/>
    <title>Relational Database Popularity Ranking</title>
    <published>2013-03-23T00:00:00+00:00</published>
    <updated>2013-03-23T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div&gt;
    &lt;p&gt;
        While planing and developing features for &lt;a href=&quot;http://flywaydb.org/&quot;&gt;Flyway&lt;/a&gt;, I often wonder how the
        &lt;strong&gt;different relational databases&lt;/strong&gt; supported by Flyway stack up in terms of
        &lt;strong&gt;popularity&lt;/strong&gt;.&lt;/p&gt;

    &lt;p&gt;These are the results based on &lt;strong&gt;Google Analytics page view counts&lt;/strong&gt; of the database-specific pages
        in the &lt;a href=&quot;http://flywaydb.org/documentation/database/&quot;&gt;docs&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;This is a very imprecise measure at best, so take it with a grain of salt.&lt;/p&gt;

    &lt;p&gt;Ranking based on the analytics data from 2013-01-01 until 2013-03-23:&lt;/p&gt;

    &lt;table&gt;
        &lt;tr&gt;
            &lt;td&gt;
                &lt;ol&gt;
                    &lt;li&gt;Oracle&lt;/li&gt;
                    &lt;li&gt;MySQL&lt;/li&gt;
                    &lt;li&gt;PostgreSQL&lt;/li&gt;
                    &lt;li&gt;SQL Server&lt;/li&gt;
                    &lt;li&gt;H2&lt;/li&gt;
                    &lt;li&gt;Google Cloud SQL&lt;/li&gt;
                    &lt;li&gt;DB2&lt;/li&gt;
                    &lt;li&gt;Hsql&lt;/li&gt;
                    &lt;li&gt;Derby&lt;/li&gt;
                &lt;/ol&gt;
            &lt;/td&gt;
            &lt;td&gt;
                &lt;img src=&quot;/assets/posts/database-popularity/popularity-pie-chart.png&quot; alt=&quot;Pie Chart&quot;/&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;p&gt;Three big eye-openers for me so far:&lt;/p&gt;
    &lt;ul&gt;
        &lt;li&gt;The Oracle dominance is even stronger than I thought&lt;/li&gt;
        &lt;li&gt;H2 is more popular than Hsql and Derby, combined&lt;/li&gt;
        &lt;li&gt;Google Cloud SQL is surprisingly well represented&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&amp;nbsp;&lt;/p&gt;

    &lt;p&gt;What do you think? Does this match your experience?&lt;/p&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/flyway20.html</id>
    <link type="text/html" rel="alternate" href="/blog/flyway20.html"/>
    <title>Flyway 2.0 and Methods &amp; Tools article</title>
    <published>2012-11-20T00:00:00+00:00</published>
    <updated>2012-11-20T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;It was during the last days of 2010 that &lt;a
        href=&quot;http://flywaydb.org/documentation/releaseNotes.html#flyway-1.0&quot;&gt;Flyway 1.0&lt;/a&gt; saw the light of
    day.&lt;br/&gt;&lt;br/&gt;Since then almost 2 years and 11 months have passed. During this time Flyway improved considerably.
    Next to the Maven plugin and API, there is now a &lt;a href=&quot;http://flywaydb.org/documentation/commandline/&quot;&gt;Command-line
        tool&lt;/a&gt; and &lt;a href=&quot;http://flywaydb.org/documentation/ant/&quot;&gt;Ant tasks&lt;/a&gt;. Database support has vastly
    improved with the addition of &lt;a href=&quot;http://flywaydb.org/documentation/database/databaseSqlServer.html&quot;&gt;SQL
        Server&lt;/a&gt;, &lt;a href=&quot;http://flywaydb.org/documentation/database/databaseDb2.html&quot;&gt;DB2&lt;/a&gt;, &lt;a
            href=&quot;http://flywaydb.org/documentation/database/databaseDerby.html&quot;&gt;Derby&lt;/a&gt; and &lt;a
            href=&quot;http://flywaydb.org/documentation/database/databaseGoogleCloudSql.html&quot;&gt;Google Cloud SQL&lt;/a&gt;.
    Meanwhile, all of Flyway&apos;s dependencies have been made optional. Flyway now has zero required dependencies! And if
    that wasn&apos;t enough, many smaller features have been implemented and countless bugs have been fixed!&lt;br/&gt;

    &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
        &lt;a href=&quot;http://flywaydb.org/&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;224&quot; src=&quot;/assets/flyway-logo-tm.png&quot; width=&quot;320&quot;/&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;br/&gt;It&apos;s been quite a ride indeed! And now the next chapter can begin! &lt;a
            href=&quot;http://java.dzone.com/announcements/flyway-20-out-order-migrations&quot;&gt;&lt;b&gt;Flyway 2.0 was released&lt;/b&gt;&lt;/a&gt;
    a few days ago. The number of download has quadrupled in the last year, and there doesn&apos;t seem to be any stopping in
    sight!&lt;br/&gt;&lt;br/&gt;To celebrate Flyway&apos;s new release, I&apos;ve also launched a completely redesigned project home page and
    moved it to its own domain:&lt;b&gt; &lt;a href=&quot;http://flywaydb.org/&quot;&gt;flywaydb.org&lt;/a&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;For announcements or
    referencing the project, there is now also an own twitter account: &lt;a href=&quot;https://twitter.com/flywaydb&quot;&gt;&lt;b&gt;@flywaydb&lt;/b&gt;&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;And
    to make getting started even easier, I also wrote an &lt;b&gt;&lt;a href=&quot;http://www.methodsandtools.com/tools/flyway.php&quot;&gt;introductory
        article&lt;/a&gt;&lt;/b&gt; for &lt;a href=&quot;http://www.methodsandtools.com/&quot;&gt;Methods &amp;amp; Tools&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;The &lt;a
            href=&quot;http://flywaydb.org/documentation/roadmap.html&quot;&gt;future&lt;/a&gt; looks bright! Enjoy!&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/optional-dependencies.html</id>
    <link type="text/html" rel="alternate" href="/blog/optional-dependencies.html"/>
    <title>Optional Dependency Strategies for Java Libraries</title>
    <published>2012-08-06T00:00:00+00:00</published>
    <updated>2012-08-06T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;In software, contrary to common belief, &lt;b&gt;lines of code are a
    liability not an asset&lt;/b&gt;. As you gradually accumulate code, little by little the pain sets in. The complexity
increases. It gets harder to understand. And eventually, quality suffers.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Dependencies only&amp;nbsp;exacerbate&amp;nbsp;this
    problem.&lt;/b&gt; With each dependency you add, you pull in more code, more APIs to learn and more potential
bugs.&lt;br/&gt;&lt;br/&gt;&lt;a
        href=&quot;http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies&quot;&gt;Transitive
    dependencies&lt;/a&gt; take this problem to 11. You now have the possible issue of conflicting dependencies! And
before you know it ... you have landed in &lt;a href=&quot;http://en.wikipedia.org/wiki/Java_Classloader#jarhell&quot;&gt;JAR
    Hell&lt;/a&gt;! So much for laughing at our Windows friends stuck in&amp;nbsp;&lt;a
        href=&quot;http://en.wikipedia.org/wiki/DLL_hell&quot;&gt;DLL Hell&lt;/a&gt;...&lt;br/&gt;&lt;br/&gt;And yet, dependencies are a necessary
evil. If you want to avoid reinventing the wheel or if you want to integrate with the outside world, there very
often is no way to avoid them. In the spirit of &lt;a href=&quot;http://www.xprogramming.com/Practices/PracSimplest.html&quot;&gt;doing
    the simplest thing that could possibly work&lt;/a&gt;, strive to &lt;b&gt;reduce the number of dependencies to the absolute
    minimum required&lt;/b&gt;. Every single dependency you add should be weighed carefully: does the functional benefit
outweigh the complexity cost?&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Special case: Libraries and Frameworks&lt;/span&gt;
&lt;/h4&gt;&lt;br/&gt;A library&amp;nbsp;or framework&amp;nbsp;in broad general use&amp;nbsp;(like &lt;a
        href=&quot;http://code.google.com/p/flyway/&quot;&gt;Flyway&lt;/a&gt;) usually supports a wide range of scenarios for a very
diverse set of users. In Flyway&apos;s case this currently means dependencies on:&lt;br/&gt;
&lt;ul style=&quot;text-align: left;&quot;&gt;
    &lt;li&gt;10+ Jdbc Drivers&lt;/li&gt;
    &lt;li&gt;Spring Jdbc&lt;/li&gt;
    &lt;li&gt;OSGi (Equinox)&lt;/li&gt;
    &lt;li&gt;JBoss VFS v2&lt;/li&gt;
    &lt;li&gt;JBoss VFS v3&lt;/li&gt;
    &lt;li&gt;Ant&lt;/li&gt;
    &lt;li&gt;Maven&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;br/&gt;Nobody in their right mind would be keen on pulling all these dependencies in just to use the subset they
    need. And in fact, it wouldn&apos;t even be possible as some of them are conflicting! Yes, JBoss VFS v2 and v3, it&apos;s
    you I&apos;m looking at!
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;How do we solve this? How do we support all users without forcing all these dependencies onto each and everyone
    of them?
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;The answer lies in &lt;b&gt;optional dependencies&lt;/b&gt;.&lt;/div&gt;
&lt;div&gt;
    &lt;a href=&quot;http://www.amazon.de/gp/product/B005F2MVGO/ref=as_li_qf_sp_asin_tl?ie=UTF8&amp;amp;camp=1638&amp;amp;creative=6742&amp;amp;creativeASIN=B005F2MVGO&amp;amp;linkCode=as2&amp;amp;tag=axelfont-21&quot;&gt;&lt;img
            alt=&quot;Rock Band 2 Triple Cymbal Expansion Kit  (PS and PS3 compatible)&quot;
            src=&quot;http://ecx.images-amazon.com/images/I/41onyx-PtWL._SL500_AA300_.jpg&quot;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;There are &lt;b&gt;5 basic strategies&lt;/b&gt; for dealing with optional dependencies:&lt;/div&gt;
&lt;div&gt;
    &lt;ul style=&quot;text-align: left;&quot;&gt;
        &lt;li&gt;Create a separate module which depends on the base module and the optional dependency&lt;/li&gt;
        &lt;li&gt;Create a module per optional dependency which the base module depends on.&lt;/li&gt;
        &lt;li&gt;Mark the dependency as non-transitive and activate the functionality at runtime if present&lt;/li&gt;
        &lt;li&gt;Use reflection and activate the functionality at runtime if present&lt;/li&gt;
        &lt;li&gt;Use a Service Provider Interface and call the correct implementation at runtime&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div&gt;&lt;br/&gt;Each of these strategies has its pros and cons. Let&apos;s look at them in turn.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Separate Module&lt;/span&gt;&lt;/h4&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/posts/optional-dependencies/SeparateModule.png&quot; alt=&quot;Separate Module&quot;/&gt;
&lt;/div&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;b&gt;Typical use case:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Well-isolated dependencies that do not need to be combined together. In Flyway&apos;s case, this applies to the
    Ant and Maven dependencies. You will not need the Ant dependency when executing the Maven plugin and vice
    versa.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;b&gt;Advantage for the End-User:&lt;/b&gt;

&lt;div&gt;Smallest amount of code in KB as no code to support other optional dependencies is pulled in.&lt;/div&gt;
&lt;div&gt;All dependencies are transitive.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the End-User:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Must know which specific module from the library should be imported.&lt;br/&gt;Can only make use of one of the
    optional dependencies at a time.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Advantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Compile-time checking and IDE completion when working with the optional dependency.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Two modules to maintain and release instead of one.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;h4&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Module per Dependency&lt;/span&gt;&lt;/h4&gt;

&lt;div&gt;
    &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
    &lt;br/&gt;

    &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img
            src=&quot;/assets/posts/optional-dependencies/ModulePerDependency.png&quot;
            alt=&quot;Module per Dependency&quot;/&gt;&lt;/div&gt;
    &lt;div class=&quot;clear&quot;&gt;&lt;b&gt;Typical use case:&lt;/b&gt;&lt;/div&gt;
    &lt;div&gt;Dependencies that require a large amount of custom code to deal with. This becomes especially relevant
        in environments where application size has a direct impact on user experience. (Installation size vs
        download times on mobile, ...)
    &lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;b&gt;Advantage for the End-User:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Smallest amount of code in KB as no code to support other optional dependencies is pulled in.&lt;/div&gt;
&lt;div&gt;Can depend on multiple optional dependencies at the same time.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the End-User:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;No transitive dependency support. Must manually reference the correct library module for the optional
    dependency. &lt;br/&gt;Largest amount of modules to manage overall.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Advantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Compile-time checking and IDE completion when working with the optional dependency.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Two modules to maintain and release instead of one.&lt;br/&gt;All access to the code of the optional dependency
    support module must be carefully guarded to avoid NoClassDefFoundError.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;br class=&quot;Apple-interchange-newline&quot;/&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Non-transitive Dependency&lt;/span&gt;&lt;/b&gt;
&lt;/h4&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img
        src=&quot;/assets/posts/optional-dependencies/Optional.png&quot;
        alt=&quot;Optional&quot;/&gt;
&lt;/div&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;b&gt;Typical use case:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Dependencies that can be combined together. In Flyway&apos;s case, this applies to JBoss VFS, OSGi and Spring
    Jdbc. It is very well possible for a JBoss or an OSGi user to have Spring on board. Being able to use both
    at the same time is critical.
&lt;/div&gt;
&lt;br/&gt;&lt;b&gt;Advantage for the End-User:&lt;/b&gt;

&lt;div&gt;A single library module to depend upon.&lt;br/&gt;Can depend on multiple optional dependencies at the same time.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the End-User:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Must pull in some unused code to support the other missing optional dependencies.&lt;/div&gt;
&lt;div&gt;No transitive dependency support. Must manually reference optional dependency in own project.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Advantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Compile-time checking and IDE completion when working with the optional dependency.&lt;/div&gt;
&lt;div&gt;A single module to maintain and release.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;All access to the code relying on the optional dependency must be carefully guarded to avoid
    NoClassDefFoundError.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Reflection&lt;/span&gt;&lt;/h4&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/posts/optional-dependencies/Reflection.png&quot; alt=&quot;Reflection&quot;/&gt;
&lt;/div&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;b&gt;Typical use case:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Support multiple, mutually incompatible versions of the same dependency. In Flyway&apos;s case, this applies to
    JBoss VFS v2 and v3. Even though they have different package structures, they share the same artifact id.
    Maven will therefore always pull in the higher version. One of them can be declared and used as regular
    optional dependency, while the other must then be used via reflection (and not appear in the POM).
&lt;/div&gt;
&lt;div&gt;&lt;br class=&quot;Apple-interchange-newline&quot;/&gt;&lt;/div&gt;
&lt;b&gt;Advantage for the End-User:&lt;/b&gt;

&lt;div&gt;A single library module to depend upon.&lt;br/&gt;Can depend on multiple optional dependencies at the same time.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the End-User:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Must pull in some unused code to support the other missing optional dependencies.&lt;br/&gt;No transitive dependency
    support. Must manually reference optional dependency in own project.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Advantage for the Library
        Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Possibility to support multiple, mutually incompatible versions of the same dependency.&lt;/div&gt;
&lt;div&gt;A single module to maintain and release.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;The code relying on the optional dependency must use reflection, sacrificing readability and compiler safety.
&lt;/div&gt;
&lt;div&gt;
    &lt;div&gt;All access to the code relying on the optional dependency must be carefully guarded to avoid
        NoClassDefFoundError.
    &lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Service Provider Interface&lt;/span&gt;&lt;/h4&gt;

&lt;div&gt;&lt;img
        src=&quot;/assets/posts/optional-dependencies/SPI.png&quot;
        alt=&quot;SPI&quot;/&gt;&lt;/div&gt;
&lt;div class=&quot;clear&quot;&gt;&lt;b&gt;Typical use case:&lt;/b&gt;&lt;br/&gt;Support various implementations of the same
    interface. In Flyway&apos;s case, this applies to the Jdbc drivers. Flyway supports many of them, and yet
    they are all accessed through the same API (Jdbc).
&lt;/div&gt;
&lt;div&gt;&lt;br class=&quot;Apple-interchange-newline&quot;/&gt;&lt;/div&gt;
&lt;b&gt;Advantage for the End-User:&lt;/b&gt;

&lt;div&gt;A single library module to depend upon.&lt;br/&gt;Smallest amount of code in KB as only code to support the
    common SPI is pulled in.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the End-User:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;No transitive dependency support. Must manually reference optional dependency in own project.&lt;br/&gt;May have
    to configure which SPI implementation to use.
&lt;/div&gt;
&lt;div&gt;&lt;br class=&quot;Apple-interchange-newline&quot;/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Advantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Common SPI to program against, with compile-time checking and IDE completion.&lt;/div&gt;
&lt;div&gt;A single module to maintain and release.&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Disadvantage for the Library Developer:&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;Must match the SPI with its implementation at runtime. Failure to properly do so will result in Exceptions
    at runtime.&lt;br/&gt;Should test the library with the different SPI implementations to ensure they behave as
    expected.
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span
        style=&quot;font-size: x-large;&quot;&gt;Checking if a dependency is present at runtime&lt;/span&gt;&lt;/h4&gt;

&lt;div&gt;&lt;br/&gt;A number of these strategies depend on being able to check whether a certain dependency is available at
    runtime and guard against using its related features if it isn&apos;t.&lt;br/&gt;&lt;br/&gt;This sounds complicated, but it turns
    out to be relatively easy on the Java platform: &lt;br/&gt;
    &lt;pre class=&quot;prettyprint&quot;&gt;public static boolean isPresent(String className) {&lt;br/&gt;    try {&lt;br/&gt;        Class.forName(className);&lt;br/&gt;        return true;&lt;br/&gt;    } catch (Throwable ex) {&lt;br/&gt;        // Class or one of its dependencies is not present...&lt;br/&gt;        return false;&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;...&lt;br/&gt;&lt;br/&gt;if (isPresent(&quot;com.optionaldependency.DependencyClass&quot;)) {&lt;br/&gt;    // This block will never execute when the dependency is not present&lt;br/&gt;    // There is therefore no more risk of code throwing NoClassDefFoundException.&lt;br/&gt;    executeCodeLinkingToDependency();&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;Conclusion&lt;/span&gt;&lt;/h4&gt;

&lt;div&gt;&lt;br/&gt;The 5 different strategies each deal with different scenarios and different forces that must be balanced.
    Even in a relatively small library like Flyway, it wasn&apos;t possible to simply rely on a single one. Know them
    well and know when to use them. But if there has to be a single most important guideline to remember, let it be
    this one:
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;b&gt;Always favor the convenience of the end-user over your own when designing your library or framework.&lt;/b&gt;
&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div&gt;Thanks for reading this far! Find out more and stay in touch by &lt;a href=&quot;https://twitter.com/axelfontaine&quot;&gt;following
    me on Twitter&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/private-methods.html</id>
    <link type="text/html" rel="alternate" href="/blog/private-methods.html"/>
    <title>Testing private methods: easier than you think!</title>
    <published>2012-07-10T00:00:00+00:00</published>
    <updated>2012-07-10T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div dir=&quot;ltr&quot; style=&quot;text-align: left;&quot; trbidi=&quot;on&quot;&gt;Testing private methods is something that has traditionally drawn
    &lt;a href=&quot;http://stackoverflow.com/questions/34571/whats-the-proper-way-to-test-a-class-with-private-methods-using-junit&quot;&gt;heated
        debates&lt;/a&gt; in the Java world.&lt;br/&gt;&lt;br/&gt;The solutions usually fall into 4 categories:&lt;br/&gt;
    &lt;ul style=&quot;text-align: left;&quot;&gt;
        &lt;li&gt;Don&apos;t test private methods&lt;/li&gt;
        &lt;li&gt;Use reflection&lt;/li&gt;
        &lt;li&gt;Use a nested class&lt;/li&gt;
        &lt;li&gt;Change the visibility&lt;/li&gt;
    &lt;/ul&gt;
    &lt;div&gt;&lt;br/&gt;Let&apos;s look at them in turn:&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;b&gt;Don&apos;t test private methods&lt;/b&gt;&lt;/div&gt;
    &lt;div&gt;&lt;b&gt;&lt;br/&gt;&lt;/b&gt;&lt;/div&gt;
    &lt;div&gt;This really leaves us with three choices:&lt;/div&gt;
    &lt;div&gt;
        &lt;ul style=&quot;text-align: left;&quot;&gt;
            &lt;li&gt;refactor to make the method public in some helper class&lt;/li&gt;
            &lt;li&gt;test through a calling method with a higher visibility&lt;/li&gt;
            &lt;li&gt;give up&lt;/li&gt;
        &lt;/ul&gt;
        &lt;div&gt;A delightful choice between increased bloat, higher test complexity and resignation!&lt;/div&gt;
    &lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;No, thank you!&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;b&gt;Use reflection&lt;/b&gt;&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;Why make things simple when you can also make them hard and long-winded? Haven&apos;t you always been dreaming of
        needing 10 lines of code to make a method call?&amp;nbsp;(Yes, there are now even entire&amp;nbsp;&lt;a
                href=&quot;http://dp4j.com/&quot;&gt;tools&lt;/a&gt;&amp;nbsp;dedicated to this big operation!)&amp;nbsp;Extra bonus points because
        you can now also prevent your IDE&apos;s compiler and refactoring tools from helping you!
    &lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;No, thank you!&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;b&gt;Use a nested class&lt;/b&gt;&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;No too bad, but with 3 significant drawbacks: &lt;br/&gt;
        &lt;ul style=&quot;text-align: left;&quot;&gt;
            &lt;li&gt;no separate sources / test sources folders&lt;/li&gt;
            &lt;li&gt;larger classes&lt;/li&gt;
            &lt;li&gt;unit test code in production binaries&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/div&gt;
    &lt;div&gt;We can do better.&lt;br/&gt;&lt;br/&gt;No thank you!&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;&lt;b&gt;Change the visibility&lt;/b&gt;&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;This leaves us with the last option. Not perfect either, but by far the most pragmatic!&lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;&lt;/div&gt;
    &lt;div&gt;It trades a slight increase in visibility (to package-protected) for greatly simplified calling (a regular
        method call, no less!), while still preserving the valuable sources / test sources separation.
    &lt;/div&gt;
    &lt;div&gt;&lt;br/&gt;And with a simple&amp;nbsp;documentation&amp;nbsp;habit, it becomes clear to everyone why this design trade-off
        was made:
    &lt;/div&gt;
    &lt;div&gt;
        &lt;pre class=&quot;prettyprint&quot;&gt;/* private -&amp;gt; testing */ void myMethodUnderTest() {&lt;br/&gt;    ...&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
        &lt;br/&gt;&lt;br/&gt;So the next time you face this problem, choose the pragmatic route. And enjoy a coffee while everyone
        else is still trying to complicate things. :-)&lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/getting-to-yes.html</id>
    <link type="text/html" rel="alternate" href="/blog/getting-to-yes.html"/>
    <title>One Minute Book Review: Getting To Yes</title>
    <published>2011-05-30T00:00:00+00:00</published>
    <updated>2011-05-30T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">Today I take a look at a big classic from the field of negotiation: Roger Fisher&apos;s and William Ury&apos;s&lt;br/&gt;&lt;a
        href=&quot;http://www.amazon.de/gp/product/1844131467/ref=as_li_tf_tl?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=1844131467&quot;&gt;&lt;b&gt;Getting
    to Yes: Negotiating an agreement without giving in&lt;/b&gt;&lt;/a&gt;&lt;img
        src=&quot;http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=1844131467&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot;
        alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot;/&gt;.&lt;br/&gt;&lt;br/&gt;&lt;p align=&quot;center&quot;&gt;&lt;a
        href=&quot;http://www.amazon.de/gp/product/1844131467/ref=as_li_tf_il?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=1844131467&quot;&gt;&lt;img
        border=&quot;0&quot; src=&quot;/assets/posts/getting-to-yes/getting-to-yes.jpg&quot;/&gt;&lt;/a&gt;&lt;img
        src=&quot;http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=1844131467&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot;
        alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;br/&gt;
&lt;b&gt;Negotiation&lt;/b&gt; is really only about one thing: &lt;b&gt;getting what you
    want&lt;/b&gt;. 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&apos;t matter. We negotiate
&lt;b&gt;all the time&lt;/b&gt; and the outcome of our negotiations &lt;b&gt;greatly influences&lt;/b&gt; our lives.&lt;br/&gt;
&lt;br/&gt;And yet, this is a skill most of us in software engineering &lt;b&gt;didn&apos;t receive any formal
    training&lt;/b&gt; in. Professionally the matter is even worse. Most of our &quot;opponents&quot;, ranging from managers to sales people, have both more practice and better training. This leaves us fighting an uphill battle!
&lt;br/&gt;&lt;br/&gt;We must stand up and level the playing field!&lt;br/&gt;
&lt;br/&gt;I found Roger Fisher and William Ury to be powerful allies for this quest.&lt;br/&gt;
&lt;br/&gt;Getting To Yes makes the case for &lt;b&gt;principled negotiation&lt;/b&gt;. The main focus is reaching a &lt;b&gt;mutually
    satisfying
    agreement&lt;/b&gt;. This implies meeting the needs of both parties, and resisting the urge of trying to &quot;win&quot; against your opponent.
&lt;br/&gt;&lt;br/&gt;The reason they designed this method, is because most people get &lt;b&gt;stuck bargaining over
    positions&lt;/b&gt;, effectively creating a win-lose situation.&lt;br/&gt;
&lt;br/&gt;The alternative is to take a step back and understand what your opponent really wants. Once his
&lt;b&gt;interests&lt;/b&gt; have been &lt;b&gt;uncovered&lt;/b&gt;, you can then look whether the pie can be divided or whether &lt;b&gt;new
    options&lt;/b&gt; should be &lt;b&gt;invented for mutual
    gain&lt;/b&gt;. 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.
&lt;br/&gt;&lt;br/&gt;If the negotiation gets difficult, make sure you &lt;b&gt;focus on the problem and not on the
    people&lt;/b&gt;. You should always insist on &lt;b&gt;objective
    criterias&lt;/b&gt;. And if all that doesn&apos;t work, you should have another plan ready: your BATNA (&lt;b&gt;Best Alternative To
    Negotiated Agreement&lt;/b&gt;).&lt;br/&gt;
&lt;br/&gt;I found this book to be immensely useful. And I am not alone thinking this: they have sold millions of copies!&lt;br/&gt;
&lt;br/&gt;&lt;b&gt;Highly recommended.&lt;/b&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/getting-past-no.html</id>
    <link type="text/html" rel="alternate" href="/blog/getting-past-no.html"/>
    <title>One Minute Book Review: Getting Past No</title>
    <published>2011-05-29T00:00:00+00:00</published>
    <updated>2011-05-29T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">Last month I finally finished reading a book I&apos;ve been wanting to read for a long time: William Ury&apos;s&lt;br/&gt;&lt;a
        href=&quot;http://www.amazon.de/gp/product/0712655239/ref=as_li_tf_tl?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=0712655239&quot;&gt;&lt;b&gt;Getting
    Past No: Negotiating with Difficult People&lt;/b&gt;&lt;/a&gt;&lt;img
        src=&quot;http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=0712655239&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot;
        alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot;/&gt;.&lt;br/&gt;&lt;br/&gt;&lt;p align=&quot;center&quot;&gt;&lt;a
        href=&quot;http://www.amazon.de/gp/product/0712655239/ref=as_li_tf_il?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=0712655239&quot;&gt;&lt;img
        border=&quot;0&quot; src=&quot;/assets/posts/getting-past-no/getting-past-no.jpg&quot;&gt;&lt;/a&gt;&lt;img
        src=&quot;http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=0712655239&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot;
        alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot;/&gt;&lt;br/&gt;&lt;/p&gt;&lt;br/&gt;
&lt;b&gt;Negotiation&lt;/b&gt; is really only about one thing: &lt;b&gt;getting what you
    want&lt;/b&gt;. 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&apos;t matter. We negotiate
&lt;b&gt;all the time&lt;/b&gt; and the outcome of our negotiations &lt;b&gt;greatly influences&lt;/b&gt; our lives.&lt;br/&gt;
&lt;br/&gt;And yet, this is a skill most of us in software engineering &lt;b&gt;didn&apos;t receive any formal
    training&lt;/b&gt; in. Professionally the matter is even worse. Most of our &quot;opponents&quot;, ranging from managers to sales people, have both more practice and better training. This leaves us fighting an uphill battle!
&lt;br/&gt;&lt;br/&gt;We must stand up and level the playing field!&lt;br/&gt;
&lt;br/&gt;I found William Ury to be a powerful ally for this quest.&lt;br/&gt;
&lt;br/&gt;&lt;b&gt;Highly recommended.&lt;/b&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/continuous-delivery-parleys.html</id>
    <link type="text/html" rel="alternate" href="/blog/continuous-delivery-parleys.html"/>
    <title>Continuous Delivery Talk on Parleys</title>
    <published>2011-05-27T00:00:00+00:00</published>
    <updated>2011-05-27T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">Earlier this month I was at the &lt;a
        href=&quot;http://www.bejug.org/confluenceBeJUG/display/BeJUG/Continuous+Delivery&quot;&gt;BeJUG&lt;/a&gt; in Leuven to present my
&lt;b&gt;Continuous Delivery&lt;/b&gt; talk.&lt;br/&gt;
&lt;br/&gt;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
&lt;a href=&quot;https://twitter.com/#!/Stephan007&quot;&gt;Stephan Janssen&lt;/a&gt; of &lt;a href=&quot;http://www.devoxx.com&quot;&gt;Devoxx&lt;/a&gt; and &lt;a
        href=&quot;http://parleys.com&quot;&gt;Parleys&lt;/a&gt; fame. And so, with the precious help of &lt;a
        href=&quot;https://twitter.com/#!/danieldeluca&quot;&gt;Daniel De Luca&lt;/a&gt; they made the talk &lt;a
        href=&quot;http://parleys.com/#id=2443&amp;sl=0&amp;st=5&quot;&gt;available online at Parleys.com&lt;/a&gt; as well!&lt;br/&gt;
&lt;br/&gt;Here are some pictures of the event (more on the &lt;a
        href=&quot;http://www.bejug.org/confluenceBeJUG/display/BeJUG/Continuous+Delivery&quot;&gt;BeJUG&lt;/a&gt; page):&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;132&quot; width=&quot;200&quot;
                                                                     src=&quot;/assets/posts/continuous-delivery-parleys/DSC_1369.jpg&quot;
                                                                     style=&quot;padding: 5px;&quot;/&gt; &lt;img border=&quot;0&quot;
                                                                                                  height=&quot;132&quot;
                                                                                                  width=&quot;200&quot;
                                                                                                  src=&quot;/assets/posts/continuous-delivery-parleys/DSC_1397.jpg&quot;
                                                                                                  style=&quot;padding: 5px;&quot;/&gt;
    &lt;img border=&quot;0&quot; height=&quot;132&quot; width=&quot;200&quot;
         src=&quot;/assets/posts/continuous-delivery-parleys/DSC_1401.jpg&quot;
         style=&quot;padding: 5px;&quot;/&gt;&lt;br/&gt;&lt;/div&gt;&lt;br/&gt;And here is the presentation on &lt;a
        href=&quot;http://parleys.com/#sl=0&amp;st=5&amp;id=2443&quot;&gt;Parleys&lt;/a&gt;:&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
    &lt;object width=&quot;660&quot; height=&quot;590&quot;&gt;
        &lt;param name=&quot;movie&quot; value=&quot;http://www.parleys.com/share/parleysshare2.swf?pageId=2443&quot;/&gt;
        &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;
        &lt;param name=&quot;pageId&quot; value=&quot;2443&quot;/&gt;
        &lt;embed src=&quot;http://www.parleys.com/share/parleysshare2.swf?pageId=2443&quot; type=&quot;application/x-shockwave-flash&quot;
               allowfullscreen=&quot;true&quot; width=&quot;660&quot; height=&quot;590&quot;/&gt;
    &lt;/object&gt;
    &lt;br/&gt;&lt;/div&gt;
&lt;br/&gt;Thank you very much to all the ones that came. It was an absolute pleasure for me. And for all the ones who didn&apos;t have the chance to come, enjoy watching it online!
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/environment-detection.html</id>
    <link type="text/html" rel="alternate" href="/blog/environment-detection.html"/>
    <title>Environment Detection</title>
    <published>2011-05-26T00:00:00+00:00</published>
    <updated>2011-05-26T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">One of the key aspects of my &lt;a href=&quot;/blog/continuous-delivery-rheinjug.html&quot;&gt;&lt;b&gt;Continuous&lt;/b&gt;&lt;/a&gt;
&lt;a href=&quot;http://parleys.com/#st=5&amp;id=2443&quot;&gt;&lt;b&gt;Delivery&lt;/b&gt;&lt;/a&gt; talks is applications being aware of where they are.&lt;br/&gt;
&lt;br/&gt;&lt;b&gt;Environment
    Detection&lt;/b&gt; stands for the ability to sense in which environment an application is currently deployed using the simplest means at its disposal.
&lt;br/&gt;
&lt;br/&gt;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.
&lt;br/&gt;
&lt;br/&gt;This is powerful and simpler than it sounds. I&apos;ll show you a number of ways to implement the detection and then, we&apos;ll look at how to integrate it in an application. But always remember: use the simplest technique that works for you.
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;The most common detection strategies are:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;IP Address/Range&lt;/li&gt;
    &lt;li&gt;HostName&lt;/li&gt;
    &lt;li&gt;File contents&lt;/li&gt;
    &lt;li&gt;Operating System&lt;/li&gt;
    &lt;li&gt;System Property&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;Let&apos;s have a look at how to implement them in Java.&lt;br/&gt;&lt;br/&gt;&lt;h4&gt;IP Address/Range&lt;/h4&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;// Assuming 1.2.3.4 is the IP Address of your DEV machine&lt;br/&gt;// and 5.6.7.x is the IP Range of your PROD environment&lt;br/&gt;String ipAddress = InetAddress.getLocalHost().getHostAddress();&lt;br/&gt;if (&quot;1.2.3.4&quot;.equals(ipAddress)) {&lt;br/&gt;    // DEV&lt;br/&gt;} else if (ipAddress.startsWith(&quot;5.6.7.&quot;)) {&lt;br/&gt;    // PROD&lt;br/&gt;}&lt;/pre&gt;
&lt;br/&gt;&lt;h4&gt;HostName&lt;/h4&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;// Assuming abc and def are the hostNames of your DEV and PROD servers&lt;br/&gt;String hostName = InetAddress.getLocalHost().getHostName();&lt;br/&gt;if (&quot;abc&quot;.equals(hostName)) {&lt;br/&gt;    // DEV&lt;br/&gt;} else if (&quot;def&quot;.equals(hostName)) {&lt;br/&gt;    // PROD&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;h4&gt;File contents&lt;/h4&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;import org.springframework.util.FileCopyUtils;&lt;br/&gt;&lt;br/&gt;// Assuming /etc/my.env exists&lt;br/&gt;// and contains the name of the environment such as DEV, TEST, PROD, ...&lt;br/&gt;String environment = FileCopyUtils.copyToString(new FileReader(&quot;/etc/my.env&quot;));&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;h4&gt;Operating System&lt;/h4&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;// Assuming DEV is on Windows and PROD on Linux&lt;br/&gt;String operatingSystem = System.getProperty(&quot;os.name&quot;);&lt;br/&gt;if (operatingSystem.startsWith(&quot;Windows&quot;)) {&lt;br/&gt;    // DEV&lt;br/&gt;} else {&lt;br/&gt;    // PROD&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;h4&gt;System Property&lt;/h4&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;// Assuming my.env is set&lt;br/&gt;// and contains the name of the environment such as DEV, TEST, PROD, ...&lt;br/&gt;String environment = System.getProperty(&quot;my.env&quot;);&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;And that&apos;s all there is to it !&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Here is a &lt;b&gt;quick
    example&lt;/b&gt; of how to leverage this newly acquired piece of information:&lt;br/&gt;
&lt;br/&gt;Say we use a framework like Spring and want to easily load the &lt;b&gt;appropriate configuration for the current
    environment&lt;/b&gt;.&lt;br/&gt;
&lt;br/&gt;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.
&lt;br/&gt;&lt;br/&gt;We can now load the appropriate configuration like this:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;bean id=&quot;environmentDetectionService&quot; class=&quot;my.pkg.EnvironmentDetectionService&quot;&lt;br/&gt;    init-method=&quot;detectEnvironment&quot;/&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;bean&lt;br/&gt;    class=&quot;org.springframework.beans.factory.config.PropertyPlaceholderConfigurer&quot;&lt;br/&gt;    depends-on=&quot;environmentDetectionService&quot;&amp;gt;&lt;br/&gt;    &amp;lt;property name=&quot;location&quot; value=&quot;/config/${my.env}/my.properties&quot;/&amp;gt;&lt;br/&gt;&amp;lt;/bean&amp;gt;&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Environment
    Detection&lt;/b&gt; is a simple, yet very powerful capability. Start using it today and you&apos;ll never look back!
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/continuous-delivery-rheinjug.html</id>
    <link type="text/html" rel="alternate" href="/blog/continuous-delivery-rheinjug.html"/>
    <title>Continuous Delivery Talk at the Rheinjug (in German)</title>
    <published>2011-04-05T00:00:00+00:00</published>
    <updated>2011-04-05T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">On Thursday I had the pleasure to go and present my &lt;b&gt;Continuous Delivery&lt;/b&gt; talk (in German) at the &lt;a
        href=&quot;http://rheinjug.de/&quot;&gt;&lt;b&gt;rheinjug&lt;/b&gt;&lt;/a&gt; in Düsseldorf.&lt;br/&gt;
&lt;br/&gt;I really enjoyed my visit. The organisation was great, and it drew a large and interesting crowd. We had a great Q&amp;amp;A session, and the conversation continued for a few more hours around some fine beers at the social event.
&lt;br/&gt;&lt;br/&gt;I&apos;ve made the slides of the talk available on &lt;a
        href=&quot;http://www.slideshare.net/axelfontaine/continuous-delivery-7524266&quot;&gt;slideshare&lt;/a&gt;:&lt;br/&gt;&lt;br/&gt;
&lt;div id=&quot;__ss_7524266&quot; style=&quot;text-align: center; width: 100%;&quot;&gt;
    &lt;object height=&quot;520&quot; id=&quot;__sse7524266&quot; width=&quot;640&quot;&gt;
        &lt;param name=&quot;movie&quot;
               value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=continuousdeliveryrheinjug-110405111733-phpapp02&amp;stripped_title=continuous-delivery-7524266&amp;userName=axelfontaine&quot;/&gt;
        &lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;
        &lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;
        &lt;embed name=&quot;__sse7524266&quot;
               src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=continuousdeliveryrheinjug-110405111733-phpapp02&amp;stripped_title=continuous-delivery-7524266&amp;userName=axelfontaine&quot;
               type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;640&quot;
               height=&quot;520&quot;&gt;&lt;/embed&gt;
    &lt;/object&gt;
&lt;/div&gt;&lt;br/&gt;The video is now &lt;a
        href=&quot;http://rheinjug.de/videos/gse.lectures.app/Talk.html#ContinuousDelivery&quot;&gt;online&lt;/a&gt; as well:&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a
        href=&quot;http://rheinjug.de/videos/gse.lectures.app/Talk.html#ContinuousDelivery&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;422&quot;
                                                                                            src=&quot;/assets/posts/continuous-delivery-rheinjug/video.png&quot;
                                                                                            width=&quot;640&quot;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br/&gt;Thanks to everyone who came. I hope you enjoyed it. I sure did :-)
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/inbound-marketing.html</id>
    <link type="text/html" rel="alternate" href="/blog/inbound-marketing.html"/>
    <title>One Minute Book Review: Inbound Marketing</title>
    <published>2011-02-20T00:00:00+00:00</published>
    <updated>2011-02-20T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">Over the Christmas holiday, I finally got around to something I had planned for a while: reading Brian Halligan&apos;s and Dharmesh Shah&apos;s very popular
&lt;br/&gt;&lt;b&gt;&lt;a
        href=&quot;http://www.amazon.de/gp/product/0470499311?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=0470499311&quot;&gt;Inbound
    Marketing&lt;/a&gt;&lt;img src=&quot;http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=0470499311&quot; width=&quot;1&quot; height=&quot;1&quot;
                      border=&quot;0&quot; alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot;/&gt;: Get Found using
    Google, Social Media, and Blogs&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;&lt;p align=&quot;center&quot;&gt;&lt;a
        href=&quot;http://www.amazon.de/gp/product/0470499311?ie=UTF8&amp;tag=axelfont-21&amp;linkCode=as2&amp;camp=1638&amp;creative=6742&amp;creativeASIN=0470499311&quot;&gt;&lt;img
        border=&quot;0&quot; src=&quot;/assets/posts/inbound-marketing/inbound-marketing.jpg&quot;&gt;&lt;/a&gt;&lt;img
        src=&quot;http://www.assoc-amazon.de/e/ir?t=axelfont-21&amp;l=as2&amp;o=3&amp;a=0470499311&quot; width=&quot;1&quot; height=&quot;1&quot; border=&quot;0&quot;
        alt=&quot;&quot; style=&quot;border:none !important; margin:0px !important;&quot;/&gt;&lt;/p&gt;&lt;br/&gt;&lt;b&gt;The business world is changing. And
    it&apos;s changing
    fast.&lt;/b&gt; One of the most interesting statistics supporting this does not appear until the last chapter of the book. Here it is:
&lt;br/&gt;
&lt;br/&gt;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.
&lt;b&gt;Of the 500 companies in the Fortune 500 in 1995, only 250 remained in 2009!&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;So why did companies like Amazon, eBay and Google replace other ones likes Toys &apos;R&apos; Us and Polaroid? The answer to this question is very much related to why Obama defeated McCain in the 2008 US presidential elections.
&lt;br/&gt;&lt;br/&gt;&lt;i&gt;So what did the Obama campaign have in common with Amazon, eBay and Google?&lt;/i&gt;&lt;br/&gt;
&lt;br/&gt;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.
&lt;br/&gt;&lt;br/&gt;The point Brian and Dharmesh make is that this &lt;b&gt;50 year era of outbound marketing is coming to a
    close&lt;/b&gt;. People are getting increasingly better at blocking out these messages.&lt;br/&gt;
&lt;br/&gt;We are now at the dawn of a new era in the field of marketing: &lt;b&gt;inbound
    marketing&lt;/b&gt;. Instead of focusing on bombarding as many people as possible with a message they don&apos;t want to hear, there are new rules that must be mastered on the road to success.
&lt;b&gt;Producing remarkable content&lt;/b&gt; that people want to read about is the way forward. &lt;b&gt;Turning customers into
    fans&lt;/b&gt;.&lt;br/&gt;
&lt;br/&gt;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.
&lt;b&gt;Quality trumps dollars&lt;/b&gt;. And yet, all of a sudden the &lt;b&gt;competition became global&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;&lt;i&gt;How can you
    and your company stand out and become better at this game?&lt;/i&gt;&lt;br/&gt;
&lt;br/&gt;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!
&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Highly recommended.&lt;/b&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/maven-releases-steroids-3.html</id>
    <link type="text/html" rel="alternate" href="/blog/maven-releases-steroids-3.html"/>
    <title>Maven Releases on Steroids (3): Rounding it up with Jenkins</title>
    <published>2011-02-10T00:00:00+00:00</published>
    <updated>2011-02-10T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div class=&quot;well well-small&quot;&gt;&lt;strong&gt;Update:&lt;/strong&gt; I updated this article in 2013 as &lt;a href=&quot;/blog/final-nail.html&quot;&gt;Maven Release Plugin: The Final Nail in the Coffin&lt;/a&gt;&lt;/div&gt;

In &lt;a href=&quot;/blog/maven-releases-steroids-2.html&quot;&gt;&lt;b&gt;Part
    2&lt;/b&gt;&lt;/a&gt;, we looked at what changes where necessary to the Maven POMs to make it all work.&lt;br/&gt;
&lt;br/&gt;In this final part, we&apos;ll put the finishing touch by choosing a &lt;b&gt;version number&lt;/b&gt; strategy and
&lt;b&gt;integrating&lt;/b&gt; what we have so far &lt;b&gt;with Jenkins&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;Version
    Number&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;A good version number has a number of properties:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;b&gt;Natural order:&lt;/b&gt; it should be possible to determine at a glance between two versions which one is newer
    &lt;/li&gt;
    &lt;li&gt;&lt;b&gt;Maven support:&lt;/b&gt; Maven should be able to deal with the format of the version number to enfore the natural
        order
    &lt;/li&gt;
    &lt;li&gt;&lt;b&gt;Machine incrementable:&lt;/b&gt; so you don&apos;t have to specify it explicitely every time&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;Typical candidates can be:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;build number&lt;/li&gt;
    &lt;li&gt;timestamp (in a suitable format such as yyyy.MM.dd.HH.mm)&lt;/li&gt;
    &lt;li&gt;revision number (SVN only)&lt;/li&gt;
&lt;/ul&gt;
&lt;br/&gt;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
&lt;a href=&quot;http://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-JenkinsSetEnvironmentVariables&quot;&gt;a number of environments
    variables&lt;/a&gt;. A few of these are particularly interesting:&lt;br/&gt;&lt;br/&gt;
&lt;blockquote&gt;
    &lt;table border=&quot;1&quot;&gt;
        &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th style=&quot;padding: 10px;&quot;&gt;Environment Variable&lt;/th&gt;
            &lt;th&gt;Description&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;BUILD_NUMBER&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;The current build number, such as &quot;153&quot;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;BUILD_ID&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;The current build id, such as &quot;2005-08-22_23-59-59&quot; (YYYY-MM-DD_hh-mm-ss)&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;SVN_REVISION&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;For Subversion-based projects, this variable contains the revision number of the
                module. If you have more than one module specified, this won&apos;t be set.
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;
&lt;/blockquote&gt;&lt;br/&gt;In this article, we&apos;&apos;ll use the
&lt;b&gt;BUILD_NUMBER&lt;/b&gt; 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.
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;Jenkins&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;The first thing to do is to set up a new Maven 2/3 project.&lt;br/&gt;&lt;br/&gt;In this project you must&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;configure the &lt;b&gt;SCM URL&lt;/b&gt;&lt;/li&gt;
    &lt;li&gt;set the &lt;b&gt;Maven Goals and options&lt;/b&gt; to&lt;br/&gt;clean deploy scm:tag -DVERSION_NUMBER=&lt;b&gt;${BUILD_NUMBER}&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/maven-releases-steroids-3/JenkinsConfig.png&quot;
                                                                          alt=&quot;Jenkins Config&quot;/&gt;&lt;/div&gt;
&lt;br/&gt;And that&apos;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.
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;A small note for Nexus users:&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;In order to allow Maven to &lt;b&gt;upload the corrected POMs&lt;/b&gt; from Part 2 of this article, you need to set the &lt;b&gt;Deployment
    Policy&lt;/b&gt; of the &lt;i&gt;Releases&lt;/i&gt; repository to &lt;b&gt;Allow Redeploy&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/maven-releases-steroids-3/NexusConfig.png&quot;
                                                                          alt=&quot;Nexus Config&quot;/&gt;&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;Next step&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;You&apos;re now ready to add a build trigger on SCM changes in Jenkins. Once you have this,&lt;b&gt;every&lt;/b&gt; commit causing a
&lt;b&gt;green build&lt;/b&gt; will produce a &lt;b&gt;new release&lt;/b&gt;. It&apos;s the next step up.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;Download&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;Last, but not least, here is a sample &lt;b&gt;multi-module Maven
    Project&lt;/b&gt; with all the POMs correctly set up available for &lt;a
        href=&quot;/assets/posts/maven-releases-steroids-3/releasesonsteroids.zip&quot;&gt;&lt;b&gt;download&lt;/b&gt;&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;Conclusion&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;Looking back at the workflow of the Release Plugin we discussed in &lt;a
        href=&quot;/blog/maven-releases-steroids.html&quot;&gt;&lt;b&gt;Part
    1&lt;/b&gt;&lt;/a&gt;, we have come a long way!&lt;br/&gt;&lt;br/&gt;If you&apos;re willing to live with 3 simple things:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;you do NOT depend on SNAPSHOTs, ever.&lt;/li&gt;
    &lt;li&gt;the POM does not contain the version number&lt;/li&gt;
    &lt;li&gt;you ALWAYS build releases from a CI server, and NEVER locally on a developer&apos;s machine&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;you can now enjoy &lt;b&gt;very fast (3x) and robust releases&lt;/b&gt;, without the headaches of the Release Plugin.&lt;br/&gt;
&lt;br/&gt;For reference:&lt;br/&gt;
&lt;blockquote&gt;
    &lt;table border=&quot;1&quot;&gt;
        &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;&lt;/th&gt;
            &lt;th style=&quot;padding: 10px;&quot;&gt;Releases on Steroids&lt;/th&gt;
            &lt;th style=&quot;padding: 10px;&quot;&gt;Release Plugin&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;clean/compile/test cycle&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: red;&quot;&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;POM transformations&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;b&gt;0 &lt;/b&gt;&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: red;&quot;&gt;2&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;commits&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;b&gt;0 &lt;/b&gt;&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: red;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;SCM revisons&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/td&gt;
            &lt;td style=&quot;padding: 10px;&quot;&gt;&lt;b&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: red;&quot;&gt;3&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;
&lt;/blockquote&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Enjoy !&lt;/b&gt; (You&apos;ll never look back :-) )
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/maven-releases-steroids-2.html</id>
    <link type="text/html" rel="alternate" href="/blog/maven-releases-steroids-2.html"/>
    <title>Maven Releases on Steroids (2): Preparing the POMs</title>
    <published>2011-01-29T00:00:00+00:00</published>
    <updated>2011-01-29T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div class=&quot;well well-small&quot;&gt;&lt;strong&gt;Update:&lt;/strong&gt; I updated this article in 2013 as &lt;a href=&quot;/blog/final-nail.html&quot;&gt;Maven Release Plugin: The Final Nail in the Coffin&lt;/a&gt;&lt;/div&gt;

In &lt;a href=&quot;/blog/maven-releases-steroids.html&quot;&gt;&lt;b&gt;Part
    1&lt;/b&gt;&lt;/a&gt;, I wrote about the problems with the Maven Release Plugin and what could be a better way to perform releases with Maven.
&lt;br/&gt;&lt;br/&gt;In this part, we will make the necessary adjustments to the POMs to make it all work.&lt;br/&gt;
&lt;br/&gt;Our goal is to have a &lt;b&gt;single command&lt;/b&gt; to:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Build and Test the SCM revision currently checked out&lt;/li&gt;
    &lt;li&gt;Deploy the binary artifacts to the Artifact Repository&lt;/li&gt;
    &lt;li&gt;Tag the SCM revision with the version number of the artifacts&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;As we only want one commit instead of 3 per release, the &lt;b&gt;version number can not be contained inside the
    POM&lt;/b&gt; anymore, as this would make it impossible to update it without updating the POM itself.
&lt;br/&gt;We have to balance this against the need for a &lt;b&gt;default version number&lt;/b&gt; when performing local, &lt;b&gt;non-release
    builds&lt;/b&gt;, as we don&apos;t want to pass in a version number for every build.&lt;br/&gt;
&lt;br/&gt;This means we have the following requirements:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Version number settable from outside for release builds&lt;/li&gt;
    &lt;li&gt;Default version number for local, non-release builds&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;This can be solved by introducing a &lt;b&gt;VERSION_NUMBER&lt;/b&gt; property:&lt;br/&gt;&lt;br/&gt;Parent POM:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;properties&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;    &amp;lt;VERSION_NUMBER&amp;gt;1.0-SNAPSHOT&amp;lt;/VERSION_NUMBER&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;  &amp;lt;/properties&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;Child POMs:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;parent&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;    &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;  &amp;lt;/parent&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;The VERSION_NUMBER property now determines the version of our project.&lt;br/&gt;
&lt;br/&gt;By default it is set to 1.0-SNAPSHOT for local, non-release builds.
&lt;br/&gt;It can also be set externally using -DVERSION_NUMBER=... for release builds.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;And normally, this should
    be it!&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Unfortunately, Maven has a &lt;a
        href=&quot;http://jira.codehaus.org/browse/MNG-2971&quot;&gt;&lt;b&gt;minefield&lt;/b&gt;&lt;/a&gt; &lt;a
        href=&quot;http://jira.codehaus.org/browse/MNG-4223&quot;&gt;&lt;b&gt;of&lt;/b&gt;&lt;/a&gt; &lt;a
        href=&quot;http://jira.codehaus.org/browse/MINSTALL-50&quot;&gt;&lt;b&gt;bugs&lt;/b&gt;&lt;/a&gt; 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 &amp;lt;version&amp;gt;${VERSION_NUMBER}&amp;lt;/version&amp;gt;, which causes problems at runtime.
&lt;br/&gt;
&lt;br/&gt;We will need to overwrite the broken POMs with a new version that has its variables replaced with their values.
&lt;br/&gt;
&lt;br/&gt;The first thing we need to add (only to our parent POM) is a way to distinguisch between snapshot and release builds:
&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;properties&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;    &amp;lt;releaseRepoUrl&amp;gt;http://my.release.repo&amp;lt;/releaseRepoUrl&amp;gt;&lt;br/&gt;    &amp;lt;snapshotRepoUrl&amp;gt;http://my.snapshot.repo&amp;lt;/snapshotRepoUrl&amp;gt;&lt;br/&gt;    &amp;lt;deployRepoUrl&amp;gt;${releaseRepoUrl}&amp;lt;/deployRepoUrl&amp;gt;&lt;br/&gt;    &amp;lt;isRelease&amp;gt;true&amp;lt;/isRelease&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;  &amp;lt;/properties&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;profiles&amp;gt;&lt;br/&gt;    &amp;lt;profile&amp;gt;&lt;br/&gt;      &amp;lt;id&amp;gt;snapshot-deploy-url-override&amp;lt;/id&amp;gt;&lt;br/&gt;      &amp;lt;activation&amp;gt;&lt;br/&gt;        &amp;lt;property&amp;gt;&lt;br/&gt;          &amp;lt;name&amp;gt;!VERSION_NUMBER&amp;lt;/name&amp;gt;&lt;br/&gt;        &amp;lt;/property&amp;gt;&lt;br/&gt;      &amp;lt;/activation&amp;gt;&lt;br/&gt;      &amp;lt;properties&amp;gt;&lt;br/&gt;        &amp;lt;deployRepoUrl&amp;gt;${snapshotRepoUrl}&amp;lt;/deployRepoUrl&amp;gt;&lt;br/&gt;        &amp;lt;isRelease&amp;gt;false&amp;lt;/isRelease&amp;gt;&lt;br/&gt;      &amp;lt;/properties&amp;gt;&lt;br/&gt;    &amp;lt;/profile&amp;gt;&lt;br/&gt;  &amp;lt;/profiles&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;distributionManagement&amp;gt;&lt;br/&gt;    &amp;lt;snapshotRepository&amp;gt;&lt;br/&gt;      &amp;lt;id&amp;gt;snapshots-repo&amp;lt;/id&amp;gt;&lt;br/&gt;      &amp;lt;name&amp;gt;Snapshots Repo&amp;lt;/name&amp;gt;&lt;br/&gt;      &amp;lt;url&amp;gt;${snapshotRepoUrl}&amp;lt;/url&amp;gt;&lt;br/&gt;    &amp;lt;/snapshotRepository&amp;gt;&lt;br/&gt;    &amp;lt;repository&amp;gt;&lt;br/&gt;      &amp;lt;id&amp;gt;releases-repo&amp;lt;/id&amp;gt;&lt;br/&gt;      &amp;lt;name&amp;gt;Releases Repo&amp;lt;/name&amp;gt;&lt;br/&gt;      &amp;lt;url&amp;gt;${releaseRepoUrl}&amp;lt;/url&amp;gt;&lt;br/&gt;    &amp;lt;/repository&amp;gt;&lt;br/&gt;  &amp;lt;/distributionManagement&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;And now comes the real juicy part (only necessary in the parent POM):&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Fixing the POM by substituting the variables&lt;/li&gt;
    &lt;li&gt;Overwriting the existing POM in the local repo&lt;/li&gt;
    &lt;li&gt;Overwriting the existing POM in the remote repo&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;build&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;    &amp;lt;plugins&amp;gt;&lt;br/&gt;      &amp;lt;plugin&amp;gt;&lt;br/&gt;        &amp;lt;artifactId&amp;gt;maven-resources-plugin&amp;lt;/artifactId&amp;gt;&lt;br/&gt;        &amp;lt;version&amp;gt;2.4.3&amp;lt;/version&amp;gt;&lt;br/&gt;        &amp;lt;executions&amp;gt;&lt;br/&gt;          &amp;lt;execution&amp;gt;&lt;br/&gt;            &amp;lt;id&amp;gt;replace-pom-placeholder&amp;lt;/id&amp;gt;&lt;br/&gt;            &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;&lt;br/&gt;            &amp;lt;goals&amp;gt;&lt;br/&gt;              &amp;lt;goal&amp;gt;copy-resources&amp;lt;/goal&amp;gt;&lt;br/&gt;            &amp;lt;/goals&amp;gt;&lt;br/&gt;            &amp;lt;configuration&amp;gt;&lt;br/&gt;              &amp;lt;resources&amp;gt;&lt;br/&gt;                &amp;lt;resource&amp;gt;&lt;br/&gt;                  &amp;lt;directory&amp;gt;${basedir}&amp;lt;/directory&amp;gt;&lt;br/&gt;                  &amp;lt;includes&amp;gt;&lt;br/&gt;                    &amp;lt;include&amp;gt;pom.xml&amp;lt;/include&amp;gt;&lt;br/&gt;                  &amp;lt;/includes&amp;gt;&lt;br/&gt;                  &amp;lt;filtering&amp;gt;true&amp;lt;/filtering&amp;gt;&lt;br/&gt;                &amp;lt;/resource&amp;gt;&lt;br/&gt;              &amp;lt;/resources&amp;gt;&lt;br/&gt;              &amp;lt;outputDirectory&amp;gt;${project.build.directory}/pom-install-deploy-fix&amp;lt;/outputDirectory&amp;gt;&lt;br/&gt;            &amp;lt;/configuration&amp;gt;&lt;br/&gt;          &amp;lt;/execution&amp;gt;&lt;br/&gt;        &amp;lt;/executions&amp;gt;&lt;br/&gt;      &amp;lt;/plugin&amp;gt;&lt;br/&gt;&lt;br/&gt;      &amp;lt;plugin&amp;gt;&lt;br/&gt;        &amp;lt;artifactId&amp;gt;maven-install-plugin&amp;lt;/artifactId&amp;gt;&lt;br/&gt;        &amp;lt;version&amp;gt;2.3.1&amp;lt;/version&amp;gt;&lt;br/&gt;        &amp;lt;executions&amp;gt;&lt;br/&gt;          &amp;lt;execution&amp;gt;&lt;br/&gt;            &amp;lt;id&amp;gt;overwrite-pom&amp;lt;/id&amp;gt;&lt;br/&gt;            &amp;lt;phase&amp;gt;install&amp;lt;/phase&amp;gt;&lt;br/&gt;            &amp;lt;goals&amp;gt;&lt;br/&gt;              &amp;lt;goal&amp;gt;install-file&amp;lt;/goal&amp;gt;&lt;br/&gt;            &amp;lt;/goals&amp;gt;&lt;br/&gt;            &amp;lt;configuration&amp;gt;&lt;br/&gt;              &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;&lt;br/&gt;              &amp;lt;file&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/file&amp;gt;&lt;br/&gt;              &amp;lt;pomFile&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/pomFile&amp;gt;&lt;br/&gt;              &amp;lt;version&amp;gt;${project.version}&amp;lt;/version&amp;gt;&lt;br/&gt;            &amp;lt;/configuration&amp;gt;&lt;br/&gt;          &amp;lt;/execution&amp;gt;&lt;br/&gt;        &amp;lt;/executions&amp;gt;&lt;br/&gt;      &amp;lt;/plugin&amp;gt;&lt;br/&gt;&lt;br/&gt;      &amp;lt;plugin&amp;gt;&lt;br/&gt;        &amp;lt;artifactId&amp;gt;maven-deploy-plugin&amp;lt;/artifactId&amp;gt;&lt;br/&gt;        &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt;&lt;br/&gt;        &amp;lt;executions&amp;gt;&lt;br/&gt;          &amp;lt;execution&amp;gt;&lt;br/&gt;            &amp;lt;id&amp;gt;overwrite-pom&amp;lt;/id&amp;gt;&lt;br/&gt;            &amp;lt;phase&amp;gt;deploy&amp;lt;/phase&amp;gt;&lt;br/&gt;            &amp;lt;goals&amp;gt;&lt;br/&gt;              &amp;lt;goal&amp;gt;deploy-file&amp;lt;/goal&amp;gt;&lt;br/&gt;            &amp;lt;/goals&amp;gt;&lt;br/&gt;            &amp;lt;configuration&amp;gt;&lt;br/&gt;              &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;&lt;br/&gt;              &amp;lt;file&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/file&amp;gt;&lt;br/&gt;              &amp;lt;pomFile&amp;gt;target/pom-install-deploy-fix/pom.xml&amp;lt;/pomFile&amp;gt;&lt;br/&gt;              &amp;lt;url&amp;gt;${deployRepoUrl}&amp;lt;/url&amp;gt;&lt;br/&gt;              &amp;lt;version&amp;gt;${project.version}&amp;lt;/version&amp;gt;&lt;br/&gt;              &amp;lt;updateReleaseInfo&amp;gt;${isRelease}&amp;lt;/updateReleaseInfo&amp;gt;&lt;br/&gt;              &amp;lt;uniqueVersion&amp;gt;false&amp;lt;/uniqueVersion&amp;gt;&lt;br/&gt;            &amp;lt;/configuration&amp;gt;&lt;br/&gt;          &amp;lt;/execution&amp;gt;&lt;br/&gt;        &amp;lt;/executions&amp;gt;&lt;br/&gt;      &amp;lt;/plugin&amp;gt;&lt;br/&gt;      ...&lt;br/&gt;    &amp;lt;/plugins&amp;gt;&lt;br/&gt;    ...&lt;br/&gt;  &amp;lt;/build&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;If you also want to deploy &lt;b&gt;source artifacts&lt;/b&gt;, check out the &lt;a
        href=&quot;http://maven.apache.org/plugins/maven-source-plugin/usage.html&quot;&gt;Maven Source Plugin&lt;/a&gt;.&lt;br/&gt;
&lt;br/&gt;So far, so good: we now have taken care of the &lt;b&gt;deployment in the Artifact Repository&lt;/b&gt;!&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;
&lt;br/&gt;Let&apos;s add the final bit to enable &lt;b&gt;SCM tagging&lt;/b&gt;...&lt;br/&gt;&lt;br/&gt;First add the scm section to your parent POM:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;project ...&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;  &amp;lt;scm&amp;gt;&lt;br/&gt;    &amp;lt;connection&amp;gt;scm:my-provider:my-read-url&amp;lt;/connection&amp;gt;&lt;br/&gt;    &amp;lt;developerConnection&amp;gt;scm:my-provider:my-read-write-url&amp;lt;/developerConnection&amp;gt;&lt;br/&gt;  &amp;lt;/scm&amp;gt;&lt;br/&gt;  ...&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;And now add the scm plugin to the plugins section of the parent POM:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;plugin&amp;gt;&lt;br/&gt;    &amp;lt;artifactId&amp;gt;maven-scm-plugin&amp;lt;/artifactId&amp;gt;&lt;br/&gt;    &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;&lt;br/&gt;    &amp;lt;configuration&amp;gt;&lt;br/&gt;      &amp;lt;tag&amp;gt;${project.artifactId}-${VERSION_NUMBER}&amp;lt;/tag&amp;gt;&lt;br/&gt;    &amp;lt;/configuration&amp;gt;&lt;br/&gt;  &amp;lt;/plugin&amp;gt;&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;Done!&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;We can now&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;b&gt;publish new snapshots&lt;/b&gt; using&lt;br/&gt;mvn clean deploy&lt;br/&gt;&lt;/li&gt;
    &lt;li&gt;&lt;b&gt;release and tag new versions&lt;/b&gt; using&lt;br/&gt;mvn clean deploy scm:tag -DVERSION_NUMBER=1.2.3&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;In &lt;a href=&quot;/blog/maven-releases-steroids-3.html&quot;&gt;&lt;b&gt;Part
    3&lt;/b&gt;&lt;/a&gt;, we conclude our adventure by choosing a version number strategy and looking at Jenkins integration.
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/maven-releases-steroids.html</id>
    <link type="text/html" rel="alternate" href="/blog/maven-releases-steroids.html"/>
    <title>Maven Releases on Steroids: Adios Release Plugin!</title>
    <published>2011-01-23T00:00:00+00:00</published>
    <updated>2011-01-23T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">&lt;div class=&quot;well well-small&quot;&gt;&lt;strong&gt;Update:&lt;/strong&gt; I updated this article in 2013 as &lt;a href=&quot;/blog/final-nail.html&quot;&gt;Maven Release Plugin: The Final Nail in the Coffin&lt;/a&gt;&lt;/div&gt;

One of the central themes of my current series of talks about Continuous Delivery is &lt;b&gt;releasing software&lt;/b&gt;.&lt;br/&gt;
&lt;br/&gt;Releasing software encompasses a number of activities such as&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Picking a version number&lt;/li&gt;
    &lt;li&gt;Checking out the latest revision from SCM&lt;/li&gt;
    &lt;li&gt;Building and Testing binaries&lt;/li&gt;
    &lt;li&gt;Tagging the SCM revison with the version number&lt;/li&gt;
    &lt;li&gt;Publishing the binary artifacts in an Artifact Repository&lt;/li&gt;
    &lt;li&gt;Writing release notes, announcement e-mails, etc...&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;In order to avoid the &lt;a
        href=&quot;http://www.codinghorror.com/blog/2007/03/the-works-on-my-machine-certification-program.html&quot;&gt;&lt;b&gt;Works On
    My Machine&lt;/b&gt;&lt;/a&gt; syndrome, releases are typically built centrally on a &lt;b&gt;continuous integration
    server&lt;/b&gt; such as &lt;strike&gt;Hudson&lt;/strike&gt; &lt;a href=&quot;http://jenkins-ci.org/&quot;&gt;Jenkins&lt;/a&gt;.&lt;br/&gt;
&lt;br/&gt;The Continuous Integration server serves as a choreographer between the following components:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;SCM (&lt;a href=&quot;http://subversion.apache.org/&quot;&gt;Subversion&lt;/a&gt;, &lt;a
            href=&quot;http://mercurial.selenic.com/&quot;&gt;Mercurial&lt;/a&gt;, &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt;, ...)
    &lt;/li&gt;
    &lt;li&gt;Build Tool (&lt;a href=&quot;http://maven.apache.org/&quot;&gt;Maven&lt;/a&gt;, &lt;a href=&quot;http://ant.apache.org/&quot;&gt;Ant&lt;/a&gt;, &lt;a
            href=&quot;http://www.gradle.org/&quot;&gt;Gradle&lt;/a&gt;, ...)
    &lt;/li&gt;
    &lt;li&gt;Artifact Repository (&lt;a href=&quot;http://nexus.sonatype.org/&quot;&gt;Nexus&lt;/a&gt;, &lt;a
            href=&quot;http://www.jfrog.org/products.php&quot;&gt;Artifactory&lt;/a&gt;, ...)
    &lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;On &lt;b&gt;Maven
    projects&lt;/b&gt;, the Building, Testing, Tagging and Publishing steps have traditionally been handled by the &lt;a
        href=&quot;http://maven.apache.org/plugins/maven-release-plugin/&quot;&gt;&lt;b&gt;Maven Release
    Plugin&lt;/b&gt;&lt;/a&gt;. It works, to a reasonable degree, and it has a decent &lt;a
        href=&quot;http://wiki.jenkins-ci.org/display/HUDSON/M2+Release+Plugin&quot;&gt;Jenkins plugin&lt;/a&gt;.&lt;br/&gt;
&lt;br/&gt;Using Jenkins and the Release Plugin, here are the typical steps performed by the various components:&lt;br/&gt;
&lt;p style=&quot;font-size: x-small;&quot;&gt;(&lt;strong style=&quot;color: red;&quot;&gt;Safety Notice:&lt;/strong&gt; buckle up, it&apos;s going to be a wild ride!)&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Jenkins &lt;b&gt;checks out&lt;/b&gt; the latest revision from SCM&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
    &lt;li&gt;Release Plugin &lt;b&gt;transforms the POMs&lt;/b&gt; with the new version number&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
    &lt;li&gt;Release Plugin &lt;b&gt;commits&lt;/b&gt; the new POMs into SCM&lt;/li&gt;
    &lt;li&gt;Release Plugin &lt;b&gt;tags&lt;/b&gt; the new SCM revision with the version number&lt;/li&gt;
    &lt;li&gt;Release Plugin &lt;b&gt;transforms the POMs&lt;/b&gt; to version n+1 -SNAPSHOT&lt;/li&gt;
    &lt;li&gt;Release Plugin &lt;b&gt;commits&lt;/b&gt; the new new POMs into SCM&lt;/li&gt;
    &lt;li&gt;Release Plugin &lt;b&gt;checks out&lt;/b&gt; the new tag from SCM&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;publishes&lt;/b&gt; the binaries into the Artifact Repository&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;Phew! Did you count it?&lt;br/&gt;&lt;br/&gt;That&apos;s &lt;b&gt;3 full clean/compile/test cycles&lt;/b&gt;, &lt;b&gt;2 POM transformation
    rounds&lt;/b&gt; and &lt;b&gt;3 different SCM revisions&lt;/b&gt;!&lt;br/&gt;
&lt;br/&gt;No wonder this thing has proved to be error prone and frustrating to many developers for years now. And let&apos;s not even get me started on how well this thing blows up when another team member unsuspectingly checks in a change to the POM in the middle of this multiple transform and commit carousel...
&lt;br/&gt;&lt;br/&gt;&lt;b style=&quot;font-size: large;&quot;&gt;So is there another way?&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;What if we could deal with only a &lt;b&gt;single SCM revision&lt;/b&gt; (the one we want to release) going through a &lt;b&gt;single
    clean/compile/test run&lt;/b&gt; before &lt;b&gt;tagging&lt;/b&gt; the source and &lt;b&gt;publishing&lt;/b&gt; the binaries?&lt;br/&gt;
&lt;br/&gt;Let me say this loud and clear: yes, we can!&lt;br/&gt;&lt;br/&gt;The
&lt;b&gt;solution&lt;/b&gt; I present in part 2 does just that. This is what it looks like:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Jenkins &lt;b&gt;checks out&lt;/b&gt; the latest revision from SCM&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;compiles&lt;/b&gt; the sources and runs the &lt;b&gt;tests&lt;/b&gt;&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;tags&lt;/b&gt; the SCM revision with the version number&lt;/li&gt;
    &lt;li&gt;Maven &lt;b&gt;publishes&lt;/b&gt; the binaries into the Artifact Repository&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;&lt;b&gt;Simple and to the point.&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Continue to &lt;a
        href=&quot;/blog/maven-releases-steroids-2.html&quot;&gt;&lt;b&gt;Part
    2&lt;/b&gt;&lt;/a&gt; where we go into the adjustments to make to the POMs.
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/ubuntu-server-10-virtualpc.html</id>
    <link type="text/html" rel="alternate" href="/blog/ubuntu-server-10-virtualpc.html"/>
    <title>Ubuntu Server 10.10 on Virtual PC under Win7</title>
    <published>2011-01-16T00:00:00+00:00</published>
    <updated>2011-01-16T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">A while ago, I described how to &lt;a
        href=&quot;/blog/ubuntu-server-virtualpc.html&quot;&gt;get Ubuntu Server 9.10
    to run Windows Virtual PC&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;As it turned out though, the beasts were only tamed for a release or two. For Ubuntu Server 10.10 this guide needed an update, so here it is!&lt;br/&gt;
&lt;br/&gt;These are the steps required to get &lt;b&gt;Ubuntu Server
    10.10&lt;/b&gt; to run on &lt;b&gt;Windows Virtual PC&lt;/b&gt; under &lt;b&gt;Windows 7&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;For this to work you will need:
&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Windows 7 with Virtual PC installed&lt;/li&gt;
    &lt;li&gt;The &lt;a
            href=&quot;http://www.ubuntu.com/server/get-ubuntu/download&quot;&gt;Ubuntu Server 10.10 32-bit ISO&lt;/a&gt;&amp;nbsp;&lt;i&gt;(Virtual PC still does not support 64-bit guests)&lt;/i&gt;
    &lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;Ready? Let&apos;s go !&lt;br/&gt;&lt;br/&gt;1.&amp;nbsp;In the&amp;nbsp;&lt;b&gt;Virtual
    Machines&lt;/b&gt;&amp;nbsp;folder, create a new VM. Before launching it, edit the settings to&lt;b&gt;&amp;nbsp;mount the Ubuntu
    ISO&lt;br/&gt;&lt;/b&gt;&lt;br/&gt;2. Launch the VM and select your language.&lt;br/&gt;
&lt;br/&gt;3. Press &lt;b&gt;F4&lt;/b&gt; and select &lt;b&gt;Install
    a minimum virtual machine&lt;br/&gt;&lt;/b&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ubuntu-server-10-virtualpc/mode-select.png&quot;
                                                                          alt=&quot;Mode select&quot;/&gt;&lt;/div&gt;&lt;br/&gt;
&lt;br/&gt;4. Perform the installation all the way through.&lt;br/&gt;
&lt;br/&gt;5. After the reboot, in Grub, select the &lt;b&gt;first
    entry&lt;/b&gt; and press &quot;&lt;b&gt;e&lt;/b&gt;&quot; to edit it.&lt;br/&gt;&lt;br/&gt;6.&amp;nbsp;Add &quot;&lt;b&gt;noreplace-paravirt
    vga=771&lt;/b&gt;&quot; (no quotes) before &quot;&lt;b&gt;quiet&lt;/b&gt;&quot; on the second last line and press&amp;nbsp;&lt;b&gt;Ctrl+x&lt;/b&gt;
&amp;nbsp;to boot&lt;br/&gt;
&lt;br/&gt;7.&amp;nbsp;Log in and edit the file called &quot;&lt;b&gt;/etc/default/grub&lt;/b&gt;&quot; as root. Change the line with &lt;b&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/b&gt; in:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;GRUB_CMDLINE_LINUX_DEFAULT=&quot;noreplace-paravirt vga=771 quiet&quot;&lt;br/&gt;&lt;/pre&gt;8. Execute this command:
&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;sudo update-grub&lt;/pre&gt;9. Reboot&lt;br/&gt;&lt;br/&gt;10. &lt;b&gt;Welcome to Ubuntu Server 10.10 under Virtual
    PC on Windows 7!&lt;br/&gt;&lt;/b&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/posts/ubuntu-server-10-virtualpc/login-prompt.png&quot; alt=&quot;Login prompt&quot;/&gt;&lt;/div&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/600-euro-upgrade.html</id>
    <link type="text/html" rel="alternate" href="/blog/600-euro-upgrade.html"/>
    <title>The 600 Euro upgrade that cut build times in half</title>
    <published>2009-11-24T00:00:00+00:00</published>
    <updated>2009-11-24T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">In the past, I have talked &lt;a href=&quot;/blog/ubuntu-server-virtualpc.html&quot;&gt;here&lt;/a&gt; and
&lt;a href=&quot;/blog/ie-6-7-8.html&quot;&gt;here&lt;/a&gt; about my test environment for
&lt;a href=&quot;http://www.veturanto.com/&quot;&gt;Veturanto&lt;/a&gt;. Today I&apos;ll talk about my development environment instead.&lt;br/&gt;
&lt;br/&gt;My main workstation used to have the following hardware configuration:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Intel Core 2 Duo (dual core) @ 1.86 Ghz&lt;/li&gt;
    &lt;li&gt;4 GB DDR2 RAM &lt;br/&gt;&lt;/li&gt;
    &lt;li&gt;Western Digital VelociRaptor 300 GB @ 10000 RPM&lt;/li&gt;
&lt;/ul&gt;Decent, but not the absolute latest.&lt;br/&gt;&lt;br/&gt;About two and a half months ago, a worthy successor of the &lt;i&gt;Core 2
    Duo&lt;/i&gt; arrived on the market: the &lt;b&gt;&lt;i&gt;Intel Core i5&lt;/i&gt;&lt;/b&gt;. By that time, Intel had also released the &lt;b&gt;second
    generation of its high-performance SSDs&lt;/b&gt;. It was time for an upgrade.&lt;br/&gt;
&lt;br/&gt;I decided to take the plunge and invested about 600 Euro in the following hardware:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Intel Core i5 750 (quad core) @ 3.01 Ghz (overclocked from 2.67 Ghz)&lt;/li&gt;
    &lt;li&gt;Scythe Ninja 2 Cooler (yes, I do share &lt;a href=&quot;http://www.codinghorror.com/blog/archives/000707.html&quot;&gt;Jeff
        Atwood&apos;s giant heatsink fettish&lt;/a&gt;)
    &lt;/li&gt;
    &lt;li&gt;Asus P7P55D Pro motherboard &lt;br/&gt;&lt;/li&gt;
    &lt;li&gt;8 GB DDR3 RAM&lt;/li&gt;
    &lt;li&gt;Intel Postville 34nm SSD 80 GB&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/600-euro-upgrade/WindowsExperienceIndex.png&quot; alt=&quot;Windows Performance Index&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;i&gt;But what kind of performance do you get out of this?&lt;/i&gt;&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;Let&apos;s compare two day to day activities: the&lt;b&gt; full build&lt;/b&gt; and the&lt;b&gt; application startup&lt;/b&gt; times.&lt;br/&gt;
&lt;br/&gt;Here is how they fared:&lt;br/&gt;
&lt;table height=&quot;105&quot; style=&quot;border: 1px solid; padding: 5px; width: 453px;&quot;&gt;
    &lt;tbody&gt;
    &lt;tr align=&quot;left&quot;&gt;
        &lt;td&gt;&lt;/td&gt;
        &lt;td style=&quot;text-align: center;&quot;&gt;&lt;i&gt;&lt;b&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Core 2 Duo + Raptor&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;br/&gt;
        &lt;/td&gt;
        &lt;td style=&quot;text-align: center;&quot;&gt;&lt;i&gt;&lt;b&gt;Core i5 + SSD&lt;/b&gt;&lt;/i&gt;&lt;br/&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr align=&quot;left&quot;&gt;
        &lt;td&gt;Full build&lt;br/&gt;&lt;/td&gt;
        &lt;td style=&quot;color: red; text-align: center;&quot;&gt;1 minute 50 seconds&lt;br/&gt;&lt;/td&gt;
        &lt;td style=&quot;color: #38761d; text-align: center;&quot;&gt;&lt;b&gt;45 seconds &lt;/b&gt;&lt;br/&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td style=&quot;text-align: left;&quot;&gt;Application startup&lt;br/&gt;&lt;/td&gt;
        &lt;td style=&quot;color: red; text-align: center;&quot;&gt;17 seconds&lt;br/&gt;&lt;/td&gt;
        &lt;td style=&quot;color: #38761d; text-align: center;&quot;&gt;&lt;b&gt;5 seconds &lt;/b&gt;&lt;br/&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;&lt;br/&gt;&lt;b&gt;The difference is nothing short of phenomenal !&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;Go out, get a modern processor and a high-performance SSD and you&apos;ll never look back !
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/crossing-the-chasm.html</id>
    <link type="text/html" rel="alternate" href="/blog/crossing-the-chasm.html"/>
    <title>One Minute Book Review: Crossing the Chasm</title>
    <published>2009-11-18T00:00:00+00:00</published>
    <updated>2009-11-18T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">Last week, I finished reading Geoffrey Moore&apos;s excellent&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;br/&gt;&lt;b&gt; &lt;a
        href=&quot;http://www.amazon.com/Crossing-Chasm-Marketing-High-Tech-Mainstream/dp/0066620023&quot;&gt;Crossing the Chasm&lt;/a&gt;:
    Marketing and Selling high-tech products to mainstream customers.&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/posts/crossing-the-chasm/crossing-the-chasm.jpg&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;(image courtesy of &lt;a
        href=&quot;http://en.wikipedia.org/wiki/Crossing_the_Chasm&quot;&gt;wikipedia&lt;/a&gt;) &lt;/span&gt;&lt;br/&gt;&lt;/div&gt;
&lt;br/&gt;Moore sets out by describing the&lt;i&gt; &lt;/i&gt;&lt;b&gt;technology adoption
    lifecycle&lt;/b&gt;, and the different demographics that compose it:&lt;br/&gt;&lt;br/&gt;
&lt;div style=&quot;color: #0b5394;&quot;&gt;&lt;b&gt;&lt;i&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Innovators&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;br/&gt;&lt;/div&gt;The &lt;b&gt;Technology
    Enthusiasts&lt;/b&gt; live on the bleeding edge and take pride to being the first try out new things. They generate the first buzz, but lack loyalty.
&lt;br/&gt;&lt;br/&gt;
&lt;div style=&quot;color: #0b5394;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;i&gt;&lt;b&gt;Early Adopters&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;The &lt;b&gt;Visionaries&lt;/b&gt; see great new strategic opportunities in new products, and are willing the invest and participate heavily in the product development to get a game changing advantage over the competition.
&lt;br/&gt;&lt;br/&gt;
&lt;div style=&quot;color: #0b5394;&quot;&gt;&lt;i&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Early Majority&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;br/&gt;&lt;/div&gt;The &lt;b&gt;Pragmatists &lt;/b&gt;stand for continuity. They want a proven solution helping them make an incremental, predictable improvement to their business.
&lt;br/&gt;&lt;br/&gt;
&lt;div style=&quot;color: #0b5394;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;&lt;i&gt;Late Majority&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;br/&gt;
&lt;/div&gt;The
&lt;b&gt;Conservatives &lt;/b&gt;believe more in tradition than progress. They will finally adopt new technologies when I becomes inconvenient not do so. By that time, the products have become a commodity, that is well tested and sells with low margins.
&lt;br/&gt;&lt;br/&gt;
&lt;div style=&quot;color: #0b5394;&quot;&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;i&gt;&lt;b&gt;Laggards&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;The
&lt;b&gt;Skeptics &lt;/b&gt;pride themselves in intentionally being behind the mainstream. They do not participate in the high-tech marketplace, except to block purchases. Their contribution is feedback about the discrepancies between sales claims and delivered products.
&lt;br/&gt;&lt;br/&gt;
&lt;br/&gt;But then comes the key observation: the technology adaption lifecycle does not look like a nicely shaped bell-curve, but more like this:
&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
    &lt;img src=&quot;/assets/posts/crossing-the-chasm/Technology-Adoption-Lifecycle.png&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;(image courtesy of &lt;a
        href=&quot;http://en.wikipedia.org/wiki/Crossing_the_Chasm&quot;&gt;wikipedia&lt;/a&gt;)&lt;/span&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;
&lt;/div&gt;Ans this will be the central theme of the rest of the book: what separates &lt;i&gt;early&lt;/i&gt; and &lt;i&gt;mainstream
    markets&lt;/i&gt;, the gap between &lt;i&gt;early adopters&lt;/i&gt; and &lt;i&gt;early majority&lt;/i&gt;, the &lt;b&gt;Chasm&lt;/b&gt;, and &lt;b&gt;how to cross
    it&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;Moore makes a compelling argument around what he calls &lt;b&gt;Beachhead Strategy&lt;/b&gt; and the &lt;b&gt;Whole
    Product
    Model&lt;/b&gt;. He describes what it takes for a company to get a foothold in the mainstream market and expand from there.
&lt;br/&gt;&lt;br/&gt;A great read. &lt;b&gt;Highly recommended.&lt;/b&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/javascript-block-scope.html</id>
    <link type="text/html" rel="alternate" href="/blog/javascript-block-scope.html"/>
    <title>The perils of the missing javascript block scope</title>
    <published>2009-11-12T00:00:00+00:00</published>
    <updated>2009-11-12T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">Javascript variable scope is something of a strange thing. You have a &lt;i&gt;global&lt;/i&gt; and a &lt;i&gt;function&lt;/i&gt; scope. &lt;b&gt;But
    unlike most other languages, there is no &lt;i&gt;block&lt;/i&gt; scope!&lt;/b&gt; This is often a cause for hard to find bugs.&lt;br/&gt;
&lt;br/&gt;Let me show you the consequences of this with a small puzzler:&lt;br/&gt;&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;html&amp;gt;&lt;br/&gt;&amp;lt;body&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link1&quot; href=&quot;&quot;&amp;gt;Link 1&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part1&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link2&quot; href=&quot;&quot;&amp;gt;Link 2&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part2&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link3&quot; href=&quot;&quot;&amp;gt;Link 3&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part3&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link4&quot; href=&quot;&quot;&amp;gt;Link 4&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part4&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link5&quot; href=&quot;&quot;&amp;gt;Link 5&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part5&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;No Link 6 &amp;lt;span id=&quot;part6&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br/&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;&lt;br/&gt;  $(document).ready(function() {&lt;br/&gt;    for (i = 1; i &amp;lt;= 5; i++) {&lt;br/&gt;      $(&quot;#link&quot;+i).click(function() {&lt;br/&gt;        $(&quot;#part&quot;+i).html(&quot;Clicked !&quot;);&lt;br/&gt;        return false;&lt;br/&gt;      });&lt;br/&gt;    }&lt;br/&gt;  });&lt;br/&gt;&amp;lt;/script&amp;gt;&lt;br/&gt;&amp;lt;/body&amp;gt;&lt;br/&gt;&amp;lt;/html&amp;gt;&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Now what does this do?&lt;/b&gt; (you need a bit of &lt;a
        href=&quot;http://www.jquery.com/&quot;&gt;jquery&lt;/a&gt; knowledge to guess it)&lt;br/&gt;
&lt;br/&gt;At first glance, it walks over the 5 links present on this page, and registers a handler for mouse clicks that adds the text &quot;Clicked !&quot; to the span element with the same number as the link.
&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Or does it?&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Well, this is what the output looks like when you click on &quot;Link 3&quot;:&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;&lt;img src=&quot;/assets/posts/javascript-block-scope/test.png&quot; alt=&quot;Test&quot;/&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;&lt;b style=&quot;color: red;&quot;&gt;It is totally wrong
    !&lt;/b&gt; Now why is that? Well, as we have no block scope, by the time we are done with the for loop, the variable&lt;b&gt; i
    has been incremented up to 6&lt;/b&gt;. It is however &lt;b&gt;still in scope&lt;/b&gt;, and therefore this last value gets used &lt;b&gt;when
    the closure for the click event gets called&lt;/b&gt;. And so it is part 6 that receives the new text !&lt;br/&gt;&lt;br/&gt;&lt;b&gt;So how
    can we fix this?&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;We have to &lt;b&gt;separate the scopes&lt;/b&gt;, and to do that we need a &lt;b&gt;new
    function&lt;/b&gt;. This is what the correct code looks like:&lt;br/&gt;&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;&amp;lt;html&amp;gt;&lt;br/&gt;&amp;lt;body&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link1&quot; href=&quot;&quot;&amp;gt;Link 1&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part1&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link2&quot; href=&quot;&quot;&amp;gt;Link 2&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part2&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link3&quot; href=&quot;&quot;&amp;gt;Link 3&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part3&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link4&quot; href=&quot;&quot;&amp;gt;Link 4&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part4&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&amp;lt;a id=&quot;link5&quot; href=&quot;&quot;&amp;gt;Link 5&amp;lt;/a&amp;gt; &amp;lt;span id=&quot;part5&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;No Link 6 &amp;lt;span id=&quot;part6&quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br/&amp;gt;&lt;br/&gt;&lt;br/&gt;&amp;lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br/&gt;&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;&lt;br/&gt;  $(document).ready(function() {&lt;br/&gt;    for (i = 1; i &amp;lt;= 5; i++) {&lt;br/&gt;      addClickEvent(i);&lt;br/&gt;    }&lt;br/&gt;  });&lt;br/&gt;  &lt;br/&gt;  function addClickEvent(i) {&lt;br/&gt;    $(&quot;#link&quot;+i).click(function() {&lt;br/&gt;      $(&quot;#part&quot;+i).html(&quot;Clicked !&quot;);&lt;br/&gt;      return false;&lt;br/&gt;    });&lt;br/&gt;  }&lt;br/&gt;&amp;lt;/script&amp;gt;&lt;br/&gt;&amp;lt;/body&amp;gt;&lt;br/&gt;&amp;lt;/html&amp;gt;&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;
&lt;br/&gt;With the registration of the click event taking place in a separate function (and therefore a separate scope for the variable i), this is what the output looks like:
&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;&lt;img src=&quot;/assets/posts/javascript-block-scope/testOk.png&quot; alt=&quot;Test OK&quot;/&gt;
&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;
&lt;/div&gt;Which is much more like what we were expecting !&lt;br/&gt;&lt;br/&gt;&lt;b&gt;So beware of the lack of &lt;i&gt;block&lt;/i&gt; scope in
    Javascript! It can come and bite more easily than you think if you&apos;re not extra careful about it!&lt;/b&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/ubuntu-server-virtualpc.html</id>
    <link type="text/html" rel="alternate" href="/blog/ubuntu-server-virtualpc.html"/>
    <title>Taming the beasts: Getting Ubuntu Server 9.10 to run in Virtual PC on Windows 7</title>
    <published>2009-11-04T00:00:00+00:00</published>
    <updated>2009-11-04T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">As I
&lt;a href=&quot;/blog/ie-6-7-8.html&quot;&gt;wrote&lt;/a&gt;, I am a big fan of Windows 7 and virtualization. While my development environment for
&lt;a href=&quot;http://www.veturanto.com/&quot;&gt;Veturanto&lt;/a&gt; runs on Windows, the production server runs on &lt;a
        href=&quot;http://www.ubuntu.com/products/whatIsubuntu/serveredition&quot;&gt;Ubuntu
    Server&lt;/a&gt;. Ubuntu Server is great and by far the best Linux distribution available at the moment. One piece of the Veturanto infrastructure puzzle I haven&apos;t talked about yet is the test server. As I want it to be as close as possible to the production environment, it also naturally runs the same OS. And being a virtualization fan, I want it to run in a window to boot.
&lt;br/&gt;&lt;br/&gt;However &lt;b&gt;Virtual PC and Ubuntu Server&lt;/b&gt; have a history of making life difficult for each other and &lt;b&gt;not
    playing together nicely&lt;/b&gt;. There is however a way to get them to cooperate.&lt;br/&gt;&lt;br/&gt;&lt;span
        style=&quot;font-size: large;&quot;&gt;So let&apos;s go and tame these beasts!&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;For this to work you will
    need:&lt;/b&gt;&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Windows 7 with Virtual PC installed (see my &lt;a
            href=&quot;/blog/ie-6-7-8.html&quot;&gt;previous blog
        post&lt;/a&gt;)
    &lt;/li&gt;
    &lt;li&gt;The &lt;a href=&quot;http://www.ubuntu.com/getubuntu/download-server&quot;&gt;Ubuntu Server 9.10 32-bit ISO&lt;/a&gt; (Virtual PC does
        not yet support 64-bit guests)
    &lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Ok, let&apos;s get started!&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;1. In the &lt;b&gt;Virtual
    Machines&lt;/b&gt; folder, create a new VM. Before launching it, edit the settings to&lt;b&gt; mount the Ubuntu ISO&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;2. Launch the VM and run the installation normally.&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ubuntu-server-virtualpc/install.png&quot; alt=&quot;Install&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;3. In Grub, select the &lt;b&gt;Linux 2.6.31-14-generic-pae&lt;/b&gt; entry and press &quot;&lt;b&gt;e&lt;/b&gt;&quot; to edit it.&lt;br/&gt;
&lt;br/&gt;4. Add &quot;&lt;b&gt;noreplace-paravirt vga=771&lt;/b&gt;&quot; (no quotes) before &quot;&lt;b&gt;quiet
    splash&lt;/b&gt;&quot; on the second last line and press &lt;b&gt;Ctrl+x&lt;/b&gt; to boot&lt;br/&gt;&lt;br/&gt;5. Log in and create a file called &quot;&lt;b&gt;/etc/default/grub&lt;/b&gt;&quot; as root with this content:
&lt;br/&gt;
&lt;pre class=&quot;brush: text&quot;&gt;GRUB_DEFAULT=0&lt;br/&gt;GRUB_CMDLINE_LINUX_DEFAULT=&quot;noreplace-paravirt vga=771 quiet splash&quot;&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;6. Execute this command:&lt;br/&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;sudo update-grub&lt;br/&gt;&lt;/pre&gt;&lt;br/&gt;7. Reboot&lt;br/&gt;&lt;br/&gt;8. &lt;b&gt;Welcome to Ubuntu Server 9.10 under
    Virtual PC on Windows 7 !&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ubuntu-server-virtualpc/welcome.png&quot; alt=&quot;Welcome&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Note:&lt;/b&gt; Credits go to &lt;a
        href=&quot;http://www.myoddweb.com/2009/07/04/install-ubuntu-9-on-virtual-pc-2007-part-deux/&quot;&gt;this post&lt;/a&gt; and &lt;a
        href=&quot;http://tombuntu.com/index.php/2007/09/05/making-ubuntu-server-work-in-virtualbox/&quot;&gt;this
    post&lt;/a&gt; as they were essential inspiration to arrive at this solution!&lt;br/&gt;&lt;br/&gt;&lt;span style=&quot;color: red;&quot;&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;span
        style=&quot;color: black;&quot;&gt; Removed the bit about changing the kernel. It wasn&apos;t necessary.&lt;/span&gt;&lt;/span&gt;
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/ie-6-7-8.html</id>
    <link type="text/html" rel="alternate" href="/blog/ie-6-7-8.html"/>
    <title>Browser testing on steroids: Running IE 6, 7 and 8 simultaneously on Windows 7</title>
    <published>2009-11-04T00:00:00+00:00</published>
    <updated>2009-11-04T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">I use Windows 7 on my development machine. It works great, and I&apos;ve especially come to like the deep integration features provided by Windows Virtual PC, as I&apos;ll show you in this blog post. They have been a tremendous time-saver when it comes to testing
&lt;a href=&quot;http://www.veturanto.com/&quot;&gt;Veturanto&lt;/a&gt;, the website I am currently working on. I usually test the website using Firefox 3.5, Chrome 3, IE 6, IE7 and IE8.
&lt;br/&gt;
&lt;br/&gt;Firefox, Chrome and IE8 all run natively on Windows 7, no problem there. But what about IE6 and IE7? These guys only run on XP (IE 6 &amp;amp; 7) and Vista (IE 7). Are we out of luck? Not quite. First we have virtualization to the rescue and second we don&apos;t even need our own licenses as Microsoft freely provides
&lt;a href=&quot;http://www.microsoft.com/DOWNLOADS/details.aspx?FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef&amp;amp;displaylang=en&quot;&gt;VHDs
    of both these browsers both on XP SP3 and
    Vista&lt;/a&gt; to run tests on. (Note that they do expire every few months, but Microsoft always provides new ones in time.)
&lt;br/&gt;&lt;br/&gt;This post shows how to use them most effectively to&lt;b&gt; deeply integrate IE 6 and IE 7 into Windows 7&lt;/b&gt;.&lt;br/&gt;
&lt;br/&gt;&lt;span style=&quot;font-size: large;&quot;&gt;So let&apos;s get to work!&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;For this to work we will
&lt;b&gt;need&lt;/b&gt; the following things:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;Windows 7 with &lt;a href=&quot;http://www.microsoft.com/windows/virtual-pc/download.aspx&quot;&gt;Windows Virtual PC&lt;/a&gt;
        installed. It is a free optional component of Windows 7. (On the download page, select Ultimate to reveal the
        download buttons. If you have Windows 7 Home Premium&lt;a
                href=&quot;http://blogs.msdn.com/virtual_pc_guy/archive/2009/10/22/windows-virtual-pc-windows-xp-mode-rtm-now-available-for-general-download.aspx#9911442&quot;&gt;
            you can still use Virtual PC, but not XP Mode&lt;/a&gt;)
    &lt;/li&gt;
    &lt;li&gt;The &lt;a
            href=&quot;http://www.microsoft.com/downloads/details.aspx?displaylang=en&amp;amp;FamilyID=21eabb90-958f-4b64-b5f1-73d0a413c8ef&quot;&gt;XP
        SP3 IE6 and XP SP3 IE7 application compatibility VHDs&lt;/a&gt;, extracted in your Virtual Machines folder.
    &lt;/li&gt;
    &lt;li&gt;A Windows XP Installation CD in your CD drive (this will be needed for the Integration Components
        installation)
    &lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;
&lt;br/&gt;Now that we have all that ready, let&apos;s get started. The following steps describe the IE 6 installation, simply repeat them with the other VHD to install IE 7.
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;1. Select the &lt;b&gt;IE6 on XP SP3.vhd&lt;/b&gt; file and click &lt;b&gt;Create virtual machine&lt;/b&gt; to create a new VM
&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img
        src=&quot;/assets/posts/ie-6-7-8/CreateVirtualMachine.png&quot; alt=&quot;Create VM&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;2. For simplicity&apos;s sake, name it to match the VHD&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/VMName.png&quot;
                                                                     alt=&quot;VM Name&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;3. Leave the memory to its default setting of 512 MB&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/VMmemory.png&quot;
                                                                     alt=&quot;VM Memory&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;4. Associate the VHD with the VM and click &lt;b&gt;Create&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/VMvhd.png&quot;
                                                                     alt=&quot;VM VHD&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;5. Select the VM (&lt;b&gt;IE 6 on XP SP3.vmcx&lt;/b&gt;) and click
    &lt;b&gt;Settings &lt;/b&gt;to mount the XP CD&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/xpcd.png&quot; alt=&quot;XP CD&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;6. Launch the VM by clicking &lt;b&gt;Open &lt;/b&gt;and watch XP boot&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/OpenVirtualMachine.png&quot;
                                                                     alt=&quot;Open VM&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;7. By default a user &lt;b&gt;IETest&lt;/b&gt; with Administrator privileges gets created. &lt;b&gt;Assign it a
    password&lt;/b&gt; (Start -&amp;gt; Control Panel -&amp;gt; User Accounts -&amp;gt; IETest -&amp;gt; Create a password) Pick
&lt;b&gt;IETest &lt;/b&gt;again to keep it simple.&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/createpassword.png&quot;
                                                                     alt=&quot;Create Password&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;8. &lt;b&gt;Update the integration components&lt;/b&gt;, and let the installer reboot the VM when it needs to.&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/upgradeIntegration.png&quot;
                                                                     alt=&quot;Upgrade Integration&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;9. Make sure that at the end of the installation, the checkbox &quot;&lt;b&gt;Download updates required for running
    virtual applications from your PC&lt;/b&gt;&quot; is checked before clicking Finish.&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/downloadcheckbox.png&quot;
                                                                     alt=&quot;Download checkbox&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;10. Download and run the &lt;b&gt;RemoteApp &lt;/b&gt;installer. The
    VM will restart at the end after you click Finish.&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/remoteapp.png&quot;
                                                                     alt=&quot;Remote App&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&amp;nbsp;11. Log in and click &lt;b&gt;Enable Integration
    features&lt;/b&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/enablefeatures.png&quot;
                                                                     alt=&quot;Enable features&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;12. When prompted for credentials, click &quot;&lt;b&gt;Use another account&lt;/b&gt;&quot; and enter
&lt;b&gt;IETest/IETest&lt;/b&gt; and don&apos;t forget to &lt;b&gt;tick the checkbox&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/credentials.png&quot;
                                                                     alt=&quot;Credentials&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;13. Right click Start and select &quot;&lt;b&gt;Open all users&lt;/b&gt;&quot;, go into
&lt;b&gt;Programs &lt;/b&gt;and drag the IE icon from the desktop into this folder.&lt;br/&gt;&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/ieinxp.png&quot;
                                                                     alt=&quot;IE in XP&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;14. If you now go back to the Windows 7 Start menu, you
    will magically find the IE icon again under&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;b&gt;All Programs -&amp;gt; Windows Virtual PC -&amp;gt; IE 6 on XP
    SP3 Applications&lt;/b&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br/&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/ieon7.png&quot;
                                                                     alt=&quot;IE in Win7&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;15. Repeat for IE 7 :-)&lt;br/&gt;
&lt;br/&gt;16. (optional) Pin the icons to the taskbar next to the IE 8 icon, so that they are just only click away.&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/pin.png&quot;
                                                                     alt=&quot;pin&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;&lt;br/&gt;&lt;br/&gt;And finally there you have it, &lt;b&gt;IE 6, IE 7 and IE 8 all running at the same time on Windows 7&lt;/b&gt;:
&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;img src=&quot;/assets/posts/ie-6-7-8/ie678.png&quot;
                                                                     alt=&quot;IE 6 7 8&quot;/&gt;&lt;br/&gt;
&lt;/div&gt;
&lt;br/&gt;Hope you enjoyed it and that it improved your life as much as mine when it comes to testing in different browsers !
</content>
  </entry>
  
  <entry>
    <id>https://axelfontaine.com/blog/http-head.html</id>
    <link type="text/html" rel="alternate" href="/blog/http-head.html"/>
    <title>Transparently supporting HTTP HEAD requests in Java and Spring MVC</title>
    <published>2009-09-03T00:00:00+00:00</published>
    <updated>2009-09-03T00:00:00+00:00</updated>
    <author>
      <name>Axel Fontaine</name>
    </author>
    <content type="html">The http 1.1 specification (RFC 2616) defines a number of &lt;a
        href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html&quot;&gt;methods&lt;/a&gt;: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE and CONNECT.
&lt;br/&gt;&lt;br/&gt;Of these, the most familiar are &lt;b&gt;GET&lt;/b&gt; and &lt;b&gt;POST&lt;/b&gt;.
&lt;br/&gt;Web browsers rely on these two methods to send and receive data from web servers. (In compliance with the &lt;a
        href=&quot;http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.1&quot;&gt;W3C Html 4 recommendation&lt;/a&gt;) &lt;br/&gt;&lt;br/&gt;&lt;a
        href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3&quot;&gt;&lt;b&gt;GET&lt;/b&gt;&lt;/a&gt; is meant for &lt;b&gt;retrieving
    content&lt;/b&gt; from a web server. The requests should be
&lt;b&gt;idempotent&lt;/b&gt;. No critical state should change. Successive requests should return the same content. (This makes them ideal candidates for caching!)
&lt;br/&gt;&lt;br/&gt;&lt;a
        href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5&quot;&gt;&lt;b&gt;POST&lt;/b&gt;&lt;/a&gt; on the other hand is typically used for operations that
&lt;b&gt;manipulate content&lt;/b&gt; on the server, such as adding, editing or removing content.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span
        style=&quot;font-size: large;&quot;&gt;&lt;i&gt;So, what about the other methods, you might ask?&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;Well it turns out browsers are not the only clients talking to our web servers. The web of 2009 has two more essential infrastructure components that our servers frequently have to deal with:
&lt;b&gt;proxy servers&lt;/b&gt; and &lt;b&gt;web crawlers&lt;/b&gt;.
&lt;br/&gt;And it turns out these two types of clients are very fond of a third http method: &lt;b&gt;HEAD&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;&lt;a
        href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4&quot;&gt;&lt;b&gt;HEAD&lt;/b&gt;&lt;/a&gt; is identical to GET except that only the http headers are returned. The body is discarded. This is primarily used for checking the validity of URLs. The load on the server will most likely remain the same as the content-length header must be returned (and thus potentially calculated based on the generated response body). Only the bandwidth is saved.
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;i&gt;How do Java servlets deal with this?&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;Not too bad it turns out ! Deep inside the HttpServlet class (part of the Servlet API 2.5), we find the following code:
&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;protected void doHead(HttpServletRequest req, HttpServletResponse resp)&lt;br/&gt; throws ServletException, IOException {&lt;br/&gt;    NoBodyResponse response = new NoBodyResponse(resp);&lt;br/&gt; &lt;br/&gt;    doGet(req, response);&lt;br/&gt;    response.setContentLength();&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;Here is what  the &lt;b&gt;NoBodyResponse&lt;/b&gt; wrapper does (from the source code documentation):&lt;br/&gt;
&lt;blockquote&gt;A response that includes no body, for use in (dumb) &quot;HEAD&quot; support.&lt;br/&gt;This just swallows that body,
    counting the bytes in order to set the content length appropriately. All other methods delegate directly to the
    HttpServletResponse object used to construct this one.
&lt;/blockquote&gt;&lt;br/&gt;So this means the standard way of the servlet api to deal with with HEAD requests consists of:&lt;br/&gt;
&lt;ol&gt;
    &lt;li&gt;Wrapping the response using the NoBodyResponse in order to suppress the body, but preserve the headers.&lt;/li&gt;
    &lt;li&gt;Execute the GET functionnality of the application (with the wrapped response object)&lt;/li&gt;
    &lt;li&gt;Set the content-length header of the response&lt;/li&gt;
    &lt;li&gt;Return the response headers to the client (without the body)&lt;/li&gt;
&lt;/ol&gt;&lt;br/&gt;Sounds exactly like what we need, so where is the problem?&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;i&gt;&lt;span
        style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Comes in Spring MVC...&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;br/&gt;
&lt;br/&gt;A typical Spring MVC 2.5 controller looks like this (from the Spring 2.5.6 reference documentation):&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;@Controller&lt;br/&gt;@RequestMapping(&quot;/editPet.do&quot;)&lt;br/&gt;@SessionAttributes(&quot;pet&quot;)&lt;br/&gt;public class EditPetForm {&lt;br/&gt;    private final Clinic clinic;&lt;br/&gt;&lt;br/&gt;    @Autowired&lt;br/&gt;    public EditPetForm(Clinic clinic) {&lt;br/&gt;        this.clinic = clinic;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    @ModelAttribute(&quot;types&quot;)&lt;br/&gt;    public Collection&amp;lt;pettype&amp;gt; populatePetTypes() {&lt;br/&gt;        return this.clinic.getPetTypes();&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    @RequestMapping(method = RequestMethod.GET)&lt;br/&gt;    public String setupForm(@RequestParam(&quot;petId&quot;) int petId, ModelMap model) {&lt;br/&gt;        Pet pet = this.clinic.loadPet(petId);&lt;br/&gt;        model.addAttribute(&quot;pet&quot;, pet);&lt;br/&gt;        return &quot;petForm&quot;;&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    @RequestMapping(method = RequestMethod.POST)&lt;br/&gt;    public String processSubmit(&lt;br/&gt;            @ModelAttribute(&quot;pet&quot;) Pet pet, BindingResult result, SessionStatus status) {&lt;br/&gt;&lt;br/&gt;        new PetValidator().validate(pet, result);&lt;br/&gt;        if (result.hasErrors()) {&lt;br/&gt;            return &quot;petForm&quot;;&lt;br/&gt;        }&lt;br/&gt;        else {&lt;br/&gt;            this.clinic.storePet(pet);&lt;br/&gt;            status.setComplete();&lt;br/&gt;            return &quot;redirect:owner.do?ownerId=&quot; + pet.getOwner().getId();&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;/pre&gt;
&lt;br/&gt;The editPetForm controller will respond to the /editPet.do URL.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;GET /editPet.do&lt;/b&gt; executes the &lt;b&gt;setupForm&lt;/b&gt; method.
&lt;br/&gt;&lt;b&gt;POST /editPet.do&lt;/b&gt; executes the &lt;b&gt;processSubmit&lt;/b&gt; method.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;&lt;i&gt;But
    what about HEAD /editPet.do?&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span
        style=&quot;color: red;&quot;&gt;It generates an error!&lt;/span&gt;&lt;/b&gt; Spring MVC cannot find a method annotated with&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;@RequestMapping(method = RequestMethod.HEAD)&lt;/pre&gt;and throws an exception.&lt;br/&gt;
&lt;br/&gt;There are two solutions to this problem.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Solution #1&lt;/span&gt;&lt;/b&gt;&lt;br/&gt;&lt;b&gt;Add
    the missing RequestMapping annotation to all controllers handling GET
    requests.&lt;/b&gt; This solves the problem, but not without significant &lt;b&gt;drawbacks&lt;/b&gt;:&lt;br/&gt;
&lt;ul&gt;
    &lt;li&gt;It is verbose (this annotation must be added to all relevant controllers)&lt;/li&gt;
    &lt;li&gt;It is tedious (every controller must be reviewed)&lt;/li&gt;
    &lt;li&gt;It is error-prone (the burden lies on the developer not to forget this)&lt;/li&gt;
&lt;/ul&gt;&lt;br/&gt;But luckily there is an alternative...&lt;br/&gt;&lt;br/&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Solution #2&lt;/b&gt;&lt;/span&gt;&lt;br/&gt;
&lt;b&gt;Add a servlet filter (in web.xml) in front of the Spring MVC servlet to lie about the http method and present all
    HEAD requests as GET.&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;Here is the code:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;//Imports and documentation have been omitted...&lt;br/&gt;&lt;br/&gt;public class HttpHeadFilter implements Filter {&lt;br/&gt;    public void init(FilterConfig filterConfig) throws ServletException {&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {&lt;br/&gt;        HttpServletRequest httpServletRequest = (HttpServletRequest) request;&lt;br/&gt;&lt;br/&gt;        if (isHttpHead(httpServletRequest)) {&lt;br/&gt;            chain.doFilter(new ForceGetRequestWrapper(httpServletRequest), response);&lt;br/&gt;        } else {&lt;br/&gt;            chain.doFilter(request, response);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public void destroy() {&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private boolean isHttpHead(HttpServletRequest request) {&lt;br/&gt;        return &quot;HEAD&quot;.equals(request.getMethod());&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private class ForceGetRequestWrapper extends HttpServletRequestWrapper {&lt;br/&gt;        public ForceGetRequestWrapper(HttpServletRequest request) {&lt;br/&gt;            super(request);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public String getMethod() {&lt;br/&gt;            return &quot;GET&quot;;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;With this filter, our previous example would work as follows:&lt;br/&gt;
&lt;br/&gt;The HEAD request will be seen as a GET by Spring MVC and therefore&lt;b&gt; HEAD /editPet.do&lt;/b&gt; executes the &lt;b&gt;setupForm&lt;/b&gt; method without the need for the extra annotation!
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;i&gt;But what about the response?&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br/&gt;
&lt;br/&gt;The Spring MVC DispatcherServlet&lt;b&gt; overrides the doService
    method&lt;/b&gt; from HttpServlet. This means that the nice NoBodyResponse logic is overridden, and thus never called.
&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;There are once again two solutions to this problem:&lt;br/&gt;&lt;br/&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;b&gt;Solution
    #1&lt;/b&gt;&lt;/span&gt;&lt;br/&gt;&lt;b&gt;Rely on your web
    container &lt;/b&gt;to suppress the response body for HEAD requests. Some containers, like Apache Tomcat, provide this functionality out of the box. Relying on container-specific behavior will increase your dependency on this particular server. This may or may not be a
&lt;b&gt;problem&lt;/b&gt;.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Solution #2&lt;/span&gt;&lt;/b&gt;&lt;br/&gt;&lt;b&gt;Integrate the
    NoBodyResponse&lt;/b&gt; wrapper with the HttpHeadFilter.&lt;br/&gt;&lt;br/&gt;This is how the final solution looks like:&lt;br/&gt;
&lt;pre class=&quot;prettyprint&quot;&gt;//Imports and documentation have been omitted...&lt;br/&gt;&lt;br/&gt;public class HttpHeadFilter implements Filter {&lt;br/&gt;    public void init(FilterConfig filterConfig) throws ServletException {&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {&lt;br/&gt;        HttpServletRequest httpServletRequest = (HttpServletRequest) request;&lt;br/&gt;&lt;br/&gt;        if (isHttpHead(httpServletRequest)) {&lt;br/&gt;            HttpServletResponse httpServletResponse = (HttpServletResponse) response;&lt;br/&gt;            NoBodyResponseWrapper noBodyResponseWrapper = new NoBodyResponseWrapper(httpServletResponse);&lt;br/&gt;&lt;br/&gt;            chain.doFilter(new ForceGetRequestWrapper(httpServletRequest), noBodyResponseWrapper);&lt;br/&gt;            noBodyResponseWrapper.setContentLength();&lt;br/&gt;        } else {&lt;br/&gt;            chain.doFilter(request, response);&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public void destroy() {&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private boolean isHttpHead(HttpServletRequest request) {&lt;br/&gt;        return &quot;HEAD&quot;.equals(request.getMethod());&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private class ForceGetRequestWrapper extends HttpServletRequestWrapper {&lt;br/&gt;        public ForceGetRequestWrapper(HttpServletRequest request) {&lt;br/&gt;            super(request);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public String getMethod() {&lt;br/&gt;            return &quot;GET&quot;;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private class NoBodyResponseWrapper extends HttpServletResponseWrapper {&lt;br/&gt;        private final NoBodyOutputStream noBodyOutputStream = new NoBodyOutputStream();&lt;br/&gt;        private PrintWriter writer;&lt;br/&gt;&lt;br/&gt;        public NoBodyResponseWrapper(HttpServletResponse response) {&lt;br/&gt;            super(response);&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public ServletOutputStream getOutputStream() throws IOException {&lt;br/&gt;            return noBodyOutputStream;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public PrintWriter getWriter() throws UnsupportedEncodingException {&lt;br/&gt;            if (writer == null) {&lt;br/&gt;                writer = new PrintWriter(new OutputStreamWriter(noBodyOutputStream, getCharacterEncoding()));&lt;br/&gt;            }&lt;br/&gt;&lt;br/&gt;            return writer;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        void setContentLength() {&lt;br/&gt;            super.setContentLength(noBodyOutputStream.getContentLength());&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    private class NoBodyOutputStream extends ServletOutputStream {&lt;br/&gt;        private int contentLength = 0;&lt;br/&gt;&lt;br/&gt;        int getContentLength() {&lt;br/&gt;            return contentLength;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public void write(int b) {&lt;br/&gt;            contentLength++;&lt;br/&gt;        }&lt;br/&gt;&lt;br/&gt;        public void write(byte buf[], int offset, int len) throws IOException {&lt;br/&gt;            contentLength += len;&lt;br/&gt;        }&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;i&gt;Conclusion&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;We now have a &lt;b&gt;drop-in
    solution&lt;/b&gt;, compatible with any web framework and any container. It allows us to &lt;b&gt;transparently support http
    HEAD&lt;/b&gt; requests in our applications and finally treat web crawlers and proxy servers as first class citizens.&lt;br/&gt;
&lt;br/&gt;The source code for &lt;b&gt;HttpHeadFilter&lt;/b&gt; is available &lt;a
        href=&quot;/assets/posts/http-head/HttpHeadFilter.java&quot;&gt;here&lt;/a&gt;. Feel free to use it as you wish.&lt;br/&gt;
&lt;br/&gt;Feedback is always welcome.
</content>
  </entry>
  

</feed>