<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DkcEQ34zfSp7ImA9WhdWGUk.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750</id><updated>2011-09-14T05:00:02.085+09:00</updated><category term="SCM" /><category term="Mule" /><category term="Make" /><category term="Social" /><category term="Complexity" /><category term="snippet" /><category term="Subversion" /><category term="howto" /><category term="ESB" /><category term="jmx tips" /><category term="Build" /><category term="Proguard" /><category term="Configuration Management" /><category term="Integration" /><category term="Java" /><category term="SOA" /><category term="Packaging" /><category term="Testing" /><category term="Firefox" /><category term="groovy" /><category term="Maven" /><category term="Data Mapping" /><category term="ORM" /><category term="Tools" /><category term="NinJava" /><category term="Patterns" /><category term="code" /><category term="Ant" /><category term="Media" /><title>Dimitar's Blog</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://foobarbazqux.blogspot.com/" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>25</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/DimitarsBlog" /><feedburner:info uri="dimitarsblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by/3.0/" /><entry gd:etag="W/&quot;CU4NQHk7eyp7ImA9WhdWGUk.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6679838375705017274</id><published>2011-09-14T04:59:00.000+09:00</published><updated>2011-09-14T04:59:51.703+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-14T04:59:51.703+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Java" /><category scheme="http://www.blogger.com/atom/ns#" term="Packaging" /><title>Common scenarios for Java application packaging</title><content type="html">It all started from an overgrown answer to &lt;a href="http://stackoverflow.com/questions/7381311/best-way-to-package-a-command-line-java-project/"&gt;a question&lt;/a&gt; on StackOverflow. I realized that I haven't seen an overview of best practices and patterns for packaging of Java applications. There are the platform specific packaging formats, but they have more to deal with installation, rather than the layout of the packaged application. Below are a few common scenarios I've come across over the last few years.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: xx-small;"&gt;&lt;b&gt;Note:&lt;/b&gt; I've written another, somewhat related article on SO, about&amp;nbsp;&lt;a href="http://stackoverflow.com/questions/194349/what-is-the-proper-way-to-store-apps-conf-data-in-java/194489#194489"&gt;common strategies for managing configuration files in Java&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
A single uberjar with MAIN-CLASS specified in the manifest is convenient distribution format for simple tool applications that are intended to be run on the command line. You can copy it around and plop it somewhere on the path or in your home directory. &amp;nbsp;If you set the PATHEXT and file associations on Windows, you can run them as if they were native executables. One thing to watch out for is when you bundle libraries with custom entries in the manifest (you might need to manually merge them), when multiple jar's contain files with the same paths but different content (i.e. Spring namespace handlers, ServiceLoader implementations, LDAP SPI providers, etc.)&lt;br /&gt;
&lt;br /&gt;
If for some reason you are bundling a library and all dependencies as a single jar (bad idea), you better take care to relocate the packages (for example, see how the JDK has relocated Xerces and BCEL under com.sun.org...) Not doing so can cause subtle problems to your clients which are extremely annoying, to say the least (*caugh*Weblogic*caugh*). On the other hand, relocating classes causes problem with smart usages of reflection relying on string concatenation. Also, you will most likely need to filter all XML and properties files, replacing the packages with the relocated names. All files under META-INF/services will need to be renamed too. All in all, bundling dependencies in a library jar causes far more problems than it solves.&lt;br /&gt;
&lt;br /&gt;
When your application has more than a few options, you may find you want a config file. One approach I like is to package a template config in my app and look in a predefined location for override (i.e. in ~/.myapp) - you may provide instructions how to extract the template config and place it under the users home or you can have the app do it automatically on first usage. Which one you choose depends on your estimate how often an user will need to tweak the configs (we don't want to pollute the user home unnecessarily). A single directory app is usually installed in your user home directory.&lt;br /&gt;
&lt;br /&gt;
If your application has dependencies on external services or special environment, you will need a startup script (shell or batch file) - in this case, the simplest deployment layout is single directory with uberjar and startup script. As you now have a directory, it is a good idea to add a README file and you may as well put the configs there. There are a number of variations on this theme. Usually, you want to add this directory to the app classpath as well, so any file there may be looked up as resource - that provides convenient way to override things like Spring descriptors, patch single classes, etc. These are usually installed in your home, /usr/local, or sometimes under opt.&lt;br /&gt;
&lt;br /&gt;
If your application bundles many dependencies, has complex configuration, startup scripts for multiple platforms etc. then you will go with full blown deployment structure along these lines (used for big application deployed on multiple platforms):&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;/bin&lt;/b&gt; - startup scripts, rc3.d scripts, environment setup files, registry entries, etc.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/config&lt;/b&gt; - configuration files for app, should be possible to relocate to /etc by specifying env variable.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/logs&lt;/b&gt;&amp;nbsp;- logs produced by app, safe to delete, config should allow us to move it to /var&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/cache&lt;/b&gt; - temporary data produced by app, safe to delete, config should allow us to move it to /var&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/data&lt;/b&gt; - data produced by application, config should allow us to move it to /etc&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/lib&lt;/b&gt; - main application jar with all dependencies&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/lib/win86&lt;/b&gt; - platform specific JNI libs for all supported platforms, selected by the start script, passed as -Djava.library.path=...&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/lib/linux86&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/lib/linux64&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/lib/...&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
The main application JAR should have a Main-Class attribute starting the app and Class-Path attribute specifying the ordering of the dependencies (all located in the same dir). The Class-Path should start with the ../config path that will be used to load configurations and patch classes. This allows to keep the startup scripts simple.&lt;br /&gt;
&lt;br /&gt;
The last layout allows you to run the application from your home, work all from /opt, or install in read-only /opt and put the configs and writable dirs under /etc and /var like a decent Unix application. The last option also allows you to run a few instances with separate configs and data from the same binaries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6679838375705017274?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/TDXka8P_HVM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6679838375705017274/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6679838375705017274" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6679838375705017274?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6679838375705017274?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/TDXka8P_HVM/common-scenarios-for-java-application.html" title="Common scenarios for Java application packaging" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2011/09/common-scenarios-for-java-application.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cNRHYzfSp7ImA9Wx5UGE0.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6958692288995948076</id><published>2010-10-22T22:46:00.005+09:00</published><updated>2010-10-23T11:31:35.885+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-10-23T11:31:35.885+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="snippet" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="groovy" /><title>Groovy Classpath Scanner</title><content type="html">&lt;p&gt;I just wanted a simple classpath scanner in Groovy - no library, no extra jars, no callback interfaces.  I couldn't find any, so I wrote one. I'm posting it here and hopefully it would be useful to somebody. It is licensed under the established and permissive &lt;a href="http://www.opensource.org/licenses/mit-license.php"&gt;MIT License&lt;/a&gt; (if it precludes you from using it, let me know).&lt;/p&gt;

&lt;pre class="brush:groovy"&gt;
import java.util.zip.ZipFile
 
/**
 * &amp;lt;pre&gt;&amp;lt;code&gt;
 * def cps = new GroovyClasspathScanner(packagePrefix: 'com.company.application')
 * cps.scanClasspathRoots(classLoader1) // optional
 * cps.scanClasspathRoots(classLoader2) // optional
 * ...
 * List&amp;lt;Class&gt; classes = cps.scanClasses { Class it -&gt;
 *    Event.isAssignableFrom(it)   ||
 *    Command.isAssignableFrom(it) ||
 *    it.isAnnotationPresent(MessageDescriptor)
 * }
 * &amp;lt;/code&gt;&amp;lt;/pre&gt;
 */
class GroovyClasspathScanner {
  String packagePrefix = ''
  List&amp;lt;File&gt; classpathRoots
 
  @SuppressWarnings("GroovyAssignabilityCheck")
  List&amp;lt;File&gt; scanClasspathRoots(ClassLoader classLoader) {
    if (!classLoader) classLoader = getClass().classLoader
 
    def prefixPath = packagePrefix.replace((char) '.', (char) '/') + '/'
 
    def List&amp;lt;URL&gt; urls = []
    for (URLClassLoader cl = classLoader; cl; cl = cl.parent) {
      urls.addAll cl.URLs
    }
 
    return urls
      .each { assert it.protocol == 'file' }
      .collect { new File(it.path) }
      .each { File it -&gt; if (it.isFile()) assert it.name =~ /.*\.(?:jar|zip)$/ }
      .findAll { File it -&gt;
        (it.isDirectory() &amp;&amp; new File(it, prefixPath).exists()) ||
        (it.isFile() &amp;&amp; new ZipFile(it).entries().find { it.name == prefixPath})
      }
  }
 
  List&amp;lt;String&gt; scanClassNames() {
    if (!classpathRoots) classpathRoots = scanClasspathRoots()
 
    def classNames = []
    def collect = { it, String pathProp -&gt;
      def normalizedPath = it[pathProp].replaceAll('[\\\\/]', '.')
      def packageRegex = packagePrefix.replace('.', '\\.')
      def classRegex = "\\.($packageRegex\\..+)\\.class\$"
 
      def match = normalizedPath =~ classRegex
      if (match) classNames &lt;&lt; match[0][1]
    }
 
    classpathRoots.each {
      if (it.isDirectory()) {
        it.eachFileRecurse             { collect it, 'canonicalPath' }
      } else {
        new ZipFile(it).entries().each { collect it, 'name' }
      }
    }
 
    return classNames
  }
 
  List&amp;lt;Class&gt; scanClasses(Closure predicate = { true } ) {
    return scanClassNames()
            .collect { try { Class.forName it } catch(Throwable e) { println "$it -&gt; $e" } }
            .findAll { it }
            .findAll { predicate(it) }
  }
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6958692288995948076?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/JYqbtRXGRpQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6958692288995948076/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6958692288995948076" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6958692288995948076?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6958692288995948076?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/JYqbtRXGRpQ/i-didnt-want-library-i-didnt-want-extra.html" title="Groovy Classpath Scanner" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2010/10/i-didnt-want-library-i-didnt-want-extra.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQBRH05fCp7ImA9Wx5XGEw.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-2835781928629277094</id><published>2010-09-18T21:57:00.008+09:00</published><updated>2010-09-18T22:25:55.324+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-18T22:25:55.324+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Subversion" /><category scheme="http://www.blogger.com/atom/ns#" term="Patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="SCM" /><category scheme="http://www.blogger.com/atom/ns#" term="Social" /><category scheme="http://www.blogger.com/atom/ns#" term="Configuration Management" /><category scheme="http://www.blogger.com/atom/ns#" term="Complexity" /><title>Concurrent development</title><content type="html">&lt;h4&gt;Background Story&lt;/h4&gt;
&lt;p&gt;That certain project was in its 4th year and after a few successful deployments in the US/LATAM regions, now the company was trying to push it to EU and APAC. The original developers were all in New York and over the last few months have been frantically working to adapt the product to EU's requirements (Asia was supposed to follow.) The scope was defined as 'whatever it takes', the methodology was a mix between 'trial and error' and bullying the users to contort the requirements to fit the delivered functionality. At the time, the EU team had realized that they would better spend their time staying on top of the changes and making sure the end product meets a minimum standard, so they were not really doing much development.&lt;/p&gt;

&lt;p&gt;Time went on, requirements grew, scope shrinked. The project slipped past two deadlines and finally the Asia managers decided they need to take things into their hands and hire a local development team to avoid the communication gap that plagued the EU rollout and regain some control over the schedule. It was first time to have more than one people touching the code the core team was structured in a way that each component has an owner and the owner could do whatever they want. If you have a problem or need a change - ask the owner. The problem was not only that we were in different geographical location, in inconvenient timezone, but we were working on the same code, implementing requirements specified by separate BA teams, chasing schedules devised by separate project-management teams, and it all eventually converged in a common program-steering committee. I could go on, but suffice to say it was quite a mess - the bottom line is that moving from centralized sequential to distributed concurrent development models impose huge burden and the best advice one can give you would be "don't do it!".&lt;/p&gt;

&lt;p&gt;Probably the biggest issue was that many people in the core team, just refused to change their way of working in order to accommodate our existence. Every second morning the trunk would not compile, often changes were checked in that prevent servers from starting, our changes were overwritten routinely because somebody's local modifications conflicted and they were unwilling to merge - you name it, we have it. The management layer was protecting them as &lt;em&gt;"due to the years of accumulated experience, the productivity of the core team was much higher that ours, and the productivity hit they would suffer by addressing our petty complaints can not be justified in business terms"&lt;/em&gt;. Luckily, there were some sensible guys and gradually we got to improve this, still I consider it one of the biggest organizational faults that for a long time the management efforts were focused on suppressing our complaints, rather than backing our suggestions on fixing the environment.&lt;/p&gt;

&lt;p&gt;As the first QA delivery was approaching and the trunk was not giving any signs of getting more stable, we tried to think what can we do to stabilize the codebase. Some people said we should branch, others were weary of the cost of merging. The EU team had branched few months ago and all EU implementation were done on the branch and eventually (read 'sometimes') merged to the trunk. When the product was released in EU, they ended up with the problem how do they merge to the trunk. From what I hear it had been a terrible experience, including a lot of functionality rewrites, introduced bugs and regressions.&lt;/p&gt;

&lt;p&gt;Knowing the EU problems and knowing that on one hand the trunk was still changing rapidly, on the other hand our requirements were dependent on code that was supposed to be delivered by US, we decided to branch, but keep developing on the trunk. All merges would be in direction trunk-to-branch and this would save us from the dreaded criss-cross merge conflicts. Since most of our problems to that date were with work-in-progress checkins, which we eventually wanted, we decided that we can treat the branch as a stable release line and trunk as unstable bleeding-edge code.&lt;/p&gt;

&lt;h4&gt;Unstable trunk + Release branch&lt;/h4&gt;
&lt;p&gt;I was tacitly elected as 'merge-master' and quickly I found myself following the same routine:&lt;/p&gt; 

&lt;ol&gt;
&lt;li&gt;Every morning I would pull a list of all the unmerged commits and review them in a text editor. Then would move each commit into one of these categories:&lt;/li&gt;
&lt;ul&gt;
  &lt;li&gt;WANTED - changes that are required or prerequisites for implementing our business functionality. These should be always &lt;code&gt;merged&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;BLOCKED - changes that we DO NOT want. These should be always &lt;code&gt;marked as merged&lt;/code&gt; (no actual merging, just mark, so they will not appear in the list next time).&lt;/li&gt;
  &lt;li&gt;IRRELEVANT - changes that won't hurt us, but we don't strictly need them. We were merging these in the initial stages as keeping the branch close to trunk makes merging easier, as we got closer to the release, we flipped the policy to improve the stability.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;When I merge or mark as merged the WANTED/IRRELEVANT/BLOCKED groups, I would put the category as a first word int he commit message. This made it easier to pick out the changes that were done directly in the branch (which should be kept to minimum and if necesarry ported manually to trunk). I didn't bother separating the individual changes, since the branch was not meant as a merge-source - this was saving me some time. Overall it was taking between 1 and 3 hours a day.&lt;/li&gt;
&lt;li&gt;There would be a number of changes that didn't make it to any of the categories. For these I was contacting the comitter and following up. Often it was work in progress, sometimes after clarification they would be categorized on the next day. Usually I would post this communication as a tagged blog-entry in our wiki. There was a page displaying all the entries tagged in this way.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I found out that sorting the changes first by user and then by date simplifies the review significantly. Turned out that TextPad macros can be a very powerful tool for things like this.&lt;/p&gt;
&lt;p&gt;The release branch worked well for some time, until a major feature for the next release was implemented on the trunk. We blocked it and ever since then, every commit that touched this dreaded component had to be hand-merged. Often, merging an one-line change resulted in tens of conflicts, so we resorted to rolling back the file in question and manually porting the change. The worst thing is that we tested the trunk extensively, but the change in our release-branch received only cursory examination until it reached QA.&lt;/p&gt;
&lt;p&gt;Furthermore, once we reached the second phase of the Asia roll-out, our team split and started to work in parallel on three staged releases, which were supposed to deliver unrelated functionality within 2 months of each other startin 6 months from the date. This meant that we need better mechanism for dealing with divergent codebase and big changes in progress.&lt;/p&gt;

&lt;h4&gt;Exchange-trunk + Development &amp;amp; Release branches per stream&lt;/h4&gt;
&lt;p&gt;After taking a step back, we came up with a new branching scheme that satisfied all our requirements. For each pending project phase we would create two parallel branches - development and release (we would call the combination of two branches a &lt;code&gt;'stream'&lt;/code&gt;). In addition, we devised the following policies and procedures:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Developers always &lt;code&gt;commit&lt;/code&gt; their code changes in the dev-branches. &lt;/li&gt;
  &lt;li&gt;Any code committed to the dev-branch MUST compile. If the branch is broken, people should not commit further unrelated changes until the CI says it's fixed.&lt;/li&gt;
  &lt;li&gt;Each commit in the dev-branch should contain work for a single feature. If there is certain code pertaining to two features, we pick one of them as primary and mark the other one as dependent in the issue-tracking system. Then, all the shared code goes to the primary feature and we know that we can not release the dependent on its own. It is not necesarry that the whole feature is committed in one go or that the dev-branch committed code actually works.&lt;/li&gt;
  &lt;li&gt;When we need some code from a different stream, we would wait until they &lt;code&gt;publish&lt;/code&gt; it to trunk and only then we would &lt;code&gt;merge&lt;/code&gt; from trunk to the dev-branch. Cross-stream merges are prohibited. We were calling this &lt;code&gt;'picking-up'&lt;/code&gt; the feature. Pick-up changesets should be marked in the commit message.&lt;/li&gt;
  &lt;li&gt;Each time we &lt;code&gt;pick-up&lt;/code&gt; a feature, after we do the minimum conflict resolution, so the code works, we would &lt;code&gt;commit&lt;/code&gt; the changeset immediately (that's the &lt;code&gt;pickup changeset&lt;/code&gt;). This way, any additional enhancements, fixes. etc. will be committed in separate changeset, so it will be easier to merge them back to trunk later.&lt;/li&gt;
  &lt;li&gt;Once a feature is complete and dev-tested on the dev branch, all related changesets for that feature are &lt;code&gt;merged&lt;/code&gt; as one consolidated changeset in the release branch. We call this &lt;code&gt;'feature-promotion'&lt;/code&gt;. This practice makes creating release notes relatively easy and allows us to do cool things such as rolling back the whole feature with one command.&lt;/li&gt;
  &lt;li&gt;When we &lt;code&gt;promote&lt;/code&gt; a feature that has been &lt;code&gt;picked&lt;/code&gt; from trunk, we immediately &lt;code&gt;mark-as-merged&lt;/code&gt; this rel-branch commit into trunk to prevent double-merge conflicts. We would look if we have made any fixes on our branch and consolidate them into a single enhancement/bugfix changeset that will be &lt;code&gt;merged&lt;/code&gt; directly from dev-branch to trunk (as in the the rel-branch we consolidate the pickup and enhancement changesets).&lt;/li&gt;
  &lt;li&gt;If QA finds that the feature did not work, we would add further bugfix changesets to the rel-branch, but we would strive to keep them to minimum.&lt;/li&gt;
  &lt;li&gt;When a release has passed QA, we would &lt;code&gt;merge&lt;/code&gt; each feature-level commit that originated from this stream from the release branch to trunk (&lt;code&gt;'publishing'&lt;/code&gt;). There it will be ready for &lt;code&gt;picking up&lt;/code&gt; by the other streams (which will merge it in their dev-branch, promote it to release, etc).&lt;/li&gt;
  &lt;li&gt;For each release we would tag the release branch, since it was already stabilized. Bugfix releases were just further tags on that same branch. For urgent production changes, we would create a bugfix branch from the tag (happened only a few times).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overall it worked well for us. Few months after we addopted this scheme I moved to another company, but I really hope the process is still useful and being improved. An interesting thing is that every time I explain this, the first reactions are along the lines of "does it have to be that complicated?" And while I can agree that complicated it is, I am still to find a simpler streategy that could work on this scale. Any ideas?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-2835781928629277094?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/om5z7qZKh6Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/2835781928629277094/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=2835781928629277094" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2835781928629277094?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2835781928629277094?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/om5z7qZKh6Y/concurrent-development.html" title="Concurrent development" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2010/09/concurrent-development.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EHRng6eip7ImA9WxBQFUo.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-3018690808507732662</id><published>2010-01-15T23:21:00.004+09:00</published><updated>2010-01-16T01:07:17.612+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-16T01:07:17.612+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="howto" /><title>Setting up PuTTY to use public keys for authentication</title><content type="html">&lt;p&gt;I've looked on the internet for a quick step-by-step guide how to get PuTTY to use public key authentication with OpenSSH daemon and it took me some time to figure. I'm posting these instructions in case anybody else has the same needs.&lt;/p&gt;

&lt;h4&gt;Prerequisites&lt;/h4&gt;

&lt;p&gt;Make sure that your OpenSSH configuration (usually /etc/ssh/sshd_config) contains the following line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PubkeyAuthentication yes&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;In my case (CentOS 5.4) it was disabled by default.&lt;/p&gt;

&lt;p&gt;Also, you would need the full PuTTY suite which can be downloaded form &lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html"&gt;here&lt;/a&gt; (get &lt;tt&gt;putty.zip&lt;/tt&gt;).&lt;/p&gt;


&lt;h4&gt;Generating the key&lt;/h4&gt;

&lt;p&gt;This is a way to generate the key with Putty. Alternatively you can generate it with OpenSSH's &lt;tt&gt;ssh-keygen&lt;/tt&gt; tool and convert it to PuTTY format.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start PUTTYGEN.EXE&lt;/li&gt;
&lt;li&gt;In the parameters box at the bottom of the window, choose type of key 'SSH-2 RSA', set the bit size to 2048.&lt;/li&gt;
&lt;li&gt;Click the Generate button, move the mouse over the blank area until the progres bar fills up.&lt;/li&gt;
&lt;li&gt;Enter your notes in the comment line (this is displayed to you when you use the key, you can change later).&lt;/li&gt;
&lt;li&gt;Enter key-phrase, make it long and complex, write it down in a secure place or print it and hide it somewhere in your freezer.&lt;/li&gt;
&lt;li&gt;Save the private key (*.ppk) in a reasonably secure filesystem location. Even if somebody gets access to your private key, they will still need your passphrase to use it.&lt;/li&gt;
&lt;li&gt;Copy the text from the text box under the &lt;em&gt;'Public key for pasting into OpenSSH authorized_keys file:'&lt;/em&gt; and paste it on one line in a new file called &lt;tt&gt;authorized_keys&lt;/tt&gt; (we'll use that later). The file should contain a single line terminated by Unix-style new-line and there shall not be an empty line after it.&lt;/li&gt;
&lt;li&gt;Close PUTTYGEN.EXE&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Associating the key with your Unix account&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Login to your unix account&lt;/li&gt;
&lt;li&gt;Create a .ssh directory under your home if it does not exist&lt;/li&gt;
&lt;li&gt;Copy the &lt;tt&gt;authorized_keys&lt;/tt&gt; file there&lt;/li&gt;
&lt;li&gt;Do &lt;code&gt;chmod 700 ~/.ssh ; chmod 600 ~/.ssh/authorized_keys&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This needs to be done for each machine you are connecting to. In this case it helps if your homw is NFS mounted.&lt;/p&gt;

&lt;h4&gt;Using the key directly&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Start PuTTY&lt;/li&gt;
&lt;li&gt;Specify &lt;tt&gt;user@host&lt;/tt&gt; in the '&lt;tt&gt;Session &gt; Host Name&lt;/tt&gt;' field.&lt;/li&gt;
&lt;li&gt;Specify the path to your private key file in the '&lt;tt&gt;Connection &gt; SSH &gt; Auth &gt; Private key file&lt;/tt&gt;' box.&lt;/li&gt;
&lt;li&gt;Click the 'Open' button at the bottom of the PuTTY settings dialog.&lt;/li&gt;
&lt;li&gt;When prompted, enter your private-key pass-phrase and you will be logged in without entering your Unix password&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Setting up Pageant to cache the decrypted private key&lt;/h4&gt;

&lt;p&gt;Let's look what we have done. The good thing is that our password does not travel over the wire and is not susceptible to man-in-the-middle attacks. The bad thing is that we used to enter the short and easy password of our Unix account, while now we have to enter the long and difficult pass-phrase of our key every time we establish a new Unix connection. In order to avoid this, we can use PuTTY Pageant which is SSH authentication agent (Unix equivalent is &lt;tt&gt;ssh-agent&lt;/tt&gt;)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start PAGEANT.EXE&lt;/li&gt;
&lt;li&gt;Click on the computer-with-hat icon in your system tray.&lt;/li&gt;
&lt;li&gt;Choose the Add Key option and pick your private key (*.ppk)&lt;/li&gt;
&lt;li&gt;Enter your pass-phrase&lt;/li&gt;
&lt;li&gt;Close the pageant dialog&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From now on, when establishing SSH session Putty will try to use the decrypted key from Pageant first and then fall back to password auth if none of the keys match.&lt;/p&gt;

&lt;p&gt;You can create a shortcut, starting Pageant and passing the paths to your keys as arguments. This will start Pageant and load the keys in one step, but you will still need to specify the pass-phrase every time you do this (typically after system restart).&lt;/p&gt;

&lt;p&gt;Keep in mind that Pageant holds the private key in memory unencrypted. If anybody captures a heap dump of the process, they can get access to your private key without knowing the pass-phrase. That's why, you might want to stop the Pageant if you are not using it for a long time or if you shae the machine in multi-user environment.&lt;/p&gt;

&lt;p&gt;If using Pageant, you might also check the Putty option '&lt;tt&gt;Connection &gt; SSH &gt; Auth agent forwarding&lt;/tt&gt;', which will allow you to use your key from the remote machine on which you are logged on.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-3018690808507732662?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/lyajQ8WFk8Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/3018690808507732662/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=3018690808507732662" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/3018690808507732662?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/3018690808507732662?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/lyajQ8WFk8Y/setting-up-putty-to-use-public-keys-for.html" title="Setting up PuTTY to use public keys for authentication" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2010/01/setting-up-putty-to-use-public-keys-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkACQX4_eSp7ImA9WxBQFkw.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-2327886004523091548</id><published>2010-01-15T16:00:00.012+09:00</published><updated>2010-01-16T13:06:00.041+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-16T13:06:00.041+09:00</app:edited><title>How fast an SSD drive do you need</title><content type="html">&lt;p style="padding: 0.5em; background: #FFFFB0; font-family: Sans-Serif; border: 1px solid silver"&gt;If you need Intel X25-E 32G SSD for 70% of the cheapest listed price (shipping extra), please let me know.&lt;/p&gt;

&lt;p&gt;For a long time I thaught that the bottleneck of all builds was the HDD, so when I got my new notebook, the first thing I did was to add a spiffy extra Intel X25-E SSD hard drive to it. As I expected, the builds went much faster. To my surprise, the HDD throughput stayed fairly low during the build, which suggested that the benefit of SSD drives kicks in early and buying higher grade drives doesn't make much difference as the bottleneck moves to the CPU quite quickly. All this makes sense, considering that a typical application has hundreds to thousands of files and the HDD spends a lot of its time seeking rather than reading.&lt;/p&gt;

&lt;p&gt;When I cleared the IntelliJ IDEA caches and opened the IDEA Community project (total 900MB, 66k files), during the indexing, one of the cores stayed pegged, the HDD read throughput did not exceed 4mb/s for 4 mins then for 1 minute it rose to top 25mb/s, avg I guess around 15mb/s. The write never exceeded 10mb/s, and for most part it was bellow 4mb/s, the last minute was between 5 and 7mb/s.&lt;/p&gt;

&lt;p&gt;During initial compilation, the 2 cores of the CPU (2.53GHz T9400) were quite busy, staying above 80% all the time, the disk utilization during compilation stayed less than 4mb/sec with the ocasional peaks at 6mb/sec. The write peaks were 5mb/sec, for the most time bellow 1mb/sec.&lt;/p&gt;

&lt;p&gt;At the end of the compilation, the index update took 50 seconds, with average read throughput ~10mb/s, peaking at 30.5mb/s, the write peaked at 7mb/sec. During that time the CPU utilization dropped around 50%, which only shows that IDEA's indexing is not using both CPUs.&lt;/p&gt;

&lt;p&gt;The bottomline is - it's not worth byuing expensive SSDs for consumer usage - cheaper ones are just as good for the average home and software development workflow. Most of the applications do not involve transferring huge volumes of data and the slowness of the spinning-platter HDDs is mostly because of seek times and fragmentation. Expensive SDDs are warranted if you are working extensively with media files or are processing huge amounts of data on the disk.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-2327886004523091548?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/dTlBLAlpIjE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/2327886004523091548/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=2327886004523091548" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2327886004523091548?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2327886004523091548?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/dTlBLAlpIjE/how-fast-sdd-drive-do-you-need.html" title="How fast an SSD drive do you need" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2010/01/how-fast-sdd-drive-do-you-need.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8DR304cCp7ImA9WxNbEUo.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-2223084055636681178</id><published>2009-11-14T12:16:00.006+09:00</published><updated>2009-11-14T12:54:36.338+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-14T12:54:36.338+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="jmx tips" /><title>Adding custom handler for JMX service URLs</title><content type="html">&lt;p&gt;Recently, I've been creating some wiki pages describing the JMX management capabilities of the system I work on and I found it quite annoying to use the MX4J HTTP Connector or copy and paste the huge-ass &lt;code&gt;service:jmx:rmi:///jndi/rmi://host:port/connector&lt;/code&gt; URLs, so I dug in MSDN, waisted some time and without further ado, I present you:&lt;/p&gt;

&lt;code&gt;
&lt;pre style="border: 1px solid silver; padding: 0.5em"&gt;
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\SERVICE]
@="URL:Service Location Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\SERVICE\shell]
@="open"

[HKEY_CLASSES_ROOT\SERVICE\shell\open]

[HKEY_CLASSES_ROOT\SERVICE\shell\open\command]
@="\"C:\\Program Files\\Java\\&lt;b style="color: blue"&gt;jdk1.6.0_06&lt;/b&gt;\\bin\\jconsole.exe\" %1"
&lt;/pre&gt;
&lt;/code&gt;

&lt;p&gt;Copy the text in the box above, paste it in Notepad, edit the blue text to point to your latest JDK, save as &lt;code&gt;service-url-handler.reg&lt;/code&gt; and doubleclick to merge in the registry. If you make a mistake, rinse and repeat.&lt;/p&gt;

&lt;p&gt;Once you are done, your can use HTML like this:&lt;/p&gt;

&lt;code&gt;
&lt;pre style="border: 1px solid silver; padding: 0.5em"&gt;
&amp;lt;a title="Static Data Server" href="service:jmx:rmi:///jndi/rmi://prodhost0123:9002/jmxrmi"&amp;gt;manage SDS&amp;lt;/a&amp;gt;
&lt;/pre&gt;
&lt;/code&gt;

&lt;p&gt;On clicking the link, the browser will open JConsole for the specified service URL.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-2223084055636681178?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/U42DFKGPnik" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/2223084055636681178/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=2223084055636681178" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2223084055636681178?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2223084055636681178?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/U42DFKGPnik/adding-custom-handler-for-jmx-service.html" title="Adding custom handler for JMX service URLs" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2009/11/adding-custom-handler-for-jmx-service.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A08GSXczfCp7ImA9WxVSF0g.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-7232872026035566991</id><published>2009-01-12T20:09:00.006+09:00</published><updated>2009-01-12T20:30:28.984+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-12T20:30:28.984+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SOA" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><category scheme="http://www.blogger.com/atom/ns#" term="Complexity" /><title>The other half of the puzzle</title><content type="html">&lt;p&gt;This post on &lt;a href="http://rossmason.blogspot.com/2009/01/how-to-define-services.html" title="Blog: How to Define Services"&gt;service service granularity&lt;/a&gt; from Ross Mason (the original developer of Mule ESB) got me in retrospective mode. I've been thinking about this &lt;a href="http://foobarbazqux.blogspot.com/2008/05/component-granularity-musings.html" title="Blog: Component granularity musings"&gt;before&lt;/a&gt; and with the time, I have come up with some criteria how to break functionality into services. Unfortunately that turned out to be only  half of the puzzle. The other half is the implementation and maintenance strategy that would allow you to achieve your nicely layered boxes-and-arrows vision, while delivering ROI on quarterly intervals and not falling into the &lt;a href="http://www.webservices.org/weblog/joe_mckendrick/the_rise_of_the_jbows_architecture_or_just_a_bunch_of_web_services" title="Blog: The Rise of the JBOWS Architecture"&gt;JBOWS&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/Stovepipe_system" title="Wikipedia: Stovepipe System"&gt;stovepipe-system&lt;/a&gt; pitfalls.&lt;/p&gt;

&lt;p&gt;I personally favor starting top-down, focusing on specific applications and task-level services, and harvesting entity and utility services from working production code. The downside of this is that it is generally more work, often seen as 'tinkering' and in case we consolidate utility code from multiple systems, will likely introduce temporary instabilities. &lt;/p&gt;

&lt;p&gt;This makes it a difficult sell to management - what they see is the IT guys trying to get budget to work on some kind of metaphysical inner-beauty thing instead of delivering new features. Saying that this would reduce bugs is not a great argument, because you will be reminded that's why we pay the QA team and by the way, as a professional you are not supposed to write bugs in the first place.&lt;/p&gt;

&lt;p&gt;On the other side, the PHBs of the world seems to love the idea of the Centers of Excellence, located in China or Malaysia, full of trained and cheap labour, building the utility services and coding the entity diagrams designed by the Architecture Group in their ivory tower, while the solution engineers use point and click tools to churn 'codeless' composite applications. Unfortunately this breaks at the other end - unexpected interactions are discovered at deployment time, maintenance takes too long as the whole turns out to be more than its parts, exhibiting "emergent behavior" (also known as "underspecified features") left and right.&lt;/p&gt;
&lt;p&gt;So, there is no quick and easy way. I guess we need to become IT salesmen and we need to compete with the professional vendor scamsters and the consultancy loan-sharks (that's a topic for another post).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-7232872026035566991?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/yJgv3B64T6c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/7232872026035566991/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=7232872026035566991" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7232872026035566991?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7232872026035566991?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/yJgv3B64T6c/other-half-of-puzzle.html" title="The other half of the puzzle" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><georss:featurename>Tokyo, Japan</georss:featurename><georss:point>35.70943107467961 139.7548196464777</georss:point><georss:box>35.151741574679605 138.8209816464777 36.26712057467961 140.6886576464777</georss:box><feedburner:origLink>http://foobarbazqux.blogspot.com/2009/01/other-half-of-puzzle.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QCQX88eyp7ImA9WxRWGE0.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-1178967084824931412</id><published>2008-10-30T17:46:00.007+09:00</published><updated>2008-11-04T22:29:20.173+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-04T22:29:20.173+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Ant" /><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Build" /><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><title>Mavenizaton - A real life scenario</title><content type="html">&lt;p&gt;The other day I posted a message on a certain vendor&amp;#8217;s support forum asking about the possibility to include minimal POMs in their jars (so they will be easier to mass-import into local repository) and I got the following reply:&lt;/p&gt;

 &lt;blockquote&gt;
  &lt;p&gt;We want to move from ant to maven for a long time but never got a chance to do it. Our ant script is pretty big and complex so we are afraid it will take us a while to migrate to maven. Since we have other important things to work on, we keep delaying this kind of infrastructure things that have relatively less impact than bugs. If you know any way to migrate from ant to maven quickly, I would love to hear.&lt;/p&gt;
 &lt;/blockquote&gt;

 &lt;p&gt;So I asked if I can get access to their Ant script and they kindly sent me that 3000-lines of a beast. &lt;/p&gt;

 &lt;h4&gt;The Challenge&lt;/h4&gt;

 &lt;p&gt;The product is comprised of several modules which have well-defined dependencies on one another and can be used in various configurations. Each configuration is described in a &lt;code&gt;build.properties&lt;/code&gt; file by &lt;code&gt;xxx-source-path&lt;/code&gt;, &lt;code&gt;xxx-properties-path&lt;/code&gt; and &lt;code&gt;xxx-output-path&lt;/code&gt; properties. The &lt;code&gt;source-path&lt;/code&gt; contains both Java files and misc. resources (there are no tests). The &lt;code&gt;xxx-properties-path&lt;/code&gt; contains property files only.&lt;/p&gt;

 &lt;p&gt;In the end, for each module the build produces the following artifacts:&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;JAR files &amp;#8211; depending on properties, these can be:
 &lt;ul&gt;
  &lt;li&gt;Obfuscated with &lt;a href="http://www.zelix.com/klassmaster/"&gt;Zelix KlassMaster&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Debug builds (still obfuscated, but with line-numbers)&lt;/li&gt;
  &lt;li&gt;Postprocessed by &lt;a href="http://retroweaver.sourceforge.net/"&gt;Retroweaver&lt;/a&gt; for Java 1.4 compatibility&lt;/li&gt;
 &lt;/ul&gt;&lt;/li&gt;
  &lt;li&gt;Zipped sources&lt;/li&gt;
  &lt;li&gt;Zipped source stubs &amp;#8211; public and protected method definitions and javadoc (no method bodies)&lt;/li&gt;
  &lt;li&gt;Zipped Javadocs&lt;/li&gt;
  &lt;li&gt;User manual in PDF format&lt;/li&gt;
 &lt;/ul&gt;

 &lt;p&gt;In addition to these primary artifacts, the project:&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;Generates a couple of demo applications packaged as single-click JARs and JNLP. &lt;/li&gt;
  &lt;li&gt;Filters all property and some source files, substituting placeholders with values defined in the &lt;code&gt;build.properties&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Compiles on the fly a doclet and then uses it to generate the source stubs.&lt;/li&gt;
  &lt;li&gt;Creates a bunch of bundles, containing different combinations of the aforementioned artifacts.&lt;/li&gt;
 &lt;/ul&gt;

 &lt;p&gt;The vendor has a policy of releasing new demo-build every day which expires after 28 days.&lt;/p&gt;

 &lt;h4&gt;The First Step &amp;#8211; Fake It&lt;/h4&gt;

 &lt;p&gt;In fact, we, the customers don&amp;#8217;t care whether you are using Maven internally. All we care is to receive a &lt;acronym title="Project Object Model"&gt;POM&lt;/acronym&gt; with correct dependencies and (if possible) to be able to download the libraries from the official Maven repository (a.k.a. &lt;a href="http://repo1.maven.org/maven2/"&gt;Repo1&lt;/a&gt;) or if not &amp;#8211; your private repository (i.e. &lt;tt&gt;http://repo.your-company.com/demo&lt;/tt&gt; or &lt;tt&gt;http://repo.your-company.com/licensed &lt;/tt&gt; ).&lt;/p&gt;

 &lt;p&gt;In order to achieve this:&lt;/p&gt;

 &lt;ol&gt;
  &lt;li&gt;For each artifact, create a &lt;code&gt;pom.properties&lt;/code&gt; file containing 3 properties: &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;groupId&lt;/code&gt; and &lt;code&gt;artifactId&lt;/code&gt;. &lt;/li&gt;
  &lt;li&gt;For each artifact, create a minimal POM containg the artifact group, name, version and dependencies information. Alternatively you can put placeholders and use Ant filtering to resolve the group/name/version from the &lt;code&gt;pom.properties&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Integrate the new files into your build process, treating them as yet another resource file and placing them under the META-INF/maven/your/artifact/group in each artifact JAR.&lt;/li&gt;
  &lt;li&gt;If desired use &lt;code&gt;&lt;a href="http://maven.apache.org/ant-tasks/usage.html"&gt;artifact:deploy&lt;/a&gt;&lt;/code&gt; task to push the artifacts to a Maven repository.&lt;/li&gt;
 &lt;/ol&gt;

 &lt;p&gt;This is all you need to do for the &amp;#8216;regular&amp;#8217; JARs. For the various other files, you would want to use the same artifact name and a &lt;a href="http://maven.apache.org/pom.html#Dependencies"&gt;classifier&lt;/a&gt; I would suggest using:&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;sources&lt;/strong&gt;  &amp;#8211; standard Maven convention, since the full sources are not released to regular customers, it would make sense to have them either under a different classifier (e.g. &lt;strong&gt;fullsources&lt;/strong&gt;) or same classifier, but from a private repo &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;javadocs&lt;/strong&gt; &amp;#8211; standard Maven convention&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;jdk14&lt;/strong&gt; &amp;#8211; for retrozapped binaries&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;debug&lt;/strong&gt; &amp;#8211; for obfuscated binaries with line numbers&lt;/li&gt;
 &lt;/ul&gt;

 &lt;h4&gt;Then you Migrate&lt;/h4&gt;

 &lt;p&gt;If we step back, the current build proces is something like this:&lt;/p&gt;

 &lt;ol&gt;
  &lt;li&gt;Preparation Phase
 &lt;ol&gt;
  &lt;li&gt;Set variables&lt;/li&gt;
  &lt;li&gt;Compile custom doclet&lt;/li&gt;
 &lt;/ol&gt;&lt;/li&gt;
  &lt;li&gt;Generate Sources
 &lt;ol&gt;
  &lt;li&gt;Filter particular files to resolve values from properties&lt;/li&gt;
 &lt;/ol&gt;&lt;/li&gt;
  &lt;li&gt;Compile&lt;/li&gt;
  &lt;li&gt;Copy resources&lt;/li&gt;
  &lt;li&gt;Package binaries (create jar file)&lt;/li&gt;
  &lt;li&gt;Obfuscate&lt;/li&gt;
  &lt;li&gt;Retrozap&lt;/li&gt;
  &lt;li&gt;Javadocs&lt;/li&gt;
  &lt;li&gt;Source Stubs&lt;/li&gt;
  &lt;li&gt;Assemble distribution archives&lt;/li&gt;
  &lt;li&gt;Build the demos&lt;/li&gt;
 &lt;/ol&gt;

 &lt;p&gt;Here is how it would look after we convert the build to Maven:&lt;/p&gt;

 &lt;ol&gt;
  &lt;li&gt;All the path variables go away, replaced by standard Maven directory layout (you should be able to reorganize the source trees for a few hours on a Friday afternoon.) As a last resort you can define custom directories in the build section.&lt;/li&gt;
  &lt;li&gt;The company-name, version, etc. props go away replaced by the respective POM elements.&lt;/li&gt;
  &lt;li&gt;The rest of the settings are specified in &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-profiles.html"&gt;profiles&lt;/a&gt; defined on project or user level.&lt;/li&gt;
  &lt;li&gt;The &lt;a href="http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html"&gt;resource filtering&lt;/a&gt; is a built in feature for maven, but if you need to pre-process Java files, you would need to attach your own plugin to the grnerate-sources lifecycle phase.&lt;/li&gt;
  &lt;li&gt;Compile and Package are standard Maven targets and you don&amp;#8217;t need to do anything.&lt;/li&gt;
  &lt;li&gt;The ZKM obfuscation would be tricky because there is no Maven plug in (or at least I couldn&amp;#8217;t find any). I suggest that you use the &lt;a href="http://maven.apache.org/plugins/maven-antrun-plugin/"&gt;AntRun&lt;/a&gt; plugin as a temporary hack.&lt;/li&gt;
  &lt;li&gt;The Javadoc plugin would automatically generate your Javadocs, you need to explicitly specify a second execution for your &lt;a href="http://maven.apache.org/plugins/maven-javadoc-plugin/examples/alternate-doclet.html"&gt;custom doclet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;The assembly plugin should help you organize your different distributions.&lt;/li&gt;
 &lt;/ol&gt;

 &lt;p&gt;This leaves out a lot of details, but ultimately some of the decisions are yours to make. I would suggest using a script to reorganize your sources, so you can do a number of dry-runs and verify that the result is as expected before you change the script to perform the move in the version control system.&lt;/p&gt;

 &lt;h4&gt;Project Layout Considerations&lt;/h4&gt;

 &lt;p&gt;Each Maven POM has exactly one parent, but can be part of multiple reactors. Both parent and reactors are pom-packaged artifacts, but their role is different. Most tutorials use the same pom for both purposes, but there is benefit in separating the functions (more about this in a bit).&lt;/p&gt;

 &lt;h5&gt;POM Inheritance&lt;/h5&gt;

 &lt;p&gt;The role of the parent is to provide defaults for the child POMs that inherit from it. The POMs are resolved by the normal Maven dependency resolution mechanism, which means that if you want the child projects to reflect a change in a parent-pom, you need to install/deploy the parent first. Alternatively, you can use the &lt;code&gt;project/parent/relativePath&lt;/code&gt; element to explicitly specify the parent-pom&amp;#8217;s path in the file layout (in this case, the changes are picked from the file-system.)&lt;/p&gt;

 &lt;p&gt;At the top-level parent you should use &lt;code&gt;&lt;a href="http://maven.apache.org/pom.html#Dependency_Management"&gt;dependencyManagement&lt;/a&gt;&lt;/code&gt; to specify versions and transitive-dependency-exclusions for all artifacts used by the project. No child-artifacts should explicitly declare versions and exclusions. &lt;/p&gt;

 &lt;p&gt;You should use &lt;code&gt;&lt;a href="http://maven.apache.org/pom.html#Plugin_Management"&gt;pluginManagement&lt;/a&gt;&lt;/code&gt; to fix the plugin versions and (optionally) specify common options for plugins. It&amp;#8217;s ok (although not recommended) to override the plugin options in the children-pom&amp;#8217;s, but you should not specify versions there. If you need the same overrides in multiple children, consider extracting them into intermediary-parent pom.&lt;/p&gt;

 &lt;p&gt;Finally, you should try to specify most of your &lt;code&gt;&lt;a href="http://maven.apache.org/guides/introduction/introduction-to-profiles.html"&gt;profiles&lt;/a&gt;&lt;/code&gt; on a parent-pom level. This, combined with the &lt;code&gt;pluginManagement&lt;/code&gt; allows you to define the bulk your build in the parent and leave the children DRY.&lt;/p&gt;

 &lt;p&gt;The children have to explicitly specify the master-pom version which makes it a bit of a pain to increment the version (on the other side, the master-pom usually changes much slower.) &lt;/p&gt;

 &lt;h5&gt;Building in Dependency Order&lt;/h5&gt;

 &lt;p&gt;The normal way for Maven to resolve dependencies between projects is through the local repository. This means that if project A depends on project B and we make a change in B, in order to test A against the new change, we need to first &lt;code&gt;install&lt;/code&gt; or &lt;code&gt;deploy&lt;/code&gt; B and then build A, so it would pick up the new changes (this is assuming we&amp;#8217;re using SNAPSHOT versions).&lt;/p&gt;

 &lt;p&gt;The reactor projects take care about such closely related artifacts and automatically rebuild them in the correct order. Also they act as a grouping for the sub-projects (useful when you build assemblies). The reactors themselves are artifacts using pom-packaging (same as parents), but they explicitly list the &lt;em&gt;relative path&lt;/em&gt; to each constituting module, and this is the reason that I recommend separation between parents and reactors:&lt;/p&gt;

 &lt;h5&gt;Creating Distributions&lt;/h5&gt;

 &lt;p&gt;The standard way of packaging distributions in Maven is using the &lt;a href="http://maven.apache.org/plugins/maven-assembly-plugin/"&gt;Assembly plugin&lt;/a&gt; . It allows you to describe your distribution package in terms of project resources, artifactsIds and classifiers. A typical assembly descriptor would be:&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;Create a tar and zip files with classifier &amp;#8216;distro&amp;#8217;. 
 &lt;ul&gt;
  &lt;li&gt;Add all files from /src/main/assembly
 &lt;ul&gt;
  &lt;li&gt;excluding **.xml, and **.sh. &lt;/li&gt;
 &lt;/ul&gt;&lt;/li&gt;
  &lt;li&gt;Add all files from /src/main/assembly
 &lt;ul&gt;
  &lt;li&gt;that match **.sh &lt;/li&gt;
  &lt;li&gt;and set the unix permissions to 551. &lt;/li&gt;
 &lt;/ul&gt;&lt;/li&gt;
  &lt;li&gt;Add the maven artifact 
 &lt;ul&gt;
  &lt;li&gt;with group-id=com.company.product.modules and artifact-id=module1 and classifier=obfuscated&lt;/li&gt;
  &lt;li&gt;put it under lib. &lt;/li&gt;
 &lt;/ul&gt;&lt;/li&gt;
  &lt;li&gt;Add all the transitive dependencies of this project (assuming this descriptor is in a reactor project) 
 &lt;ul&gt;
  &lt;li&gt;and put them under lib/ext &lt;/li&gt;
 &lt;/ul&gt;&lt;/li&gt;
 &lt;/ul&gt;&lt;/li&gt;
 &lt;/ul&gt;

 &lt;p&gt;You can also unpack and consolidate JARs, specify manifest-entries and signing for single-JAR distributions and so on.&lt;/p&gt;

 &lt;p&gt;Each artifact can produce more than one assemblies. If you want your assemblies to go into the repo, make sure you use the &amp;#8216;attached&amp;#8217; goal. Most of the times, I use the reactor poms for distributions, but sometimes I just define the assembly in the JAR module&amp;#8217;s POM.&lt;/p&gt;

 &lt;h5&gt;Parents and Children vs. Reactors and Modules&lt;/h5&gt;

 &lt;table&gt;
  &lt;tr&gt;
   &lt;th&gt;Category &lt;/th&gt;
   &lt;th&gt;Parent/Child&lt;/th&gt;
   &lt;th&gt;Reactor/Module&lt;/th&gt;
   &lt;th&gt;&lt;abbr title="When you use the same artifact as both parent and reactor POM (not recommended)"&gt;Merged Parent+Reactor&lt;/abbr&gt; &lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th&gt;Direction of Coupling &lt;/th&gt;
   &lt;td&gt; Children know the &lt;strong&gt;names&lt;/strong&gt; of their parent, parents don&amp;#8217;t know their children &lt;/td&gt;
   &lt;td&gt; Reactors knows the &lt;strong&gt;locations&lt;/strong&gt; of their modules, modules don&amp;#8217;t even know &lt;strong&gt;whether&lt;/strong&gt; they are being built as a part of a reactor &lt;/td&gt;
   &lt;td&gt; Creates circular dependency between children/modules and parent/reactor artifacts. &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th&gt;Multiplicity &lt;/th&gt;
   &lt;td&gt; Each child has exactly one parent, specified in the child POM. &lt;/td&gt;
   &lt;td&gt; A module can be part of more than one reactors. &lt;/td&gt;
   &lt;td&gt; You must keep it to one reactor. If you define alternative reactor, the parent will still be resolved to the main parent-POM (as specified in the children POM&amp;#8217;s), which can lead to a great deal of confusion (and undefined behaviour for some plugins). &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th&gt;Location &lt;/th&gt;
   &lt;td&gt; The parent is usually resolved through the repo (optionally through relative path) &lt;/td&gt;
   &lt;td&gt; The modules are always resolved through relative path &lt;/td&gt;
   &lt;td&gt; You need to physically layout your project, so the parent POM is accessible by relative path (which is not needed otherwise). &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;th&gt;Change Drivers&lt;/th&gt;
   &lt;td&gt; The parent changes when your build process changes. &lt;/td&gt;
   &lt;td&gt; The reactor changes when you add a new module &lt;/td&gt;
   &lt;td&gt; By the artificial coupling, your POM is subject to more change. This is particularly bad for the parent role, because you need to manually update the parent-versions of the children. &lt;/td&gt;
  &lt;/tr&gt;
 &lt;/table&gt;

 &lt;p&gt;Given this table, I&amp;#8217;d recommend a project layout along these lines:&lt;/p&gt;

&lt;pre&gt;
-+-+- project-root/
 |
 +-+- modules/
 | |
 | +-+- module1/ 
 | | |
 | | +--- pom.xml       | inherit from modules parent; specify dependencies 
 | | |                  | and module details (name, version, etc.)
 | | +-+- src/
 | |   +-+- main/
 | |   | +--- java/
 | |   | +--- resources/
 | |   |
 | |   +-+- test/
 | |     +--- java/
 | |     +--- resources/
 | |
 | | 
 | +-+- module2/ 
 | | |
 | | ...
 | |
 | +-+- module3/
 | | |
 | | ...
 | |
 | +-+- reactor1/       | e.g. all modules - used for the CI build and pre-commit
 | | |
 | | +--- pom.xml       | no parent; specify the modules as ../module1, ../module2, etc.
 | |
 | +-+- reactor2/       | e.g. only module2+module3 - used by the module3 developers only
 | | |
 | | +--- pom.xml   
 | |
 | +--- pom.xml         | modules parent - inherits from the main parent pom and specifies 
 |                      | module-specific profiles and plugin settings
 |
 +-+- applications/
 | |
 | +-+- application1/ 
 | | |
 | | +--- pom.xml       | inherit from apps parent; specify dependencies, module details 
 | | |                  | and whatever custom steps necesarry for the application
 | | ...
 | | 
 | +-+- application2/ 
 | | |
 | | ...
 | |
 | +-+- reactor/        | e.g. all applications
 | | |
 | | +--- pom.xml       | no parent; specify the modules as ../application1, ../application2, etc.
 | |  
 | |
 | +--- pom.xml         | apps parent - inherits from the main parent pom and specifies 
 |                      | module-specific profiles and plugin settings
 |
 +--- main-reactor      | specify as modules ../applications/reactor and ../modules/reactor1
 |
 +--- pom.xml           | the main parent pom
&lt;/pre&gt;

 &lt;h4&gt;A few Tips&lt;/h4&gt;

 &lt;h5&gt;When You getStuck with a Bad Plugin&lt;/h5&gt;

 &lt;p&gt;For all operations that you can&amp;#8217;t easily achieve with the existing Maven plugins, you can fall back to the &lt;a href="http://maven.apache.org/plugins/maven-antrun-plugin/"&gt;Antrun&lt;/a&gt; plugin and reuse snippets of your current build script. Yes, it&amp;#8217;s a hack, but it gets the job done and you can fix it when it breaks.&lt;/p&gt;

 &lt;p&gt;Try to keep these hacks in the parent pom.&lt;/p&gt;

 &lt;h5&gt;Dependency Management&lt;/h5&gt;

 &lt;p&gt;When you define dependencies, take care to specify proper scopes (default is &amp;#8216;compile&amp;#8217;, also you should consider &amp;#8216;provided&amp;#8217; and &amp;#8216;test&amp;#8217;). You should also mark all &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html"&gt;optional dependencies&lt;/a&gt; like POI HSSF. For some artifacts you might need to specify dependency-excludes, so Maven doesn&amp;#8217;t bundle half of the Apache Commons with you.&lt;/p&gt;

 &lt;h5&gt;Evaluation Builds&lt;/h5&gt;

 &lt;p&gt;You might want to release the daily evaluation builds as snapshots. Maven has specific semantic for snapshots that it always refreshes them based on timestamp. For example, if you release an artifact &lt;code&gt;my.group:module:1.0.0&lt;/code&gt;, Maven will download it once to the local repository and never look for another version unless you delete it manually (that's why you should NEVER re-cut a release once it's been pushed out - just declare the version broken and increment).&lt;/p&gt;

 &lt;p&gt;If you use a snapshot version (i.e. &lt;code&gt;my.group:module:1.0.0-eval-SNAPSHOT&lt;/code&gt;), Maven will check once a day (unless forced with '-u') and automatically any new version base on timestamp. To achieve this you might want to cut an eval-branch from the tag of each release and change the version using a shell script or something.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-1178967084824931412?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/MM64vANblB4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/1178967084824931412/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=1178967084824931412" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/1178967084824931412?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/1178967084824931412?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/MM64vANblB4/mavenizaton-real-life-scenario.html" title="Mavenizaton - A real life scenario" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/10/mavenizaton-real-life-scenario.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEDRHg9eip7ImA9Wx5XGEw.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-4194862653113026421</id><published>2008-10-25T15:24:00.009+09:00</published><updated>2010-09-18T21:57:55.662+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-18T21:57:55.662+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ORM" /><category scheme="http://www.blogger.com/atom/ns#" term="Complexity" /><title>Why ORM?</title><content type="html">&lt;p&gt;I like Spring JDBC Template - it is simple, clean and saves a lot from the JDBC drudgery. It provides nice abstraction, simplifying the usage and management of prepared statements and overall if all you want is to do an ocasional query, it doesn't get any simpler. Oh, and you have full control on the underlying JDBC connection, allowing you to exploit any vendor-specific functionality. The provided functionality only makes the data access easier and supports only very basic property to column mapping out of the box (or you can write your own mapper in Java). Because of its lightweight nature, JDBC Template does not allow for transparent caching, horizontal table partitioning, vertical sharding, etc. It also doesn't offer lazy fetching of relations, identity tracking and other instrumentation magic.&lt;/p&gt;


&lt;p&gt;Another tool I like is iBATIS. In comparison with JDBC template, it offers more structure, organizing my SQL statements in a logical way and supports most common forms of mapping the result sets to beans (including graphs of objects and joins). Ibatis does support caching (only on a whole query level), still no sharding and partitioning, lazy fetching and identity tracking. IBATIS doesn't try to parse your queries.&lt;/p&gt;

&lt;p&gt;The Abator tool can generate iBATIS CRUD mappings, DDL from object model, and object model from a database, but frankly - in its generated form all these suck. The DDL uses only a few datatypes, has no RI or semantic constraints, nor indexes (I use it sometimes, but only as a boilerplate which I extensively tweak afterwards). The generated beans are isomorphic with the underlying tables, which is great if you are doing CRUD, but I find that most of my applications do data analysis, so the queries tend to be quite hairy, half of them encapsulated in stored procedures (for transaction processing I'd rather use Spring or plain JDBC anyway). The bottom line is that Abator handles the trivial cases, but for most of my projects it doesn't help much, so I'm back to manual coding (which is not that bad anyway.)&lt;/p&gt;


&lt;p&gt;The first time I looked at ORM was when I checked TopLink for a project around 2000. Back then I got the impression that it introduces a lot of new concepts in order to simplify something that's already simple enough - loading a couple of beans from a table. For that project I used plain JDBC, it took me perhaps 20 mins to write and I can't remember taking much time to maintain that code - the total cost should have been less than 3 man-hours.&lt;/p&gt;

&lt;p&gt;The second time I tried Hibernate and Toplink last year (2006) on a prototype with the same dataset and relatively small domain model (for which I finally ended up using iBATIS). The first thing that stroke me was how slow everything was - the startup time was noticeably slower than with iBATIS (about 500-800%), spent in initializing the JPA entity manager and the queries were consistently 30-50% slower. It might have been that I didn't know how to tune it, but I just couldn't achieve satisfactory results. I researched the facilities for mapping to externally defined schema and it stroke me that both Hibernate and TL are way clunkier than iBatis. There were also a number of restrictions that suggested that I need to modify my schema just to enable certain features of the tool... in the end, the identity tracking is a leaky abstraction - the whole story with the attached and detached entities smells to me.&lt;/p&gt;

&lt;p&gt;Now the thousand dolar question, given that most applications out there DO NOT use horizontal partitioning or sharding, caching in the application layer is usually more efficient anyway, identity tracking and the transparent (hidden) lazy fetching often causes more problems than it solves (and countless hours lost in app tuning with dubious results), &lt;strong&gt;why are so many people obsessed with the idea of cramming an ORM into their application?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The other day I wrote a small application that had four composite entities and a couple of fairly sophisticated queries, the the data access part took me about less than an hour (that's implementation, testing and tuning), so:  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How long would it have taken me if I used JPA? (to get reasonably well performing, tested code)&lt;/li&gt;
&lt;li&gt;If you are using ORM, how many entities do you have? How much time (percentage) do you spend working on your persistence logic? Are you using the database as operational storage or are you trating it as a long-term asset? Do you share the DB with other applications?&lt;/li&gt;
&lt;li&gt;Are the productivity gains realized only when your persistent model is so big that it's unmanageable by other means? Is it to futureproof a product (what is a reasonable timeframe for ROI, any examples?)?&lt;/li&gt;
&lt;li&gt;How important is for you the ability to scale your data access to multiple database servers?&lt;/li&gt;
&lt;li&gt;Have you ever switched an application from one SQL server to another? How much effort was it? What does the application do with the DB?&lt;/li&gt;
&lt;li&gt;What are the benefits of using ORM smart caching and partial queries in comparison with in-memory database like TimesTen or H2?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please enlighten me...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-4194862653113026421?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/hugFKzCa7G4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/4194862653113026421/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=4194862653113026421" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/4194862653113026421?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/4194862653113026421?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/hugFKzCa7G4/why-orm.html" title="Why ORM?" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/10/why-orm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IAQnw5eyp7ImA9WxRSEE0.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6982485595680086588</id><published>2008-09-10T01:21:00.002+09:00</published><updated>2008-09-10T10:19:03.223+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-10T10:19:03.223+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><title>On Scopes</title><content type="html">&lt;p&gt;Let's define &lt;em&gt;component&lt;/em&gt; as a programming abstraction that exposes a number of &lt;em&gt;interfaces&lt;/em&gt; and is instantiated and managed by a container. A component has implementation that sits behind the interface and provides the functionality, which could be a custom Java class, a proxy, a BPEL engine, a mock object, or even a &lt;a href="http://en.wikipedia.org/wiki/The_Turk" title="Wikipedia"&gt;mechanical turk&lt;/a&gt; solving captchas.&lt;/p&gt;

&lt;p&gt;In the case of Java class components, they are usually composed of smaller Java classes like the ones in &lt;tt&gt;java.lang.*&lt;/tt&gt; and &lt;tt&gt;java.util.*&lt;/tt&gt; packages. All but the most simple Java objects are actually object graphs which are instantiated, wired togerher and orchestrated by the Java language and the JVM. The Java language specifies the composition structure and behavior, while JVM provides the means to invoke operations and share data. In contrast, the components are instantiated by a &lt;em&gt;container&lt;/em&gt; and the container is responsible to wire them together (usually based on a blueprint in the form of a configuration or class annotations). The container can also provide a number of declarative services to its components: transaction management, access control, performance statistics and transparent distribution. Some popular containers are OSGi, Spring, EJB, ActiveX, MTS/COM+.&lt;/p&gt;

&lt;p&gt;Even if a container can expose a local component over remote interface without &lt;em&gt;requiring&lt;/em&gt; any code changes, practice has shown that taking a single-server application and distributing it in such fashion usually results in a &lt;a href="http://research.sun.com/technical-reports/1994/smli_tr-94-29.pdf" title="A Note on Distributed Computing"&gt;disaster&lt;/a&gt;. This doesn't mean that the non-invasive distribution support is useless though. Given responsible usage, it can enable you to build distributed applications without having to deal with the transport API, using clean and reusable code (&lt;a href="http://en.wikipedia.org/wiki/POJO" title="Wikipedia"&gt;POJO&lt;/a&gt;). There are a number of new frameworks that are built around the concept and try to provide the right level of transparency and control (Mule ESB, Spring Remoting, Spring Integration are some popular choices).&lt;/p&gt;

&lt;p&gt;Once you get too many components in the same contaner, autowiring starts doing most unexpected things, debugging becomes difficult and you start loosing track of your system. The solution is to add scoping. Spring supports limited scoping facilities in the form of parent-child application contexts. Although it solves the problem with configuration visibility, it does not provide facilities for controlling the public interface of the scope (explicitly exported objects). OSGi tackles this problem from a different direction using controlled classloaders, Spring OSGi is trying to be the best of both worlds, giving you scoped configuration and runtime autodiscoverable scoped components.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;lt;interlude/&amp;gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I just finished reading &lt;a href="http://www.amazon.com/Distributed-Event-Based-Systems-Gero-M%C3%BChl/dp/3540326510/" title="Amazon.com"&gt;Distributed Event Based Systems&lt;/a&gt; and they have an excellent chapter on utilizing scopes as means to structure a distributed event-driven application (chapter 6). They suggest a scoped architecture, where each component can belong to multiple scopes, scopes are linked in an arbitrary graph and notifications are governed by the different scope and component properties. The scopes described can declaratively provide a number of services (think AOP for messages).  Some of these services are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Containment&lt;/strong&gt;  - logical grouping of components and other scopes, allowing easy addressing for event dissemination and policy enforcement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scope Interface&lt;/strong&gt; - defining which messages can cross the scope boundary and enforcing this policy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transmission policy&lt;/strong&gt; - determine which scope components will receive a certain message and/or which components have a right to publish/receive messages that cross the scope boundary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mappings&lt;/strong&gt;  - when a message crosses the scope boundary, enrich or transform it based on the source and destination scopes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scopes could be used to delineate groups with different QoS requirements, or to partition the application in geographical or security domains (or even both at the same time) and apply the appropriate policies. Integrating an external systems is also easier, because they are treated as yet another scope (as opposed to "enemy in the bee's nest") and you can provide rich access to the messages that the third party is entitled to without having to bolt on yet another authentication and authorization mechanism.&lt;/p&gt;

&lt;p&gt;The book focuses in great detail and implementation strategies, analyzing different approaches ranging from simplistic (flooding) to very complex (integrated routing). Right now, the described architecture can not be implemented directly in any eventing system that I know of, though we can see some of the ideas in Jini (peer to peer with cooperative filtering), JMS (in implementation supporting topic hierarchies), OSGi (intra-JVM) or SCA (a lot of talk about scopes and composites, but I don't see them doing anything useful with them). The authors also propose a configuration language for managing scoped systems with the specified features. I can see &lt;a href="http://www.amqp.org" title=" Advanced Message Queuing Protocol"&gt;AMQP&lt;/a&gt; as a flexible low-level specification that would allow to build something like this by implementing custom exchanges. We can use the scope configuration language as an intermediate representation, from which we can generate the custom exchange code.&lt;/p&gt;

&lt;p&gt;Ultimately, I believe that in 10 years from now this scoping and routing facilities will become standard part of the messaging middleware (and perhaps hardware?) I'm looking in the general direction of AMQP, possibly SCA (despite their WS-* fetish) and new high level languages directly expressing architectural concerns like &lt;a href="http://www.cs.cmu.edu/~acme/docs/language_overview.html" title="ACME ADL @CMU"&gt;ACME&lt;/a&gt; and &lt;a href="http://einstein.codecauldron.org/" title="Einstein @CodeCauldron"&gt;Einstein&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6982485595680086588?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/3LyUYPZskB8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6982485595680086588/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6982485595680086588" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6982485595680086588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6982485595680086588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/3LyUYPZskB8/on-scopes.html" title="On Scopes" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/09/on-scopes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEEBQ3s4fip7ImA9WxRTE0Q.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6843110546082218845</id><published>2008-09-02T17:18:00.004+09:00</published><updated>2008-09-03T08:04:12.536+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-03T08:04:12.536+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><title>Dynamic components in Mule</title><content type="html">&lt;p&gt;Imagine that you are given to implement the following scenario:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A system is composed of a number of uniform entities, each entity publishes its status 
    on a separate pub-sub topic and accepting instructions over separate control queue.&lt;/li&gt;
&lt;li&gt;Your application receives a stream of instructions over a control channel, 
    instructing it to monitor and control or stop controlling certain entity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;or you receive a stream of active orders and want to subscribe to the right marketdata to 
calculate a relative performance benchmark, or...&lt;/p&gt;

&lt;p&gt;Usually I write about how to implement stuff with Mule, but this time I'm going to write why
Mule might not be your best choice if your use-case is anything like above.&lt;/p&gt;

&lt;p&gt;The most straight forward approach for implementing the system above is to create a 
simple POJO, encapsulating the management algorithm and have a service listen to the 
control channel and instantiate/dispose a new component for each managed entity.&lt;/p&gt;

&lt;p&gt;The problem is that in Mule the components are somewhat heavyweight and it's not so nice when you start having hundreds (approaching thousands) of them. Another problem is that the code for manually creating and registering a componment along with the whole paraphernalia of routers, endpoints, filters and transformers is 
&lt;a href="http://fisheye.codehaus.org/browse/mule/branches/mule-2.0.x/examples/loanbroker/esb/src/test/java/org/mule/example/loanbroker/esb/LoanBrokerEsbConfigurationBuilder.java?r=11569" title="LoanBrokerEsbConfigurationBuilder.java"&gt;
quite&lt;/a&gt; &lt;a href="http://fisheye.codehaus.org/browse/mule/trunk/mule/modules/scripting/src/test/resources/mule-config.groovy?r=9093" title="mule-config.groovy"&gt;
verbose&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The latter problem is easier to solve. There are a couple of JIRA issues that aim to simplify the programmatic configuration (&lt;a href="http://mule.mulesource.org/jira/browse/MULE-2228" title="Java-based configuration mechanism for Mule 2.0"&gt;MULE-2228&lt;/a&gt;,
&lt;a href="http://mule.mulesource.org/jira/browse/MULE-3495" title="Create ServiceBuilder similar to the EndpointBuilder"&gt;MULE-3495&lt;/a&gt;,
&lt;a href="http://mule.mulesource.org/jira/browse/MULE-3580" title="Extend TemplateEndpointRouter to use expressions"&gt;MULE-3495&lt;/a&gt;). The 
&lt;a href="http://muleforge.org/projects.php?projectname=Annotations" title="Mule Annotations Project"&gt;Annotations&lt;/a&gt; project at Muleforge is also worth watching (right now there's no documentation, so you'd need to dig in Subversion).&lt;/p&gt;

&lt;p&gt;The problem with the too many components is more fundamental. The main application domain for Mule is service integration. Though it also happens to be a fairly good application platform, it does fall short when it comes to managing a lot of components. One of the important things missing is the ability to create groups of components with shared thread pools. Another missing thing is better support for variable subscriptions (provide an API to easily add and remove subscriptions to the same component using some kind of template). Another notable improvement would be to elaborate the models into full blown scope-controllers, allowing to create composite applications with proper interfaces, routing policies, etc. All of these are addressable, but there is a long way to go.&lt;/p&gt;

&lt;p&gt;There are also some improvements that can be done to the JMX agent - use JMX relation service to connect component to its endpoint and statistics, all components of certain type, user defined groups of components. Allow the component to exercise some control over the Mule-generated ObjectName so users can organize the different components in groups and ease the monitoring by EMS tools by allowing to query the parameters from a specific group.&lt;/p&gt;

&lt;p&gt;Please share if you've had similar issues, how you dealt with them and whether you think {with the benefit of a hindsight) that the solution was worth the effort. Also I'd like to hear from users/developers of other integration frameworks or composite application containers (Newton?) how they handle these problems.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6843110546082218845?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/Ad88El1Wqp4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6843110546082218845/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6843110546082218845" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6843110546082218845?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6843110546082218845?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/Ad88El1Wqp4/dynamic-components-in-mule.html" title="Dynamic components in Mule" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/09/dynamic-components-in-mule.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIDSH05cSp7ImA9WxRTEko.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-5661634408956064907</id><published>2008-09-01T01:14:00.002+09:00</published><updated>2008-09-01T21:52:59.329+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-01T21:52:59.329+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><title>Transformers vs. Components - Take 2</title><content type="html">&lt;p&gt;In my &lt;a href="http://foobarbazqux.blogspot.com/2008/07/transformers-vs-components.html" title="Transformers vs Components"&gt;previous article&lt;/a&gt;, I claimed that one of the main criteria for which Mule artifact to choose is the multiplicity of the inbound and outbound messages. I've been thinking about it and I want to add two more points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transformers are one instance per endpoint reference. This means that even if you use pooled components, all messages go through single transformer instance. In such case, you need to make sure that the transformer is threadsafe (which is not true if it is holding a JDBC connection or Hibernate session). The components do not have to be threadsafe, though if you are injecting some shared state you still need to properly synchronize the access to it.&lt;/li&gt;
&lt;li&gt; Mule2 services allow you to configure different ways of instantiating the component (singleton, pooled, looked up from Spring/JNDI/OSGi/etc.). In contrast, all transformers defined using the &lt;tt&gt;mule-core&lt;/tt&gt; namespace are prototype-scoped.&lt;/li&gt;
&lt;li&gt;I actualy agree that direct database access belongs in a component. I still think that accessing a cache is kindof a gray area though.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-5661634408956064907?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/EEd7l2dVxcc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/5661634408956064907/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=5661634408956064907" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/5661634408956064907?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/5661634408956064907?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/EEd7l2dVxcc/transformers-vs-components-take-2.html" title="Transformers vs. Components - Take 2" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/09/transformers-vs-components-take-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UBRHY8fSp7ImA9WxdbGUQ.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6374797954622191805</id><published>2008-08-16T01:06:00.007+09:00</published><updated>2008-08-18T01:40:55.875+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-18T01:40:55.875+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Social" /><category scheme="http://www.blogger.com/atom/ns#" term="Media" /><category scheme="http://www.blogger.com/atom/ns#" term="Firefox" /><title>InfoQ, Firefox Hacks and Media Snobbery</title><content type="html">&lt;p&gt;I happen to be one of those people that don't like TV - it's not that I don't watch it when I get a chance, but I've made a conscious decision not to buy one and to get my news and movies from other sources. My primary issue is that TV as a media is too engaging, passive and slow. Radio is also passive and slow, but less engaging, hence better. &lt;/p&gt;

&lt;p&gt;For example: in 10 mins browsing news sites, I can learn more than 10 mins of browsing newspapers, which still fare better than 10 mins of radio, which is just the same as 10 mins of TV, except that when I watch TV I don't do anything else.&lt;/p&gt;

&lt;p&gt;I'm a much faster reader than listener. When I read I can always stop and mull over a sentence for a couple of minutes, go back or skip forward with natural ease. Not so with video and audio. Even though most streaming media these days have some kind of non-linear controls (skip-bar, etc.) it's still impossible to do the equivalent of scanning the headlines or speed-reading in the case of podcast or video content.&lt;/p&gt;

&lt;p&gt;One of the reasons I like the &lt;a href="http://www.infoq.com"&gt;InfoQ&lt;/a&gt; interviews is that they have full transcripts. One of the resons I hate them is that the transcript is enclosed in small box, 250px high in the middle of the screen and one has to click the open and close buttons and scroll like crazy. What I often end up doing is to fire &lt;a href="http://www.mozilla.org/projects/inspector/"&gt;DOM Inspector&lt;/a&gt;, cut off all the DOM nodes except the ancestors of &lt;code&gt;#interviewContent&lt;/code&gt;, switch to CSS properties, delete the &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;max-height&lt;/code&gt; props and this way I end up with full-screen view of the transcript, which I can print or browse at my convenience.&lt;/p&gt;

&lt;p&gt;Today as I was debugging some stuff, I remembered that Firefox &lt;a href="http://www.mozilla.org/unix/customizing.html#userContent"&gt;supports user stylesheets&lt;/a&gt;. By putting the bellow statements in my &lt;tt&gt;${FIREFOX_PROFILE}/chrome/userContent.css&lt;/tt&gt;, I was able to expand the transcript to be readable in a browser without inner scrolling and tweak the printable view to display only the relevant content (no empty squares in place of the flash player or vendor links I can't click on paper.)&lt;/p&gt;

&lt;style type="text/css"&gt;
.ln { color: rgb(0,0,0); font-weight: normal; font-style: normal; }
.s0 { color: rgb(128,128,128); font-style: italic; }
.s1 { color: rgb(0,0,0); }
.s2 { color: rgb(0,0,128); font-weight: bold; }
.s3 { color: rgb(0,0,255); font-weight: bold; }
.s4 { color: rgb(0,128,0); font-weight: bold; }
.s5 { color: rgb(0,0,255); }
&lt;/style&gt;

&lt;pre&gt;
&lt;span class="s0"&gt;/*
 * This file can be used to apply a style to all web pages you view 
 * Rules without !important are overruled by author rules if the author sets any. 
 * Rules with !important overrule author rules. 
 * 
 * For more examples see http://www.mozilla.org/unix/customizing.html 
 */&lt;/span&gt;&lt;span class="s1"&gt; 
 
&lt;/span&gt;&lt;span class="s2"&gt;div#interviewContent&lt;/span&gt;&lt;span class="s1"&gt;, 
&lt;/span&gt;&lt;span class="s2"&gt;div#interviewContent &lt;/span&gt;&lt;span class="s1"&gt;* { 
    &lt;/span&gt;&lt;span class="s3"&gt;height&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;auto &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    &lt;/span&gt;&lt;span class="s3"&gt;max-height&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;none &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    &lt;/span&gt;&lt;span class="s3"&gt;overflow&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;visible &lt;/span&gt;&lt;span class="s1"&gt;! important; 
} 
 
&lt;/span&gt;&lt;span class="s2"&gt;div#interviewContent div div div &lt;/span&gt;&lt;span class="s1"&gt;{ 
    &lt;/span&gt;&lt;span class="s3"&gt;display&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;block &lt;/span&gt;&lt;span class="s1"&gt;! important; 
} 
 
&lt;/span&gt;&lt;span class="s2"&gt;@media print &lt;/span&gt;&lt;span class="s1"&gt;{ 
    * { 
        &lt;/span&gt;&lt;span class="s3"&gt;border&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s5"&gt;0&lt;/span&gt;&lt;span class="s4"&gt;px &lt;/span&gt;&lt;span class="s1"&gt;! important; 
        &lt;/span&gt;&lt;span class="s3"&gt;float&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;none &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    } 
 
    &lt;/span&gt;&lt;span class="s2"&gt;#content&lt;/span&gt;&lt;span class="s1"&gt;, 
    &lt;/span&gt;&lt;span class="s2"&gt;#container&lt;/span&gt;&lt;span class="s1"&gt;, 
    &lt;/span&gt;&lt;span class="s2"&gt;#content-wrapper&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;bottom-corners&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;bottom-corners div&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;top-corners&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;top-corners div&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;box-content&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;box-content-2&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;box-bottom&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;box-content-3 &lt;/span&gt;&lt;span class="s1"&gt;{ 
        &lt;/span&gt;&lt;span class="s3"&gt;margin&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s5"&gt;0 &lt;/span&gt;&lt;span class="s1"&gt;! important; 
        &lt;/span&gt;&lt;span class="s3"&gt;padding&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s5"&gt;0 &lt;/span&gt;&lt;span class="s1"&gt;! important ; 
        &lt;/span&gt;&lt;span class="s3"&gt;float &lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;none &lt;/span&gt;&lt;span class="s1"&gt;! important; 
        &lt;/span&gt;&lt;span class="s3"&gt;width&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s5"&gt;100&lt;/span&gt;&lt;span class="s1"&gt;% ! important; 
        &lt;/span&gt;&lt;span class="s3"&gt;line-height&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s5"&gt;130&lt;/span&gt;&lt;span class="s1"&gt;% ! important; 
    } 
 
    &lt;/span&gt;&lt;span class="s0"&gt;/* these don't work on paper */&lt;/span&gt;&lt;span class="s1"&gt; 
    &lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;comments-sort&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;vendor-content-box &lt;/span&gt;&lt;span class="s1"&gt;{ 
        &lt;/span&gt;&lt;span class="s3"&gt;display&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;none &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    } 
 
    &lt;/span&gt;&lt;span class="s0"&gt;/* visual garbage */&lt;/span&gt;&lt;span class="s1"&gt; 
    .&lt;/span&gt;&lt;span class="s2"&gt;tags3&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;comment-reply&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;comment-header &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="s1"&gt;, 
    .&lt;/span&gt;&lt;span class="s2"&gt;comment-footer&lt;/span&gt;&lt;span class="s1"&gt;, 
    &lt;/span&gt;&lt;span class="s2"&gt;#interviewContent img&lt;/span&gt;&lt;span class="s1"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;alt&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;'show all'&lt;/span&gt;&lt;span class="s1"&gt;], 
    &lt;/span&gt;&lt;span class="s2"&gt;#interviewContent img&lt;/span&gt;&lt;span class="s1"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;alt&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="s4"&gt;'hide all'&lt;/span&gt;&lt;span class="s1"&gt;], 
    &lt;/span&gt;&lt;span class="s2"&gt;#content-wrapper &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt; .&lt;/span&gt;&lt;span class="s2"&gt;box &lt;/span&gt;&lt;span class="s1"&gt;&amp;gt; &lt;/span&gt;&lt;span class="s2"&gt;h2&lt;/span&gt;&lt;span class="s1"&gt;, 
    &lt;/span&gt;&lt;span class="s2"&gt;#footer &lt;/span&gt;&lt;span class="s1"&gt;{ 
        &lt;/span&gt;&lt;span class="s3"&gt;display&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;none &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    } 
 
    &lt;/span&gt;&lt;span class="s0"&gt;/* Fix comment headings */&lt;/span&gt;&lt;span class="s1"&gt; 
    .&lt;/span&gt;&lt;span class="s2"&gt;comment-header &lt;/span&gt;&lt;span class="s1"&gt;* { 
        &lt;/span&gt;&lt;span class="s3"&gt;display&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s4"&gt;inline &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    } 
 
    &lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;comment-header &lt;/span&gt;&lt;span class="s1"&gt;{ 
        &lt;/span&gt;&lt;span class="s3"&gt;border-top&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="s5"&gt;1&lt;/span&gt;&lt;span class="s4"&gt;px solid gray &lt;/span&gt;&lt;span class="s1"&gt;! important; 
    } 
 
} 
&lt;/span&gt;&lt;/pre&gt;

Now the only thing left is to convince the InfoQ guys to start providing transcripts for the presentations and downloadable slides :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6374797954622191805?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/SidJiW6Ue_k" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6374797954622191805/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6374797954622191805" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6374797954622191805?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6374797954622191805?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/SidJiW6Ue_k/infoq-firefox-hacks-and-media-snobbery.html" title="InfoQ, Firefox Hacks and Media Snobbery" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/08/infoq-firefox-hacks-and-media-snobbery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YDQXozeyp7ImA9WxdVGE8.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-7863269136987674239</id><published>2008-07-23T23:53:00.002+09:00</published><updated>2008-07-23T23:59:30.483+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-23T23:59:30.483+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><title>Transformers vs Components</title><content type="html">&lt;p&gt;When I started using Mule, for some time I used to wonder &lt;a href="http://www.nabble.com/transformer-vs.-component-td18610215.html#a18610215"&gt;what's the big difference between a transformer and a component.&lt;/a&gt; Why don't we just stick with the plain pipes and filters model and we complicate it with the 'component' concept?&lt;/p&gt;

&lt;p&gt;In general, transformers have conceptually simpler interface - they are supposed to get a payload and return a payload, possibly of different type. You &lt;em&gt;should&lt;/em&gt; prefer transformers for reusable transformation tasks. On the other hand, transformers can not:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swallow messages - to achieve this use filter or router.&lt;/li&gt;
&lt;li&gt;Return multiple messages - use router.&lt;/li&gt;
&lt;li&gt;Pause temporarily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, despite their more complex configuration components provide some neat features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Message queuing - if your message goes through multiple stages of enrichment, each taking variable time, you might be better off implementing the stages as components and separating them with VM queues.&lt;/li&gt;
&lt;li&gt;Statistics - automatically measures the processing time and volume through each in or outbound endpoint.&lt;/li&gt;
&lt;li&gt;Lifecycle control - you can start, stop or pause component multiple times (while a component is not running the messages will queue up.) The transformers are only initialized and disposed once.&lt;/li&gt;
&lt;li&gt;A componen allows you to tack on multiple filters, transformers, routers, etc. A transformer is one part of this chain.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;To put it together, here is an overview of Mule's component roles in a simple message routing sequence (I'm trying to explain the roles, not the exact sequence.)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The message enters through an inbound endpoint, where the transport extracts the payload and the message headers and bundles them in a message. (The message and some other objects are bundled in EventContext, but it is still a mystery to me why do we need it.)&lt;/li&gt; 
&lt;li&gt;After the message is created it passes through a filter chain, where the filters are applied one after another and each of them votes with true or false a full consensus is required or otherwise the message is rejected. Depending on the config the rejected messages can be routed somewhere else. The filters are not supposed to modify the message (in practice they can, but it's a very bad idea.)&lt;/li&gt;
&lt;li&gt;If a message passes all filters it goes through a transformer chain, where each transformer is applied to the output of the preceding one. A transformer is not able to gracefully reject a message, but it can throw an exception.&lt;/li&gt; 
&lt;li&gt;We might have an interceptor wrapped around the component, which can log stuff before or after invocation or measure latency, etc.&lt;/li&gt;
&lt;li&gt;Based on the payload and on the component type, Mule resolves the method it should call and if necessarry transforms the payload to something that fits. The return value of the method is used as a payload to a single outgoing message.&lt;/li&gt;
&lt;li&gt;The outgoing message is passed to an outbound router, that can split it in multiple messages or just drop it. The router then usually sends the message(s) to arbitrary number of outgoing endpoints. The outgoing router uses the filter chains of the outgoing endpoints to decide which ones to use. The outgoing endpoints can be Mule internal endpoints or periphery endpoints, conecting the application to external system.
&lt;li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, I would recommend that you start with transformer and refactor it to a component if you realize that you want to add any of the aspects mentioned above. You can even easily use transformers as POJO components.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-7863269136987674239?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/EJK1pe077sM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/7863269136987674239/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=7863269136987674239" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7863269136987674239?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7863269136987674239?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/EJK1pe077sM/transformers-vs-components.html" title="Transformers vs Components" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>6</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/07/transformers-vs-components.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUGRnoycCp7ImA9WxdVFkQ.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-2840893101656555794</id><published>2008-07-21T13:50:00.013+09:00</published><updated>2008-07-22T11:03:47.498+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-22T11:03:47.498+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Testing" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><title>Testing Mule applications</title><content type="html">&lt;p&gt;Antoine Borg has posted an intersting article at &lt;a href="http://ricston.com/blog/wp-trackback.php?p=36" title="jMock and Mule"&gt;Ricston Blog&lt;/a&gt; about the feasibility of using mock objects for testing Mule applications. The bottom line is that in integration scenario is usually difficult to capture the application specification in mocks and often it's easier to write stub applications simulating the external systems (outside of your application process).&lt;/p&gt;

&lt;p&gt;I've found that often I don't really test the whole application, but instead I test single components with a few attached transformers, filters and routers. I start by writing a simple Mule configuration - a single component using VM endpoints with queuing. Then I use MuleClient to feed in canned input data and assert the output from the outbound endpoint(s). As the application takes shape, I add transformers and routers as needed to approximate the real usage. &lt;/p&gt;

&lt;p&gt;I could imagine that the next step would be to reuse my production configuration and extract the perimeter endpoint definitions in a new file (separating them from the model, connectors and internal endpoints) and pass the two configuration files to the config builder. This would allow me to create an alternative perimeter endpoints file using VM endpoints, so I can instantiate it in test case and use MuleClient for testing. &lt;/p&gt;

&lt;p&gt;The benefits of the approach are that you are testing your component and routing logic and are not exposed to the peculiarities of the external system. Ideally we still want to have a full integration tests, including ones covering crash-failure, failover, connectivity loss and overload scenarios. We can achieve parts of this by stubbing the external system, but so far I usually find it difficult to reproduce the behaviour faithfully enough (especially when we have limited understanding about the external system).&lt;/p&gt;

&lt;p&gt;No bulletpoints this time.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-2840893101656555794?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/DUhqhau01e0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/2840893101656555794/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=2840893101656555794" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2840893101656555794?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2840893101656555794?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/DUhqhau01e0/testing-mule-applications.html" title="Testing Mule applications" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/07/testing-mule-applications.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04BQ3Y_eSp7ImA9WxdQFUo.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6976740327090745587</id><published>2008-06-16T00:41:00.009+09:00</published><updated>2008-06-16T10:32:32.841+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-16T10:32:32.841+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Social" /><title>Build, Buy or Steal</title><content type="html">&lt;p&gt;&lt;em&gt;This post is based on a text I wrote at my day job. It is edited to reflect my personal opinions and does not represent my employer’s view in any way.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The classic 'build vs. buy' dilemma is further complicated by the new wave of quality open source components.&lt;/p&gt;

&lt;p&gt;Even if we assume that the open-source alternatives are generally inferior to their closed-source counterparts, their low price makes them an attractive choice for getting started, provided that there is an easy migration path to more powerful solutions. Additionally, many open-source tools are backed by commercial companies which can provide support, consulting and guidance on demand.&lt;/p&gt;

&lt;p&gt;Open-source components are often (not always) higher quality than the internally developed libraries. This is because of the usually pretty-good community QA (many users; no time pressures) and the small-vendor mentality of the backing firms (they need to be much better than the industry standard in order to convince a client). Also, a solid OS project provides a decent documentation and community support, often has books written about it and, in general, makes it easier to recruit people already familiar with it.&lt;/p&gt;

&lt;p&gt;We do want to build components in-house when we believe that we can provide &lt;strong&gt;and need&lt;/strong&gt; more value than their OS and commercial counterparts can provide. We always need to keep in account that building good library is a continuous investment in new features, bug fixing and documentation. Providing a sub-optimal internal component is the worst of all worlds.&lt;/p&gt;

&lt;p&gt;Another big question when to contribute our changes back to an open source project. Conventional wisdom says that you shouldn't give our work for free. Still, given the previous paragraph, I would claim that it's in our best commercial interest to contribute back any changes to the external module's core. In such cases, the initial investment is small, the maintenance is high (as we need to reapply changes with every release) and the business value of the code is low. Alternative is to fork the open-source component, which brings us to the problem in the previous paragraph. &lt;/p&gt;

&lt;p&gt;We &lt;em&gt;might&lt;/em&gt; also decide to contribute or open source internally developed extensions of Open Source library, gaining free QA and possibly bugfixes. We &lt;em&gt;should not&lt;/em&gt; open source code that gives us [our product] significant advantage over alternative solutions on the market. We &lt;em&gt;must not&lt;/em&gt; share non-generic code, capturing: business processes, algorithms, site-specific logic, etc.&lt;/p&gt;

&lt;p&gt;And now is the time for the mandatory list at the end of the post. I'm going to enumerate a few build vs buy decision anti-patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Not Invented Here (NIH) Syndrome&lt;/strong&gt; - you know, when we write your own thing because we are too lazy to do our research or read the docs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Wrapping Party&lt;/strong&gt; - every external library is wrapped in order to integrate into the proprietary architectural framework. Though it might look like a good decision, it often leads to difficulties in the debugging, inability to apply best practices and tools, and generally inefficient use of the library&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nobody Got Fired for Buying Expensive Stuff&lt;/strong&gt; - when technical decisions are taken by managers without enough information (or understanding). Sometimes this is rationalized as that all the products look the same on paper, so at least this one comes from a reputable company we can sue. Problem is that often the very expensive do-it-all products require a staff of rocket scientists (or vendor consultants) in order to deliver &lt;em&gt;anything&lt;/em&gt; after that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The First One is Free&lt;/strong&gt; - some vendors try to promote their products as open source, while capturing your data and interfaces in proprietary formats and protocols and then selling services around them. The SOA RAD tools and BPM tools are particularly bad offenders here. The problem is that this limits the ways for evolving your platform. The way to prevent this is to always be aware what part of the solution is platform specific: configuration (is it documented file format), POJO vs proprietary interface components, can you get the whole solution as a bunch of text files, what protocols are used for communication, what is the data storage, can we plug our custom infrastructure, where?&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6976740327090745587?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/tZMnf6eKmyw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6976740327090745587/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6976740327090745587" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6976740327090745587?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6976740327090745587?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/tZMnf6eKmyw/build-buy-or-steal.html" title="Build, Buy or Steal" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/06/build-buy-or-steal.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4CQHg4eip7ImA9WxdRFU0.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-7573683702862701451</id><published>2008-06-03T22:05:00.003+09:00</published><updated>2008-06-03T23:56:01.632+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-03T23:56:01.632+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Complexity" /><title>The Shape of Complexity</title><content type="html">&lt;p&gt;Some things are complex and there's no way around it. Still, even if we can't remove the complexity, often we can shape it into different forms. Some applications have shallow and wide complexity - many simple things with relatively few dependencies, but the overall system has mind-boggling emergent behavior (my favorite 25kloc perl scripts example). Other applications have narrow and deep complexity - small code base, but using so much infrastructure amd metaprogramming, that to understand what's going on, you need to be expert in the platform (think about Hello World written with EJB2 or any application using Ruby on Rails).&lt;/p&gt;

&lt;p&gt;The horizontal complexity is pretty easy to deal with - find two similar things and create abstraction for them, rinse and repeat. It is important to stop and look every now and then for similar abstractions and for ugly usages. Eliminate the similar abstractions by extracting common functionality in helpers or superclasses; deal with the ugly usages by splitting the abstraction.&lt;/p&gt;

&lt;p&gt;By definition, when we introduce abstractions, our complexity becomes 'narrower' and 'taller'. If we put too much stuff into the abstract classes or we nest them too much, we might transform the bunch of simple classes that we couldn't understand when taken together into a somewhat smaller bunch of more complex classes that we can't understand even in isolation. If go overboard in the other direction, e.g. adding too many facades and convenience methods, the API becomes too big without providing enough benefit to learn it (canonical example - I know a project that has a &lt;tt&gt;Strings&lt;/tt&gt; class, containing constants for empty string, single digits, punctoation marks, single letters and other. Apart from being pointless, more verbose and difficult to apply consistently, this also couples all classes in that project to the &lt;tt&gt;util&lt;/tt&gt; package).&lt;/p&gt; 

&lt;p&gt;So, how do we end up with code base that is neither too tall, neither too wide, but just the right shape?&lt;/p&gt; 
&lt;ul&gt;

&lt;li&gt;Acknowledge that the right shape depends on the individual - some people can cope with more abstraction, while others can remember more facts. A metric for abstraction efficiency can be defined as &lt;tt&gt;delta-loc/n&lt;sup&gt;levels-of-indirection&lt;/sup&gt;&lt;/tt&gt; (where &lt;em&gt;n&lt;/em&gt; is a constant bigger than 2).&lt;/li&gt;

&lt;li&gt;Keep in mind the choice of tools - for example IntelliJ IDEA excels at navigating well-factored code, while Vi people often prefer decoupled classes that can be changed with low risk of impacting other areas of code. &lt;/li&gt;

&lt;li&gt;Consider the infrastructure maturity - using XA transactions with JMS is simple, debugging buggy JMS (caugh.. activemq.. caugh) is entirely different issue.&lt;/li&gt;

&lt;li&gt;The experience of the team is important - for some people JMS is the most obvious way to send a piece of data once and only once to another system; others treat JMS as black magic and resort to FTP and cunning rename+move schemes, involving multiple directories and recovery scenarios. &lt;/li&gt;

&lt;li&gt;And finaly, even if different pieces of infrastructure can provide similar functionality, sometimes they vary by the way they do it - in my previous article about component granularity, I mentioned the fat component vs fat Mule configuration scenarios. In this case, we can move the complexity between the Java code and the Mule code. Mule provides out of the box abstractions for threading, routing and transforming, but it is not great as a general-purpose process definition language. Java provides general purpose language, but does not provide high level primitives for threading and routhing. Another example: consider running OLAP against OLTP schema and dedicated warehouse schema - it works, but the difference in speed and CPU utilization can be orders of magnitude.&lt;/li&gt;

&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-7573683702862701451?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/9PRQj7cMYcE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/7573683702862701451/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=7573683702862701451" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7573683702862701451?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7573683702862701451?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/9PRQj7cMYcE/shape-of-complexity.html" title="The Shape of Complexity" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/06/shape-of-complexity.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQBQn49fip7ImA9WxdRFU0.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-7755243635500332467</id><published>2008-05-27T21:38:00.001+09:00</published><updated>2008-06-03T23:45:53.066+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-03T23:45:53.066+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><category scheme="http://www.blogger.com/atom/ns#" term="Complexity" /><title>Pushing Files</title><content type="html">&lt;p&gt;In the next couple of posts I'll try to capture a couple of scenarios that I think Mule (and in general ESB) fits in. The target audience are people like my friend who once asked me once &lt;cite&gt;'Well, I got it - it's all about transports, transformers, routers and components. In the end, what would you use it for?'&lt;cite&gt;&lt;/p&gt;

&lt;p&gt;When I started reading about Mule, the first thing that caught my eye was the huge &lt;a href="http://www.mulesource.org/display/MULE2USER/Transports+Guide" title="Mule Transports Guide"&gt;collection of transports&lt;/a&gt; and &lt;a href="http://www.muleforge.org/activeprojects.php" title="MuleForge - Project List"&gt;third party modules&lt;/a&gt;. It allows you with a relatively little configuration to automate scenarios like sucking a file, uploading it to FTP and sending an email if it failed or moving it to a audit dir on success. Add a few lines and you can have Mule try to upload, if it fails, try to post to JMS queue and if it still fails automatically create a JIRA issue.&lt;/p&gt;

&lt;p&gt;Still, even though Mule is easy to use, it's not simple. Actually even for basic use of Mule, you need to know XML, have idea about &lt;a href="http://www.enterpriseintegrationpatterns.com/"&gt;Enterprise Integration Patterns&lt;/a&gt; and be familiar with Java server applications. Suffice to say that many of my colleagues do not meet these requirements. Compare this with writing a bash or Perl script - it's much easier and quite often it is good enough. I wouldn't be a stretch to say that the TCO of a Perl script for the previous scenario is 10 times less than the TCO of an application built using Mule or any other free or commercial integrated solution.&lt;/p&gt;

&lt;p&gt;Things change a bit when you have a big number of integration jobs. If the tasks are similar, a smart scripter would abstract away the processing, capturing it into a parameterized sub-routine or shell script, with multiple simple wrappers with different arguments. Unfortunately, much too often the strategy is copy-and-modify (especially when the guy who wrote the original script has left the company, and the guy who did the first 30 clones also). Cloning is a pragmatic, low-risk strategy since it minimizes the chance that you break stuff that works. Such developers are usually praised for their get-it-done, goal oriented attitude and management likes their low-risk approach. Still, the dirty secret that nobody likes to talk about is that the system grows in complexity until the moment when nobody knows what is it doing anymore (I think Skynet started that way).&lt;/p&gt;

&lt;p&gt;Even we assume that the TCO of a single Perl script is 10 times less than the one of a Mule implementation, a single Mule instance with relatively little custom development can easily handle the job of all the 170 scripts that I counted in one directory on a production server I use. If we assume that these scripts were derived from 10 archetypes (actually it's less) this still gives us a cost reduction of 170%. Even more important - the Mule and Spring configurations give you a roadmap, which while not trivial is much easier to comprehend and audit than the 27,227 lines of repetitive Perl code.&lt;/p&gt; 

&lt;p&gt;To be fair, in this example I am comparing bad scripting code, written by multiple people over the time, without proper governance to an hypothetical Mule solution written by decent developers. Let's assume that you have a team of good scripting developers, writing well structured code and taking care to provide maintenance documentation and guidelines for extending the system. Actually, this would work fine. Effectively these guys will be defining a platform quite similar to what you get from an ESB (in the end it's all Turing-complete languages). The only catch is that in my experience, in a typical enterprise it's much less probable to meet such Perl coders than the above mentioned Java guys. The argument that Perl programs don't have to be messy is quite similar to "guns don't kill people".&lt;/p&gt;

&lt;p&gt;Even if we assumed that the mythical Perl programers did exist (and you had all three of them in your IT department), there are still a couple of points that make an Mule an attractive solution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mule gives you a proven architectural framework, so you don't have to invent your own. This includes guidelines, some documentation (getting better) and abstract base classes for many of the EIP patterns.&lt;/li&gt;
&lt;li&gt;The business code written against Mule is usually framework agnostic (POJO).&lt;/li&gt;
&lt;li&gt;Various transports, transformers and out-of-the box components.&lt;/li&gt;
&lt;li&gt;Handles advanced stuff as XA transactions and threading models that are just not possible using Perl.&lt;/li&gt;
&lt;li&gt;Since the bulk of your application will be built on a platform, it will be easier to find people whi have some experience with it, which will shorten the learning curve.&lt;/li&gt;
&lt;li&gt;Extensive JMX monitoring and management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are some good reasons to keep cloning scripts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Naturally resilient to regressions.&lt;/li&gt;
&lt;li&gt;Allow you to hire cheaper developers (even if you hire expensive high-qualified ones, they will be just as good as the cheap ones).&lt;/li&gt;
&lt;li&gt;If you plan to scrap the whole thing in the near future (i.e. because the whole system is being replaced)&lt;/li&gt;
&lt;li&gt;If the job is not critical, doesn't change often and forking a script is so easy that there's no point investing in anything better.&lt;/li&gt;
&lt;li&gt;leg·a·cy [ˈle-gə-sē] - code that actually works.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-7755243635500332467?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/IcZII0Y0HWQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/7755243635500332467/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=7755243635500332467" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7755243635500332467?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/7755243635500332467?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/IcZII0Y0HWQ/pushing-files.html" title="Pushing Files" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/05/pushing-files.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQBQn49fyp7ImA9WxdRFU0.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-2081754858456988008</id><published>2008-05-26T19:40:00.002+09:00</published><updated>2008-06-03T23:45:53.067+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-03T23:45:53.067+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><category scheme="http://www.blogger.com/atom/ns#" term="Complexity" /><title>Component Granularity Musings</title><content type="html">This article was written based on my experience with Mule ESB, but the general principles should apply for other similar products as well.&lt;/p&gt;

&lt;h4&gt; Short description of an ESB application&lt;/h4&gt;
&lt;p&gt;A typical ESB (Enterprise Service Bus) application starts with an endpoint, which is an abstraction for a way to receive some '&lt;tt&gt;event&lt;/tt&gt;' which would make us do some work. The event carries some information, which could be structured (i.e. JMS message or HTTP request) or simple (the timer fired) - we'll call this information '&lt;tt&gt;payload&lt;/tt&gt;'. The endpoint passes the event (containing the payload) to a '&lt;tt&gt;component&lt;/tt&gt;', which does some kind of work and optionally emits a single output event. The output event goes to an outbound endpoint which can send the result back to the client, write it into a database, relay it to an external system, or do something else.&lt;/p&gt;

&lt;p&gt;This was a high-level description - the benefits seen from here are that we get to reuse the communication logic between applications and since the endpoints are abstract, we can easily swap the actual transports. Still, a typical ESB provides some additional functionality. In the example above, when we receive an event it was relayed to a predefined component, but that doesn't have to be the case. We can have multiple components configured in the ESB and use '&lt;tt&gt;routers&lt;/tt&gt;' to determine the component that will process this particular event.&lt;/p&gt;

&lt;p&gt;The routers could determine the actual component depending on the payload properties (in which case we call them CBR - content based routers) or based on anything else (e.g. we can have a support call router which routes to different endpoints based on the time of day). When router receives an event, it optionally emits one or many events (unlike a component that optionally emits one). Also, components are supposed to contain exclusively business logic, while routers are mostly concerned with mediating the events in proper manner. Other useful types of routers include aggregating, splitting, resequencing and chaining routers.&lt;/p&gt;

&lt;p&gt;For the sake of completeness there are also '&lt;tt&gt;transformers&lt;/tt&gt;' which can be plugged between endpoint and component to apply some transformation on the event payload, converting the data or adding additional information (enriching); and '&lt;tt&gt;filters&lt;/tt&gt;' which can be used to discard the messages based on some criteria.&lt;/p&gt;

&lt;p&gt;Since the routers, filters and transformers allow us to conditionally specify the components and endpoint, we can choose whether we want to implement our logic inside the component or outside (in the ESB configuration).&lt;/p&gt;

&lt;h4&gt;Ultra-fine grained routing (anemic components)&lt;/h4&gt;

&lt;p&gt;When each component contains no control-flow statements (straight-line imperative code), all the application logic is implemented in the ESB configuration. Some would argue that a system implemented in this fashion is more flexible and allows for faster turnaround and better introspection. While these statements are true, we need to consider the other side as well. &lt;/p&gt;

&lt;p&gt;First, you are mixing business logic and communication logic at the same level, which is bad since it forces the maintainers to understand both (ideally they should be separated as much as possible). Not only this, but your code becomes platform-dependent (the configuration &lt;strong&gt;is&lt;/strong&gt; code and in this case the ESB becomes more of a platform and less of a glue). This in turn increases the chance that upgrades of the ESB software would break your stuff (especially if you use undocumented or experimental features). We also need to keep in mind that the domain complexity has not changed - we are just expressing it using a different language.&lt;/p&gt;

&lt;p&gt;Second, chances are that you have more developers knowing Java than the ESB config language. Also, during development it's much easier to step through the code of a single component rather than trace a message as it goes through multiple queues and thread pools.&lt;/p&gt;

&lt;p&gt;From operations point of view, there are more knobs to turn, which increases the chance to turn the wrong ones. The monitoring can take advantage that there are more inspection points, but then you need the consider the usefulness of this information. Do you really care to know how many executions have you got for sell orders and how many for buy orders? &lt;/p&gt;

&lt;p&gt;Many vendors (IONA, TIBCO, Progress) offer proprietary process modeling and metadata management facilities, allowing to express your business rules, routing and transformations in graphical notation and enforcing integrity based on metadata. These are expensive products and well worth their money if your project is big enough and you want to accept the vendor lock in. In that case, make sure that you make the most of it and take the time to learn how to use them instead of putting a half-assed simplification layer on top of them (just an example - so far I've seen two wrappers around Spring (in different companies) aiming to make it 'easier' to use. No need to say that none of them had any documentation).&lt;/p&gt;


&lt;h4&gt;Ultra-coarse grained routing (fat components)&lt;/h4&gt;

&lt;p&gt;In this scenario we have one component only. Multiple inbound endpoints go in (possibly passing through transformers and filters); and a single stream of events goes out. We use a content-based router to dispatch each event from the output stream, to one of the multiple outbound endpoints.&lt;/p&gt; 

&lt;p&gt;This is a code-centric approach (you won't make much use from a box-and-arrows editor). It allows one to use Java and standard Java tools and debuggers to implement, unit-test and debug the bulk of the application, while still abstracting the communication code and mundane stuff like transformations. If you want to expose application details for monitoring you have to do it by manually registering your custom MBeans or using the Spring JMX exporter.&lt;/p&gt;

&lt;p&gt;One sign that you should consider splitting your component is if you start doing threading. This includes maintaining worker pools, doing half-sync/half-async dispatching, messing with locking, synchronization and notifications.&lt;/p&gt;

&lt;p&gt;Sometimes there might be better abstractions for some pieces of code. For example, if your component is implementing a simple generic transformation and you are using Mule, consider extracting a Transformer. On the other hand, if the transformation is simple, but you feel that it is not generic enough then you have a choice to a) move it to a transformer and have your component focus on the business logic; b) leave it there and reduce the number of classes you maintain.&lt;/p&gt;


&lt;h4&gt;The Fine Line between Fat and Voluptuous... Components&lt;/h4&gt;

&lt;p&gt;...this time it is not the J Lo's booty. Actually, as much as I've looked I haven't found a good set of recommendations about how to structure components in an ESB. There's &lt;a href="http://www5.google.com/search?q=soa%20granularity"&gt;some stuff&lt;/a&gt; from the SOA guys, but they have some ill gotten assumptions that all the invocation between services has to be remote and marshaled through XML, which is not necessarily the case for a single application using ESB as a platform.&lt;/p&gt;

&lt;p&gt;I am in no way authority on EAI, but here is my attempt at defining some guidelines (take them with a big lump of salt):&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;Multiple components make your application complex. A good starting point for a new application is sticking everything in one component and extract components as necessary using the following guidelines. In general I've found it easier to split components than to merge components (Java's method-invocation semantics is less expressive than ESB routing). &lt;/li&gt;

&lt;li&gt;If you need to checkpoint your processing, consider splitting the stages into different components and separating them with durable queues. The queues could be either JMS or Mule VM queues with persistence enabled. With proper use of transactions, this would allow you to survive application crash or do a failover (you still need to take care of any non-transactional endpoints). Alternative is to keep using one component and checkpoint using a distributed transactional cache configured with redundancy.&lt;/li&gt;

&lt;li&gt;If you need to control the resources allocated to certain part of the processing, you can extract it in a separate component and change the number of workers using a &lt;a href="http://en.wikipedia.org/wiki/Staged_event-driven_architecture" title="Staged event-driven architecture"&gt;SEDA&lt;/a&gt; approach (check also &lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=MapReduceRedux" title="Map Reduce - Part 2 (TheServerSide)"&gt;this article&lt;/a&gt;; the &lt;a href="http://eaipatterns.com/BroadcastAggregate.html"&gt;Scatter-Gather&lt;/a&gt; and &lt;a href="http://eaipatterns.com/DistributionAggregate.html"&gt;Composed Message Processor&lt;/a&gt; patterns). Another valid approach is to use a compute grid like GridGain, giving you more functionality, but increasing the total complexity of the application. We should also mention GigaSpaces, providing a platform based on JINI and JavaSpaces with good integration capabilities.&lt;/li&gt;

&lt;li&gt;When parts of the processing have different state lifecycle. It is best illustrated by example: we receive a stream of events on an inbound endpoint (let's call it 'control stream'). Each event has a payload consisting of condition and a 'data stream' endpoint address . On certain conditions, we want to start receiving and processing the events on the data stream in a way which requires independent state. The implementation would be to have one component that would monitor the control stream and keep track of the registered processors, creating new ones as necessary. The processors are concerned only with their data stream of events and each of them has separate state. A clumsy alternative (antipattern?) is to have a single component subscribed for all data streams and use a cache to lookup the state based on some key derived from the incoming event. A possibly better alternative for this specific case is to embed an ESP processor like &lt;a href="http://esper.codehaus.org/"&gt;Esper&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;If you want to extract a component to reuse it, consider extracting it as a domain object first. If it encapsulates processing and is ESB aware, then perhaps it's better off as transformer, router or agent (using Mule terminology here). So far I haven't had the need to reuse a business-logic component between projects.&lt;/li&gt;

&lt;li&gt;If two components are tightly coupled and do not take advantage of any ESB-supplied functionality on the connection between them, consider hiding them behind a single Java facade. It's easier to unit test a POJO than to integration-test a component.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As always, any opinions are welcome.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-2081754858456988008?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/ZcShuzI2q1E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/2081754858456988008/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=2081754858456988008" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2081754858456988008?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/2081754858456988008?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/ZcShuzI2q1E/component-granularity-musings.html" title="Component Granularity Musings" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/05/component-granularity-musings.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYESH47fCp7ImA9WxdSFkU.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-8968085002226922379</id><published>2008-05-25T11:41:00.002+09:00</published><updated>2008-05-25T11:55:09.004+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-25T11:55:09.004+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="Data Mapping" /><title>Transformations using Domain Adapters</title><content type="html">&lt;p&gt;Actually, this entry started as a &lt;a href="http://www.nabble.com/Re%3A-Integration-story-or-5-ways-to-transorm-a-message-p17449381.html"&gt;reply on the Mule-dev mailing list&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote author="Andrew Perepelytsya"&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;What caught my attention was your transformation
challenge. Specifically, how you decided to have a less anemic domain model
and move transformations there instead of dedicated transformers (hope I
didn't misinterpret it). Could you shed more light on this move? This could
be an interesting pattern for some cases.&lt;/p&gt;
&lt;p&gt;Andrew&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, the idea is that your domain uses adapters to wrap the source data and the accessors perform the transformation in place. Since it's usually a straight mapping, we haven't found the need to cache the values.&lt;/p&gt; 

&lt;p&gt;The mutators also store directly to the underlying source bean, except in the cases where the value is derived from multiple input fields and updating them would break some consistency rules (actually in such a case, it would be better to avoid providing accessor if you can). A third approach is to have a map for changed properties and have all your accessors check there first and all mutators write there. This way you don't have to do a deep copy when you move the message using the VM transport.&lt;/p&gt;

&lt;p&gt;The technical part is that there is a transformer, which has its source and output classes configured in the Mule configuration (I've had to add a custom setter for the source class). In the transformer initialization, it resolves a constructor of the output class, that takes a single instance of the source class as argument. The transformation itself is invoking the constructor with the payload. Note that the specified output class has to be a concrete instance in this case. Perhaps I could have done something similar using expressions but I like the type safety of this approach (if one of the classes is missing it blows at runtime).&lt;/p&gt;

&lt;strong&gt;Pros:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;You can easily trace why the data is the way it is.&lt;/li&gt;
&lt;li&gt;Adding new field requires changes to only one class (the adapter).&lt;/li&gt; 
&lt;/ul&gt;
&lt;strong&gt;Cons:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;At least the first layer of adapters is coupled to your source objects (if you use regular transformers, the transformer clearly decouples the src and output models). I would advice putting thest in a separate packages.&lt;/li&gt; 
&lt;li&gt;Needs better regression testing. Usually one catches a good number of breaking data changes in the transformation step. Since we transform on demand, this means that you either need bigger unit test or might have problems go unnoticed until integration testing&lt;/li&gt;
&lt;li&gt;You lug a lot of data around, I can imagine that the serialization and cloning overhead could become prohibitive. In such cases you can have a method like Adapter.pruneStuffIDontNeed() that removes the parts of the input message that have not been used until now (you also need to track them).&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-8968085002226922379?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/-y0yhilYNQw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/8968085002226922379/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=8968085002226922379" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8968085002226922379?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8968085002226922379?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/-y0yhilYNQw/transformations-using-domain-adapters.html" title="Transformations using Domain Adapters" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/05/transformations-using-domain-adapters.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYNQH86eCp7ImA9WxdSGEg.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-8430154976796555519</id><published>2008-05-24T03:54:00.006+09:00</published><updated>2008-05-27T10:03:11.110+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-27T10:03:11.110+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mule" /><category scheme="http://www.blogger.com/atom/ns#" term="Integration" /><category scheme="http://www.blogger.com/atom/ns#" term="Data Mapping" /><category scheme="http://www.blogger.com/atom/ns#" term="ESB" /><title>An Integration Story or 5 Ways to Transform a Message</title><content type="html">&lt;p&gt;It all started when we decided to replace Moxie with Devissa*. Moxie was a decent system and it had aged well, but its years had started to show. The rigid data schema, the  inflexible order representation, the monoloitic C++ server... Don't get me wrong, it was and still is working great, but with the time we realized that we need something more. Something that would let us define the way we do business instead of having us change the business to fit in its model.&lt;/p&gt;

&lt;p&gt;* &lt;small&gt;All names have been changed to protect the innocent&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The global roll out of Devissa looked like a good opportunity to bring in a more capable trading system. Devissa itself, was a huge beast, composed of hundreds of instances of several native processes running with variety of configurations, held together by TCL code, cron jobs and a templated meta-configuration.&lt;p&gt;

&lt;p&gt;The Moxie communication protocol was simple - fixed length records sent in one direction, 32 bit status code in the other, over a TCP socket (actually 2 sockets - uplink and downlink). Devissa was much more complex - the messages were framed using XML-like self-describing hierarchical format (logically it was the standard map of strings-to-arrays of maps... ending up with primitive values at the leaf nodes). The session level protocol was simple and luckily there was a java library for it (I'll bitch about it some other time). On top of the sessions, sit a bunch of application level protocols, each with different QoS and MEP. There is also a registry, authentication service and a fcache/replicator/database/event processor thingie that sits in the center, but I am digressing.&lt;/p&gt;

&lt;p&gt;I'm actually started this article to share some interesting stuff I learned while we migrated the order flow from Moxie to Devissa. The phase-zero was to make a point to point integration Devissa to Moxie using the FIX gateways of the respective products, routing orders entered into Devissa to Moxie, so the traders could work them in the familiar Moxie interface. It allowed us to receive flow from other offices which were already on the Devissa bandwagon and it was great because we didn't have to code data transformations and behaviour orchestration logic - it all 'just worked'.&lt;/p&gt;

&lt;p&gt;The next task was to make sure that we can trade on Devissa and still be able to produce our end-of-day reports from a single point. Right then all reporting was done from Moxie, so what seemed to make most sense was to capture the reportable events from Devissa and feed them back to Moxie. I'll spare you the BA minutae for now.&lt;/p&gt;

&lt;p&gt;As we were looking for a suitable base for creating a platform on which to build various applications around Devissa, I shortlisted a couple of ESB solutions (although it's an interesting topic, I won't talk about "what's an ESB and do I need one"). I looked at &lt;a href="http://www.iona.ie/products/artix" title="IONA Artix"&gt;Artix&lt;/a&gt;, &lt;a href="http://www.tibco.com/"&gt;Tibco&lt;/a&gt;, &lt;a href="http://www.bea.com/aqualogic/" title="BEA Aqualogic"&gt;Aqualogic&lt;/a&gt;, &lt;a href="http://servicemix.apache.org/" title="Apache ServiceMix"&gt;ServiceMix&lt;/a&gt; and &lt;a href="http://www.mulesource.org/" title="Mule ESB"&gt;Mule&lt;/a&gt;. I found that Artix ESB was great, &lt;a href="http://www.iona.com/products/artix/data_services/" title="Artix DataServices"&gt;Artix DS&lt;/a&gt; looked like a good match for our data mapping needs, the only thing I was concerned was the cost. Before I get in contact with the vendor, I asked my managers about our budget - thay replied with almost surprise that we don't know - if it was good and worth the money we might try to pitch it to the global architecture group - in other words, commercial product was not really an option. This ruled out pretty much everything, leaving ServiceMix and Mule (if I was starting now I would also consider Spring Integration). I read a bit about &lt;a href="http://en.wikipedia.org/wiki/Java_Business_Integration" title="Java Business Integration"&gt;JBI&lt;/a&gt;. I tried to like it, I really did... still I couldn't swallow the idea about normalizing your data on each endpoint and being forced to handle all these chunks of XML flying arround. At that time Mule looked like the obvious answer for OS ESB. &lt;/p&gt;

&lt;p&gt;The first thing I had to do was to build custom transport for Moxie and Devissa. That took about 2-3 days. They didn't have any fancy features (actually they barely worked), but I was able to receive a message from one and stuff a message in the other. During the following year both transport evolved a lot, ending up with full rewrite last month, porting them to Mule2 and adding goodies like container-managed dispatcher threading, half-sync support, support for all Devisa application protocols and others.&lt;/p&gt;

&lt;p&gt;The second phase was to build a neutral domain model as described in the Eric Evans's "Domain Driven Design" which I had read recently. Then I wrote two transformers - Devissa2Domain and Domain2Moxie, implemented a simple POJO with about 15 lines of real code and voila - all our Devissa orders and Executions appeared in Moxie. Forking the flow to a database was really easy, since I could use the Mule JDBC connector and it took only 10 lines of config. Storing the messages in XML was also easy with the Mule &lt;a href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt; transformer and the Mule File connector. The world was great.&lt;/p&gt;

&lt;p&gt;Not really. It turned out that the DB storage and the file-based audit were not real requirements, so we cut them really quick (or perhaps they made the first release). Soon, during UAT, it turned out that even though the the BAs had created quite detailed requirements, they didn't match what the business wanted. Even worse - the business itself wasn't sure what they wanted. We were going through a few iterations a day, discovering more data that needs to be mapped, formats that need to be converted, vital pieces of information that were present in one model and not in the other and they had to be either looked up from static table or calculated from couple of different fields and sometimes ended up stuck in a field that had different purpose, which we were not using right now.&lt;/p&gt;

&lt;p&gt;During all this time, the domain model was growing. Each new piece of information was captured clearly and unambiguously in a Java bean with strongly typed properties, validation and stuff. We went live on December 14-th. On the next day the system broke. We kept tweaking the business logic for quite some time and for each tweak, there were always three places to change - the domain model, the inbound transformer and the outbound transformer.&lt;/p&gt;

&lt;p&gt;One day I decided to see what would it be if we drop the domain model altogether and replace the inbound transformer with isomorphic conversion from the Devissa data classes to standard Java collections and then use a rule engine to build the outgoing Moxie message. Enter &lt;a href="http://www.jboss.org/drools/"&gt;Drools&lt;/a&gt;. The experiment was success - in a couple of days, I was able to ditch my domain model (which has grown to be so specific to the application that it wasn't really neutral any more). Drools was working fine, though I had the feeling that something was wrong... I never asserted, nor retracted any facts in my consequences - I was abusing the &lt;a href="http://en.wikipedia.org/wiki/Rete_algorithm" title="Wikipedia: Rete algorithm"&gt;Rete&lt;/a&gt; engine. Actyally, all I was doing was a glorified switch statement.&lt;/p&gt;

&lt;p&gt;While I was at it, I decided to ditch Drools as well and use &lt;a href="http://mvel.codehaus.org/"&gt;MVEL&lt;/a&gt; - one of the consequence-dialects of Drools, which turned out to be a nice, compact and easy to embed language. MVEL is designed mainly as expression language, though it has control-flow statements and other stuff. With MVEL, all my transformation fitted on one screen and had the familiar imperative look and feel, but without the cruft. I was able to plug some Java functions using the context object, which allowed me to hide some ugly processing; and the custom resolvers allowed me to resolve MVEL variables directly from the Devissa message and assign them directly to the properties of the Moxie message beans.&lt;/p&gt;

&lt;p&gt;Some time after that, for different project, building on the same foundation, I decided to see if I can infer an XML schema from the XML serialization of the Devissa messages. After some massaging I used that schema to generate the domain model using &lt;a href="http://en.wikipedia.org/wiki/JAXB" title="Wikipedia: Java Architecture for XML Binding"&gt;JAXB&lt;/a&gt; and tried to see how it feels. It was a disaster. A typical Devissa message has more than 50 properties (often more than 100). Usually you need 10-20 of them. Alsi, the generated property names were ugly. Even after conversion from CONSTANT_CASE to camelCase, they were still ugly. The automatically generated beans was practically unusable, the XML looked not-human-editable, the XSD was not adding any real value since it lacked any semantic restrictions, so the whole thing felt like jumping through hoops. In the end I dropped the whole JAXB idea and went with MVEL again.&lt;/p&gt;

&lt;p&gt;3rd time lucky, beginning of this March, I started a new project. This time I again decided to try a new approach - in the inbound transformer, I was wrapping the raw Devissa message in an adapter, exposing the fields I need as bean properties, but carrying the full dataset of the original messages. It works well. One particular benefit is that you can always look at the source data and see if there is anything there that might be useful.&lt;/p&gt;

&lt;p&gt;In conclusion I'll try to summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Neutral model plus double translation can yield benefits when the domain is well known, especially if it is externally defined (i.e. standard). On the other hand it's a pain in the ass to maintain, especially if the domain objects change frequently.&lt;/li&gt;
&lt;li&gt;Rule engines are good when you have... ahem, rules. Think about complex condition and simple consequence. Actually, in the original Rete paper, the consequences are only meant to assert and retract facts. Changing an object in the working memory or doing anything else with side-effect behind the engine's back is considered a bad practice at best or (usually) plain wrong. Even when using fact invalidation (truth maintenance), it has big performance impact.&lt;/li&gt;
&lt;li&gt;Direct mapping using expression language works well, especially for big and complex messages. The scripts are compact and deterministic, which makes them maintainable. You might need to write your own variable resolvers and extend the language with custom functions. Also, debugging could be a nusance, but if you keep your control-flow to minimum and use plugged Java functions, it's quite OK.&lt;/li&gt;
&lt;li&gt;Adapters are a middle ground between double translation and direct mapping. They tend to work well to provide internal representation for the application, you can also stuff some intelligence in them without worrying that somebody might regenerate them. With a bean mapping framework like Dozer you can even automate the transformation to the output datatype, though for many cases that would be overkill (sometimes 200 lines of straight Java code are more maintainable than 50 lines of XML or 10 lines of LISP).&lt;/li&gt;
&lt;li&gt;Xml works well if your output format is XML; if you need to apply transformations with XSLT or render it using XSL:FO. As we know, you can run XPath on bean and collection graphs using &lt;a href="http://commons.apache.org/jxpath/"&gt;JXpath&lt;/a&gt;; also any expression language can provide sililar capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next time, I'll write about component decomposition, content-based routing vs coarse-grained components and how to decide whether to do the transformation in a component or in a transformer.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-8430154976796555519?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/7_8IPNB2VIM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/8430154976796555519/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=8430154976796555519" title="9 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8430154976796555519?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8430154976796555519?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/7_8IPNB2VIM/integration-story-or-5-ways-to.html" title="An Integration Story or 5 Ways to Transform a Message" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>9</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2008/05/integration-story-or-5-ways-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYHQXk6eip7ImA9WxdREE8.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-8715568722703615612</id><published>2007-12-01T19:48:00.000+09:00</published><updated>2008-05-29T10:55:30.712+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-29T10:55:30.712+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Proguard" /><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><title>Obfuscating the GUI</title><content type="html">&lt;p&gt;When I was working on mobile applications, obfuscation was mandatory part of the build. When every byte counts, you can not afford to have long variable names or carry extra stuff if it's not critical to the application functionality. In fact we didn't really care about the actual obfuscation (it's quite difficult to take an app out of the phone anyway, and even then, the success of a mobile game usually does not depend on some top-secret algorithms). Back then it was all about jar size.&lt;/p&gt;

&lt;p&gt;The other day, I got the task to obfuscate an application that we wanted to ship to external client. The app was a SWT GUI, making use of reflection, runtime generics and runtime attributes. Also, the idea was to merge all libraries in the app jar and wrap everything in a native launcher. First I tried to merge the JARs. There was a small issue with the order of merging, since one of the libraries needed some file in META-INF, which existed in more than one jars, but overall no major problems (good that we didn't use OSGI).&lt;/p&gt;

&lt;p&gt;Next step was the obfuscation. Obfuscating a moble app is pretty straightforward - you define all the library interfaces as seeds and let the obfuscator do the rest... errr, I guess that wasn't very clear, perhaps I should step back and take a look at &lt;a href="http://proguard.sourceforge.net/" title="ProGuard Project Site (at Sourceforge)"&gt;ProGuard&lt;/a&gt; (my weapon of choice when it comes to free obfuscators), but the principles should apply to most of the products on the market.&lt;/p&gt;

&lt;p&gt;The ProGuard obfuscation consists of a couple of stages:&lt;/p&gt;

&lt;h4&gt;Shrinking&lt;/h4&gt; 
&lt;p&gt;Starting from a specified &lt;code&gt;seed classes or methods&lt;/code&gt;, analyze the control flow and remove all the reachable code. The different obfuscators have different ways of specifying the seeds, the simplest ones being "keep everything which is not part of my source" (this is actually enough for a mobile application) of "keep everything". You also need to include here any class which is accessed by reflection only (think plugins and DI), native methods, classes accessed exclusively from native code, classes used as default values of annotation attributes unless you always specified a proper value, etc. &lt;/p&gt;

&lt;p&gt;The shrinking also removes all the attributes from the classes fields and methods. If this doesn't mean much to you, you are not alone - one usually doesn't think about what's in a class until things start breaking (and break they did).&lt;/p&gt; 

&lt;p&gt;The first problem was that all stacktraces did not contain line numbers. That was actually easy to fix - just keep the &lt;code&gt;LineNumberTable&lt;/code&gt; attribute and replace the &lt;code&gt;SourceFile&lt;/code&gt; and &lt;code&gt;SourceDir&lt;/code&gt; with fixed string - both are quite easy with ProGuard.&lt;/p&gt; 

&lt;p&gt;Next problem was that the DI container could not read the generic attributes from the collections and was sticking inside strings instead of URLs. Again - the &lt;code&gt;Signature&lt;/code&gt; attribute contains the information used by the runtime generics reflection. &lt;/p&gt;

&lt;p&gt;Then I found that none of my runtime annotations were kept. After some time spent staring dumb at the JVM spec (Chapter 4), I learned that the annotations are kept in anoher set of attributes - namely &lt;code&gt;RuntimeVisibleAnnotations&lt;/code&gt; and &lt;code&gt;RuntimeVisibleParameterAnnotations&lt;/code&gt;.  The annotation default values are kept in an &lt;code&gt;AnnotationDefault&lt;/code&gt; attribute of the corresponting method in the annotation class (or interface if you prefer) - you can strip these if you specify explicit values for all annotations. &lt;/p&gt;

&lt;p&gt;There were also some attributes related to enums, but it looks like they are not used at run time.&lt;/p&gt;

&lt;h4&gt;Optimization&lt;/h4&gt;
&lt;p&gt;Not really sure what it does exactly. I have seen it reduce the number of methods, but it has really only two settings - "optimize" (yes/no) and "number-of-passes". I guess that each pass does one level inlining if a method meets certain criteria, but it might also do many other whole-program optimizations.&lt;/p&gt; 

&lt;p&gt;One thing which might be interesting is a profile-guided optimization like the Intel C++ compiler, where the optimizer would first instrument your classes, adding probes to your bytecode. Then you would run your app a couple of times to generate execution profiles and then optimize your app using them. Of course that's partly what the Hotspot already does, but not everybody uses Hotspot and in any case it wouldn't hurt if the code takes the right branch without jump in the majority of the cases. &lt;/p&gt;

&lt;p&gt;Another possible profile-guided optimization would be to identify the order of loading classes and separate them by that - the early loaded in one jar, the latter loaded in another and the barely used ones in third - it can reduce the classloading time (if you put them on the classpath in the right order) and combined with the Java Modules proposal can help one create slimmer applications where you can start the app with the minimal jar and the rest is streamed as you work.&lt;/p&gt;

&lt;h4&gt;Obfuscation&lt;/h4&gt;
&lt;p&gt;The goal of the obfuscation process is making your code more difficult to decompile. Please note that I didn't say "impossible" - although decompiling obfuscated code exposes much less information and usually does not produce runnable Java code, it is perfectly possible for a motivated person to reverse-engineer obfuscated bytecode - it's just going to take longer. In the end it boils to the cost/benefit perception - if somebody thinks it will be cheaper to hack your product, they will - the obfuscation raises the bar to do it, but if you really care about the bottom-line, you might be better off with &lt;s&gt;open&lt;/s&gt;available source and certain legal agreement (NDA, NCA and in some cases even patents might make sense).&lt;/p&gt;

&lt;h5&gt;Class/Method Renaming&lt;/h5&gt;
&lt;p&gt;The goal of the renaming is to make the classes and methods illegible. Usually this is achieved by changing the names to short identifiers (usualy one or two letters). This also reduces the size on disk and the perm-size by reducing the constant pool. If you specify the option to use lower and upper case letters for different class names, you can make the jar impoissible to extract on case-insensitive file systems as half of the classes would overwrite the other half. Another trick is to specify a dictionary of recommended identifiers, which contains all Java keywords. Since the keywords have meaning only in Java, but not in the bytecodes, a naive decompiler might produce funny uncompilable code (imagine &lt;code&gt;for (int for=if; for&amp;lt;while.lenght; for++) else.add(while[for]);&lt;/code&gt;) - of course &lt;a href="http://www.kpdus.com/jad.html" title="The Fast JAva Decompiler"&gt;JAD&lt;/a&gt; handles this by recognizing and renaming the members, so I really consider this a wasted effort.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;note:&lt;/b&gt; again, you will want to preserve the public interfaces, which is quite similar to the specification for the shrinking phase). &lt;/p&gt;

&lt;h5&gt;Flow Mangling&lt;/h5&gt;
&lt;p&gt;Since the decompilers recognize certain byte code patternsas result from a java statement, the obfuscator can reorder these, yielding semantically equivalent bytecode, which is impossible to map 1:1 to Java (JAD handles these with labels and goto). Also, I've seen obfuscated code using loops, breaks and exceptions to simulate IFs, but I'm not sure which obfuscator does these. (Zelix?)&lt;/p&gt;

&lt;h5&gt;String Encryption&lt;/h5&gt;
&lt;p&gt;I think it was &lt;a href="http://www.zelix.com/klassmaster/features.html" title="ZKM Features"&gt;Zelix KlassMaster&lt;/a&gt; that could substitute each string with encrypted version and insert code to decrypt them at runtime. This is very efficient measure as the strings usually give away a lot about what the code is doing (especially logging statements.)&lt;/p&gt;

&lt;h4&gt;Stack Map Generation (Preverification)&lt;/h4&gt;
&lt;p&gt;J2ME JVMs feature simplified class-loading mechanism which requires each method to declare how much stack space is it going to use in the worst case. The J2SE JVMs are smart enough to do this at runtime, stil this slows down the classloading. ProGuard can generate the correct StackMap attributes for the obfuscated code, so for slightly larger disk footprint you would get faster loading. &lt;/p&gt;

&lt;p&gt;So that's about it. I figure that here is the place to throw in a couple of URLs:
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="http://proguard.sourceforge.net/" title="ProGuard Project Site (at Sourceforge)"&gt;ProGuard&lt;/a&gt;&lt;/b&gt; - free and quite decent. Nothing fancy.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="http://www.yworks.com/en/products_yguard_about.htm"&gt;yGuard&lt;/a&gt;&lt;/b&gt; - some people like its XML syntax. I don't think it's much different than ProGuard. The company producing it requires that you use it if you use their core product. It makes sense for them to want to take care about the actual protection of their IP.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JoGa&lt;/b&gt; was another tool that I used for J2ME, focused on bytecode optimization and had a nice GUI with many tweaks and gadgets. Unfortunately, it looks like the site is down.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href="http://www.zelix.com/klassmaster/features.html" title="ZKM Features"&gt;Zelix KlassMaster&lt;/a&gt;&lt;/b&gt; - comercial - implements string encryption and advanced flow obfuscation (this is what JetBrains use for IntelliJ IDEA).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So all in all it took me about 6 hours to get everything obfuscated and in one jar. I had to disable the optimization and shrinking phase because I couldn't hunt down all the SWT JNI dependencies, still the resulting size was 2/3 of the original and the app was starting up noticeably faster.&lt;/p&gt;

&lt;p&gt;The final touch was to wrap the single jar in &lt;a href="http://launch4j.sourceforge.net/" title="Launch4J Home"&gt;Launch4J&lt;/a&gt; binary launcher, so the user would need resource editor to even get to the jar. Launch4J provides some small but nice features like JRE detection (from registry), JRE version checking, custom icon and Windows metadata.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-8715568722703615612?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/BnWW_0LealU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/8715568722703615612/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=8715568722703615612" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8715568722703615612?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8715568722703615612?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/BnWW_0LealU/obfuscating-gui.html" title="Obfuscating the GUI" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2007/12/obfuscating-gui.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYDR38_eyp7ImA9WxdREE8.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-8927885665477823201</id><published>2007-11-03T20:38:00.000+09:00</published><updated>2008-05-29T10:56:16.143+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-29T10:56:16.143+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Ant" /><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Build" /><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><category scheme="http://www.blogger.com/atom/ns#" term="Make" /><title>Build Tools</title><content type="html">&lt;p&gt;I had started writhng a post explaining how the Maven repository, artifact resolution and build lifecycle work, but I figured that
    I'm repeating the &lt;a href="http://www.sonatype.com/book/" id="qlav" title="Maven: The Definitive Guide"&gt;Maven Book&lt;/a&gt; and the &lt;a href="http://cvs.peopleware.be/training/maven/maven2/index.html" id="sd2r" title="Working with Maven2"&gt;Bullet-point Guide&lt;/a&gt;.
    Instead, think it would be more interesting to go down the memory lane and talk about how my build tools have changed through the years.&lt;/p&gt;

&lt;h4&gt;Why Build?&lt;/h4&gt;
&lt;p&gt;I stated programming on Apple][ using Basic, and at that time I stored my programs as source on a 5¼" diskette. Every
    time I wanted to run a program, I typed 'load MyProg &amp;lt;ENTER&amp;gt; run&amp;lt;ENTER&amp;gt;'. No compilation, no packaging,
    no complicated dependencies. It all Just Worked™.&lt;/p&gt;

&lt;h4&gt;Integrated Development Environments&lt;/h4&gt;
&lt;p&gt;Then, new machines came about, with bigger keyboards, bigger hard drives, bigger screens and (oh, horror) no built in
    Basic. At that time somebody told me that &lt;a title="Real Programmers don't use Pascal" href="http://www.pbm.com/%7Elindahl/real.programmers.html"&gt;the Real Programmers don't use Pascal&lt;/a&gt;
    - somehow I failed to get the tongue-in-cheekness - it all made a lot of sense to me. Finally, after I couldn't
    find a Fortran compiler for IBM XT (actually &lt;a title="Pravetz16" href="http://en.wikipedia.org/wiki/Pravetz_series_8"&gt;Pravetz16&lt;/a&gt;),
    determined to become a Real Programmer I settled for QuickBasic. QB was very powerful - it had functions (which I thought
    were something like GOSUB but with a name) and you didn't have to put
    line numbers (still I didn't trust it, so I usually typed them in just in case). It also had a number of new
    commands, and almost none of the Apple II ones. Some time around 1992, I can't remember what happened, 
    but I abandoned QBasic and joined the quiche-eating side of the power - I switched to Turbo Pascal 4.0. &lt;/p&gt;
&lt;p&gt;Turbo Pascal was a big jump for me - it hade interesting new abstractions like units and scoping (the latter one being
    useless feature that only stops you from seeing your own variables), but one notable feature was that one
    program could be spread over multiple files. At that time text UIs were all the rage, so I had my own library for
    drawing animated windows, menus, etc. The whole thing was one file and I wrote wrote a couple of toy-apps, 
    each of them having its own copy of the Library (notice the capital letter here). Every day I wanted to show my mom and dad to 
    "what the computer can do" and I tried very hard to convince then start using my expense-tracking app (needless to say,
    my attempts were futile... My sister had a much better success at trying to get them to eat from her first cake).&lt;/p&gt;
&lt;p&gt;At that time I didn't realize how much the IDE was doing for me - all I knew is that I press Ctrl+F9 and a
    couple of seconds later I get an EXE in the output directory. There was no packaging and I couldn't figure for the
    life of me why would anybody want to compile outside of the IDE.&lt;/p&gt;

&lt;h4&gt;Make?&lt;/h4&gt;
&lt;p&gt;As time went by, the IDEs changed (Turbo Pascal 5-7, Turbo/Borland C++ 2-4, Visual C++ 5-6), but my attitude
    stayed the same. Come summer 1999, I was working part-time as a developer in a small company and all of us ~20
    developers were happily building release binaries with Visual Studio. There was a lone guy that tried to propose to
    use an obscure utility called &lt;code&gt;make&lt;/code&gt;. It looked like you have to write yet another program that would do
    what the IDE does, but you needed to use obscure syntax, and call the "compiler" and "linker" directly, specifying
    every command-line parameter, and listing filenames manually - it was a lot more work. The benefit that he tried to
    put forward weren't very convincing either: "you can build from the command line!" - countered by "and why would you
    want to do that?" or "people that don't use Visual Studio can build the project", retorted by "are you crazy?
    &lt;strong&gt;Everybody&lt;/strong&gt; uses Visual Studio." well, that guy was actually using VI... I think he didn't last very long there.&lt;/p&gt;
&lt;p&gt;When I joined my next company I had to use Java. They were not using Visual Studio and in fact they didn't have a standard Java IDE.
    At that company they were building using &lt;code&gt;make&lt;/code&gt;. Recursive &lt;code&gt;make&lt;/code&gt;. Every directory had its own
    &lt;code&gt;makefile&lt;/code&gt;, most of them containing only boilerplate code, including a toplevel template (quite annoying
    when you have to debug a build issue and count the number of '../' in the include), and to make it more interesting, some of the makefiles
    were not using the template, having their own goals, invoking OS commands, etc... Overall it worked (except when it
    didn't.) Most of the problems we had were related to incorrectly set environment variables and missing external programs.
    It was difficult to reason about the build process as the build files was spread all over the directory tree.
    In the end, one of the developers rewrote the whole build using Ant.&lt;/p&gt;

&lt;h4&gt;Ant&lt;/h4&gt;
&lt;p&gt;Ant worked. Much better than make. Looking back, I can say that this was because:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Ant is much less dependent on environment variables. In that case there was an &lt;code&gt;build.properties&lt;/code&gt; file
        that everybody had to customize once and that was it.&lt;/li&gt;
    &lt;li&gt;Ant does not use OS commands. Everything an Ant build needs is either provided by the distribution or shipped
        with the source files (you don't have the habbit of plopping random jars in your &lt;tt&gt;$ANT_HONE/lib&lt;/tt&gt;
        directory, do you?)&lt;/li&gt;
    &lt;li&gt;Ant's syntax is much more restricted than &lt;tt&gt;make&lt;/tt&gt;. A syntactically invalid Ant script wouldn't run; a syntactically
        invalid makefile can erase your harddrive.&lt;/li&gt;
    &lt;li&gt;Ant was designed for Java, handling many common tasks right out of the box.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many detractors say that Ant is too verbose and they are right. I personally don't have big problems with this as my
    editor usually autocompletes the tasknames and the attributes for me and warns me when I make a mistake. The modern
    Ant (1.6+) also allows you to factor your build fairly well by using &lt;code&gt;includes&lt;/code&gt;, &lt;code&gt;presetdefs&lt;/code&gt;
    and &lt;code&gt;macrodefs&lt;/code&gt;. Actually Ant's biggest problem is that it is Turing complete. The &lt;code&gt;target&lt;/code&gt;'s
    dependency resolution, combined with the &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;unless&lt;/code&gt; attributes is often abused to
    simulate control-flow statements, which pollutes the target namespace and complicates the dependencies. Too often
    the targets don't have good names because their only purpose is to hold a piece of code reused in some other targets
    (actually this use-case is served better by &lt;code&gt;macrodefs&lt;/code&gt;, but many people still use targets).
    The assign-once-ignore-following semantics of the Ant properties is good for implementing overriding, but when we use
    Ant as a language given the lack of scoping, the namespace gets polluted really quickly and you might end up having strange
    interactions between unrelated targets.&lt;/p&gt;
&lt;p&gt;As experiment I've tried useing Ant tasks from Jython. It works great - you have real variables, real control
    structures, the code is much more concise and you can use any other Java library you want. One downside is that for
    straight-forward builds (compile bunch of files, package them in a jar and zip them with some scripts) Ant is
    arguably easier to read, as there are fewer things one needs to be aware about. But the real dealbreaker is that you
    don't get any tool support - no IDE autocompletion, no syntax checking on-the-fly, no integrated build runners,
    nothing!&lt;/p&gt;
&lt;p&gt;One thing I didn't mention is that Ant is very easy to customize - extend a class, provide some getters and setters,
    write your logic in the &lt;code&gt;execute&lt;/code&gt; method and you are done! To use your custom task, you need to ship your
    jar with the build script and add an one-line definition to your build. If you have more tasks you can package them
    together with a simple descriptor and import them all at once using a namespace (this is called antlib).&lt;/p&gt;

&lt;h4&gt;Make!&lt;/h4&gt;
&lt;p&gt;Few years later, I was  porting Java games for mobile phones from Doja to EzAppli and VSCL. I had common scripts
    for each of the platforms and every time I started a new port, I just had to tweak a template-script containing an
    import statement and a couple of properties. If I needed to port the same game for another platform, all I needed
    to change was the include statement. That was nice.&lt;/p&gt;
&lt;p&gt;One day I got a port for a new system - it was called BREW and the API was in C. Initially I considered writing
    some Ant tasks to handle the native toolchain, but after some consideration, I read a couple of articles (see
    &lt;a href="http://miller.emu.id.au/pmiller/books/rmch/" title="Recursive Make Considered Harmful"&gt;Recursive Make Considered Harmful&lt;/a&gt;)
    and decided to give &lt;code&gt;make&lt;/code&gt; another try.&lt;/p&gt;
&lt;p&gt;One of the useful &lt;code&gt;make&lt;/code&gt; features is the dependency inference rules. This way, you can say that
    a *.c file generates *.o file. Then you just specify which *.o files your binary is comprised of and &lt;tt&gt;make&lt;/tt&gt; will
    automatically guess your source files. If the source file is not newer then the object file, make is smart enough
    not to recompile it. The Java compiler does this by default (when using wildcards).&lt;/p&gt;
&lt;p&gt;Make does not care about what commands you put in its goal definitions. That's why, out of the box it doesn't deal
    with transitive dependencies. To deal with this, most C compilers can generate a dependency listing in make format,
    which you can include in your makefile and regenerate when the dependency graph changes. In Java, the same thing can
    be achieved by using Ant's &lt;code&gt;dependset&lt;/code&gt; task and some IDEs (like IntelliJ IDEA) can track all your
    dependencies (including transitives) as you type and recompile all impacted files.&lt;/p&gt;
&lt;p&gt;In the end, I had a pretty well factored build system using make, requiring minimum configuration (much like the Java
    one), allowing for cross-compilation targeting x86 and ARM architectures, using different toolchains and everything.
    If I compare the Ant/makefile approach with the IDE, I'd say that the build scripts take more time to pay off. If you
    work on one project and your build is not complex and you don't need repeatable builds (because you work alone and
    your customer doesn't care), then the IDE might be a better proposition.
&lt;/p&gt;

&lt;h4&gt;Shells, Perls and Pasta&lt;/h4&gt;
&lt;p&gt;Once again, I started on a new job and it turned out that in my department nobody uses a build tool. Everybody was
    usually building in their IDEs and copying straight to production or using ad-hock shell scripts or perl to build
    from the sources directly on the production box (the latter was rationalized as "this way we can fix bugs faster").&lt;/p&gt;
&lt;p&gt;In the end, all scripts were simple compile+jar, sometimes even skipping the 'jar' step. They did get the job done
    and the business was happy. There were a number of things missing, like reproducible builds, reliable roll-back,
    etc. but it is a matter of tradeoff whether one wants to spend the necessarry time studying and implementing a build
    system or spend the same time implementing new functionality or fixing application bugs. There's nothing wrong with
    either way.&lt;/p&gt;

&lt;h4&gt;Maven&lt;/h4&gt;
&lt;p&gt;After spending some time working on an application with Ant Build from Hell, I was dreaming of a brave new world,
    where each application will be layed out in modules and packages with controlled dependencies, each module's build
    script would be simple and clean and one can focus on the actual application functionality.&lt;/p&gt;
&lt;p&gt;Enter Maven (actually Maven2). After being burned by Maven1, I still thought that the ideas were good, and it was the
    actual implementation that sucked so bad. Maven2 is a new start, and a new chance to reinvent the wheel. The project
    developers have taken the working concepts from Maven1, pruned the ones that turned out to be a bad idea, and
    reimplemented everything from scratch. It's still not clear why did they decide to use their own DI container and
    classloader management (instead of say Spring and OSGI), but it works.&lt;/p&gt;
&lt;p&gt;Maven has the chance to hit the sweet spot between a build-scripting tool and an IDE-style pure declarative build.
    In the core of Maven is the &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html" title="Introduction to the Build Lifecycle"&gt;build&lt;/a&gt;
    &lt;a href="http://cvs.peopleware.be/training/maven/maven2/buildLifecyclePhases.html" title="Build Lifecycle Phases"&gt;lifecycle&lt;/a&gt;,
    which is just an abstract sequence of steps. Then, in your POM you define (or inherit) a &lt;tt&gt;packaging&lt;/tt&gt;.
    The packaging defines a set of default &lt;tt&gt;plugins&lt;/tt&gt; and &lt;tt&gt;executions&lt;/tt&gt;. You can think about the plugins as
    a bunch of Ant-tasks (or '&lt;tt&gt;goals&lt;/tt&gt;' in mavenspeak), which are versioned together. The executions define
    parameters for the actual goal and are bound to a lifecycle phase.&lt;/p&gt;
&lt;p&gt;Most of the parameters in a goal are optional, using sensible defaults. The defaults are either sensible constants or
    references to different parts of the POM. E.g. the &lt;a href="http://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html"&gt;compiler:compile&lt;/a&gt;
    goal would get the source directory from the POM reference ${pom.build.sourceDirectory} and use the constant "false"
    for it's &lt;tt&gt;fork&lt;/tt&gt; parameter. All the POMs (or their parent POMs) in Maven2 inherit from a
    &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Super_POM" title="Super POM Definition"&gt;common "Super-POM"&lt;/a&gt;.
    The common POM specifies many defaults (i.e. directory layout), so you don't need
    to, if you keep to the Maven Conventions. An important part is complying as much as possible to the standard
    &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html"&gt;Maven Directory Layout&lt;/a&gt;
    - it makes your life much easier.&lt;/p&gt;
&lt;p&gt;There are some areas in Maven that are still rough. The release plugin is still quite limited (although there is work
    under way to implement features like release staging and binary promotion). There are a couple of annoying bugs in
    the assembly plugin, which are fixed on the head, but not released for more than an year. Some issues (like the
    explicit support for aggregator plugins) are being postponed for Maven 2.1 (which will probably ship around Q2-3 of
    2008). But overall, I think it is an improvement.&lt;/p&gt;

&lt;h4&gt;Conclusions&lt;/h4&gt;
&lt;p&gt;So, I'm planning to use Maven2 for the time being and perhaps write a plugin or two for some tasks which it does not
    handle well (right now I'm still cheating, using the &lt;a href="http://maven.apache.org/plugins/maven-antrun-plugin/"&gt;antrun&lt;/a&gt; plugin).
    I'm still (ab)using Ant for common scripting tasks like restarting a remote server through SSH connection, deleting files on remote
    machine, setting up a database table or deploying configuration files in remote environment. All these things do not
    fit in the build lifecycle and wouldn't benefit as much from writing Maven plugins for them. The main benefit in this case is that I get a simple, completely cross-platform scripting language, providing many common commands lacking from the normal Unix environment (btw did I mention that &lt;tt&gt;expect&lt;/tt&gt; sucks?) 
&lt;/p&gt;
&lt;p&gt;And finally, here are some more tools that I'm planning to check out:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;&lt;b&gt;&lt;a href="http://www.scons.org/"&gt;scons&lt;/a&gt;&lt;/b&gt; and &lt;b&gt;&lt;a href="http://rake.rubyforge.org/"&gt;rake&lt;/a&gt;&lt;/b&gt; -
        build tools using Python amd Ruby respectively, each of them using the underlying platform and some clever code
        for doing build stuff &lt;/li&gt;
    &lt;li&gt;&lt;b&gt;&lt;a href="http://buildr.rubyforge.org/"&gt;buildr&lt;/a&gt;&lt;/b&gt; - another Ruby tool that builds on rake, allows you to
        use Ant tasks, designed as a drop-in replacement for Maven2 (hopefully allowing for mixed environment).&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-8927885665477823201?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/UdMrNeMgI9I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/8927885665477823201/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=8927885665477823201" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8927885665477823201?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/8927885665477823201?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/UdMrNeMgI9I/building-tools.html" title="Build Tools" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2007/11/building-tools.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcNQH05eCp7ImA9WxdREE8.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-652362934810105334</id><published>2007-10-27T23:57:00.000+09:00</published><updated>2008-05-29T10:54:51.320+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-29T10:54:51.320+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Build" /><category scheme="http://www.blogger.com/atom/ns#" term="Maven" /><title>On Maven2</title><content type="html">&lt;p&gt;Maven is a tool with an &lt;a href="http://maven.apache.org/background/history-of-maven.html" title="History of Maven"&gt;interesting history&lt;/a&gt; dating back to 2001. In its first years it got deservedly bad reputation for being unstable, poorly documented and more or less experimental piece of work. The release of version 2.0 in 2005 fixed many of the early quirks and set right many of the short-sighted design decisions. After having some bad experience with Maven 1, I was weary to get on the M2 bandwagon, but when I moved to a new job in 2006 I decided to give it a go. So far there have been ups and downs, but I'm fairly happy with it. I still haven't abandoned all my Ant and shell scripts, but I find that I'm using Maven as a primary building tool for most of my projects.&lt;/p&gt;

&lt;p&gt;The core proposition of Maven is that one should be able to declare what they are building in some sort of manifest file and the build tool should be able to figure how to build it. The manifest should contain only the information that is specific for the project and all the build procedures should be implemented as plugins. Each build should be related to exactly one artifact of certain type. The artifacts are stored in repositories (more about this later.)&lt;/p&gt;

&lt;p&gt;In Maven parlance, the manifest file is called POM (that stands for &lt;a href="http://www.javaworld.com/javaworld/jw-05-2006/jw-0529-maven.html" title="Maven POM Demystified"&gt;Project Object Model&lt;/a&gt;). If a project adheres to a predefined filesystem layout, the actual XML one has to write can be very small. Here is a minimal example:
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;project schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd "&gt;
  &amp;lt;modelversion&gt;4.0.0&amp;lt;/modelversion&gt;
  &amp;lt;groupid&gt;com.acme.foo&amp;lt;/groupid&gt;
  &amp;lt;artifactid&gt;foobar&amp;lt;/artifactid&gt;
  &amp;lt;version&gt;3.14-alpha&amp;lt;/version&gt;
&amp;lt;/project&gt;&lt;/code&gt;&lt;/pre&gt;
This configuration is enough to enable Maven to build, package, install, deploy and clean your project. It would even generate the repots site if you run &lt;tt&gt;mvn site&lt;/tt&gt;. That's the way I usually start my projects. Later, you can tack more elements as needed.&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The top-level element defines the default schema for the POM. The schema has a version which has to match the &lt;tt&gt;modelversion&lt;/tt&gt; element below. While the schema is not strictly necessary, it makes the POM editing much easier if you are using XML aware editor. It is well constrained and there are few extensibility points, so the autocompletion works very well. It also features annotations for each element, which means that if you use IntelliJ IDEA you can just press Ctrl+Q on any element and get instant documentation. The schema design is a bit annoying, but it is very regular and easy to understand:
&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;No attributes - everything is an element.&lt;/li&gt;
&lt;li&gt;No mini-languages - everything is an element and any custom textual notations are avoided as much as possible (though in many places they use URLs). This allows for simple parsing and processing.&lt;/li&gt;
&lt;li&gt;If an element can be repeated more than once it is enclosed in container element that can appear only once. This ensures that all elements of one type are textually next to each other. Each container can contain only elements of the same type.&lt;/li&gt;
&lt;/ul&gt;
Overall, the POM bears a resemblance to an IDE configuration file and they serve the same functionality. Both Maven and IDEs runs a predefined build process, parameterized by the information in the project file (or POM). One major difference is that Maven is designed to be ran from the command line and also encapsulate all environment-specific factors into the POM and the settings.xml files. You can use Maven to generate project files for IDEA, Eclipse and Netbeans based on the information in the POM.&lt;/p&gt;

&lt;p&gt;The machine-specific and user-specific configuration is specified in the settings.xml files. There are two of them, the machine-specific settings are stored under the &lt;tt&gt;$M2_HOME/conf&lt;/tt&gt; directory and apply to all the users on the machine. Usually the contents is standardized within the team (internal repositories, proxy settings, etc.) In our company, this file is posted on the wiki where everybody can download it. Alternatively we could have built our internal Maven distribution with the file pre-included. The second settings.xml file resides under &lt;tt&gt;~/.m2&lt;/tt&gt; and contains user-specific settings overriding the machine-specific. One can use the user-specific settings to keep login credentials, private keys, etc. On Unix machine, this file should be readable only by the user.&lt;/p&gt;

&lt;p&gt;Though the POM is very flexible and can be tweaked to accommodate a number of different scenarios, it is very recommended to refrain from overriding the defaults and use the Maven conventions as much as possible. This way, new developers on the project can get up to speed faster and (important) it's much less likely that you get bitten by untested plugin 'feature'.&lt;/p&gt;

&lt;p&gt;One of the thing that new users tend to dislike most is the &lt;a href="http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html" title="Introduction to Standard Directory Layout"&gt;standard directory layout&lt;/a&gt;. In brief, you have &lt;tt&gt;pom.xml&lt;/tt&gt; in the root, and your files go under a directory called &lt;tt&gt;src&lt;/tt&gt;. By default, all files (artifacts) generated during the build go under a directory called &lt;tt&gt;target&lt;/tt&gt; which helps for an easy cleanup. Note that there is no 'lib' as all the libraries reside in the local repository (more about this in another post.)&lt;/p&gt;
&lt;p&gt;So far so good, but then under source we usually have &lt;tt&gt;main&lt;/tt&gt; and possibly &lt;tt&gt;test&lt;/tt&gt;, &lt;tt&gt;integration&lt;/tt&gt; and &lt;tt&gt;site&lt;/tt&gt; directoryes and then under them we have &lt;tt&gt;java&lt;/tt&gt;, &lt;tt&gt;resources&lt;/tt&gt; and only there we put the actual source files. This means that we have at least 3 directory levels used for classification above our sources and if you jump between them using Windows Explorer or bash it makes for a lot of clicking/typing. On the other hand, this is the price one pays for the Maven's magic - each directory level means something to the plugins that build your project. E.g. the unit test goal knows that it should runt he tests under &lt;tt&gt;test&lt;/tt&gt; and not the ones under &lt;tt&gt;integration&lt;/tt&gt;. All the files in the &lt;tt&gt;resources&lt;/tt&gt; directory are copied in the final JAR, while the ones under &lt;tt&gt;classes&lt;/tt&gt; are not and so on and so forth.&lt;/p&gt;

&lt;p&gt;This post became rather long, so I'll finish it here. Next week I'm going to cover Maven's dependencies management and repository organization. Again I'll try to talk more about "why's" and less about the "what's" that are already covered pretty well in the following tutorials:
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://cvs.peopleware.be/training/maven/maven2/" title="Working with Maven2"&gt;Maven2 by the bullet points&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sonatype.com/book/" title="Maven: the Definitive Guide"&gt;The Maven Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://maven.apache.org/guides/" title="Maven2 Guides"&gt;Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.codehaus.org/display/MAVENUSER/" title="Maven User"&gt;User Submitted Documentation and Feature Discussions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://maven.apache.org/plugins/" title="Maven Plugins"&gt;Official Plugins&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mojo.codehaus.org/" title="Mojo Project"&gt;Mojo - Semi-official Plugins&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-652362934810105334?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/ZAZw331G6Rw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/652362934810105334/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=652362934810105334" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/652362934810105334?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/652362934810105334?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/ZAZw331G6Rw/on-maven2.html" title="On Maven2" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2007/10/on-maven2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUFQ3o5eyp7ImA9WxdREE8.&quot;"><id>tag:blogger.com,1999:blog-3914252298360181750.post-6347698525180533</id><published>2007-10-26T00:44:00.000+09:00</published><updated>2008-05-29T10:56:52.423+09:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-29T10:56:52.423+09:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="NinJava" /><category scheme="http://www.blogger.com/atom/ns#" term="Social" /><title>Ninjava Presentation</title><content type="html">First Post! 

&lt;p&gt;A month ago I volunteered to give a presentation at &lt;a href="http://ninjava.jp/"&gt;Ninjava&lt;/a&gt; (a Java User Group in Tokyo). At first it looked easy - the topic was "Java Project Lifecycle" and that's something I've been doing for the last two years, so I should have a lot to say, right? Well, this actually turned to be my first problem - after putting my thoughts on paper, I realized that there are too many things and there is no way that I can fit the whole talk in one hour.&lt;/p&gt;

&lt;p&gt;Since everything looked relevant to the main topic and everything looked important, I figured that I needed to tighten the scope. I thought that I can focus on a minimal process and how we can use tools to automate the chores like building, releasing and configuration management. In the end, I put together &lt;a href="http://docs.google.com/Doc?id=dhhhfhqm_12gkn96k"&gt;this plan&lt;/a&gt; to build a small application, starting with a domain layer (actually that might be too big of a word for a class multiplying two BigDecimals), test, add command-line interface, release, add simple GUI, release, show how the whole thing can be split into 3 modules and packaged in different configs - GUI only, CLI only or both. Finally I was going to add a feature on the head and backport it to a stable branch. I planned to use the following tools:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a style="font-weight: bold;" href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; - version control system similar to CVS.
&lt;/li&gt;&lt;li&gt;&lt;a href="http://maven.apache.org/users/index.html"&gt;&lt;span style="font-weight: bold;"&gt;Maven2&lt;/span&gt;&lt;/a&gt; - project automation tool from Apache. The tool is build around the POM (&lt;a href="http://maven.apache.org/pom.html"&gt;Project Object Model&lt;/a&gt;). The POM is an abstract model, but in practice, it is usually an XML document which describes information about the project. The POM &lt;strong&gt;does not&lt;/strong&gt; describe what actions can be performed on a project.
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.jfrog.org/sites/artifactory/latest/"&gt;&lt;span style="font-weight: bold;"&gt;Artifactory&lt;/span&gt;&lt;/a&gt; - repository management server for Maven2. Usually it's configured as caching proxy in front of the internet repository, sindicating its contents with the internal repo. The deployment can be done either through WebDAV, HTTP PUT or a convenient web UI for manual deployment.
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.jetbrains.com/teamcity/"&gt;&lt;span style="font-weight: bold;"&gt;TeamCity&lt;/span&gt;&lt;/a&gt; (check out the &lt;a href="http://www.jetbrains.net/confluence/display/TW/TeamCity+EAP"&gt;EAP for the 3.0 release&lt;/a&gt;)- a continuous integration (CI) server from JetBrains. Apart from the usual watch-and-build functionality, it also features some interesting stuff like conditional commit (send the changes to the server which will commit them only if the build passes), duplicates analyzer and static analysis tool working on AST level, plugins for many different IDEs, etc.
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.atlassian.com/software/jira/"&gt;&lt;span style="font-weight: bold;"&gt;Jira&lt;/span&gt;&lt;/a&gt; - an issue tracker. Actually I should clarify - the best issue tracker I've used (especially with the &lt;a href="http://www.greenpeppersoftware.com/en/products/GreenHopper/"&gt;Green Hopper&lt;/a&gt; plugin and the &lt;a href="http://almworks.com/jiraclient/overview.html"&gt;JIRA Client&lt;/a&gt; GUI)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.atlassian.com/software/confluence/"&gt;&lt;span style="font-weight: bold;"&gt;Confluence&lt;/span&gt;&lt;/a&gt; - a damn good wiki. In our department it also doubles as reporting tool.
&lt;/li&gt;&lt;li&gt;&lt;a style="font-weight: bold;" href="http://www.atlassian.com/software/fisheye/"&gt;Fisheye&lt;/a&gt;&lt;span style="font-weight: bold;"&gt; + &lt;/span&gt;&lt;a style="font-weight: bold;" href="http://www.atlassian.com/software/crucible/"&gt;Crucible&lt;/a&gt; - a server indexing your version control system, with web interface for browsing changesets, files, revisions, filtering by committer and full text search. Crucible is an add-on to Fisheye, that lets you select a bunch of files and create a code review ticket, adding inline notes. Multiple people can collaborate, posting replies to the notes and proposing changes until the ticket is resolved.
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;The main factor for choosing these tools was that I am currently using them either at work of in the development of the &lt;a href="http://mule.mulesource.org/display/JMX/Home"&gt;Mule JMX Transport&lt;/a&gt; (BTW, all of them have free licenses for open-source). 

The first rehearsal was one evening when I stayed after work and went through all the steps on my workstation - it took me about 40. Perhaps 10 mins I spent looking up documentation on the internet, so I thought it was not too bad. On the presentation day I took a day-off from work, so I can have the time to set up &lt;a href="http://inalcove.blogspot.com/"&gt;Daniela's&lt;/a&gt; laptop as my primary demonstration machine (as I had already installed all the server apps on my poor Kohjinsha) and everything was going fine, until I started the dress rehearsal. After I chased Daniela out of the apartment, I went through the already familiar steps this time talking as I would on the presentation. Oops... it turned out that 15 minutes were gone and I was still at the very beginning (and I didn't even manage in detail explain what I was doing). Attempt #2 - this time I consciously tried to only say &lt;span style="font-style: italic;"&gt;what &lt;/span&gt;I am &lt;span style="font-style: italic;"&gt;doing &lt;/span&gt;and not what I am &lt;span style="font-style: italic;"&gt;achieving &lt;/span&gt;or &lt;span style="font-style: italic;"&gt;why &lt;/span&gt;I was doing it. This time the speed was much better, but I found out that I was getting these ~30 sec pauses when switching active files or when searching for symbol, which were ruining the whole flow.&lt;/p&gt;

&lt;p&gt;A quick look in Sysinternals' &lt;a href="http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/ProcessExplorer.mspx"&gt;ProcessExplorer&lt;/a&gt; and &lt;a href="http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/processmonitor.mspx"&gt;ProcessMonitor&lt;/a&gt; showed that the working set of java.exe is 300mb and it's paging like crazy. I stopped some services, closed JiraClient and all the other applications and tried again. This time it was better - it was also clear that this is not going to work. I was at step 13 and I was well past 1 hour in the presentation... The wall-clock was showing 4pm... It was to late to change the scope, so the only thing that seemed to make sense was to just go out, start talking and try to provoke questions, which will help me focus on something.&lt;/p&gt;

&lt;p&gt;I showed up at &lt;a href="http://www.iknow.co.jp/landing/cerego"&gt;Cerego&lt;/a&gt; around 7:30 (after meeting Nikolay at Shibuya station) and while I was thinking &lt;a href="http://www.youtube.com/watch?v=t4bMM73-qHo"&gt;which kind of excuse&lt;/a&gt; should I use, when Peter proposed that I could use one of the machines in the conference room. There was nothing to lose, so I settled to set up an environment in the remaining 30 mins - I downloaded Maven, IDEA, JiraClient, JDK, set up environment variables and just in case checked out the JMX Connector. I tried to set up Jira Client against the JIRA instance running on the Kohjinsha, but for some reason it didn't resolve the host name, so I decided not to bother. By the time I finished there were about 10-15 people in the room. &lt;/p&gt;

&lt;p&gt;I started talking the usual stuff about how some tools work well in some situations and suck in others (except SourceSafe, which sucks in every situation); how the primary criterion in choosing a is that they should help us get the job done in less time/risk and blah, blah.. (more about this in a latter post) and then I moved on to my current environment and to Maven. Then Curt had a question about the POM, then another and then just one more... well, I guess I have to thank him for this. Overall, we talked a lot about Maven, went quickly through TeamCity, just mentioned Crucible and didn't even touch most of the other stuff.&lt;/p&gt;

&lt;p&gt;Now I realize that even my cut-down scope was huge and it was impossible to cover everything in one hour with enough detail. The other fundamental problem was that I started the presentaion without having "something to sell". That's why the whole talk was lacking direction, so only when I started "selling" Maven it started taking shape. It would have been better if I had picked Maven from the very beginning, so I could prepare more examples and not waste time with general stuff. In the end, people said they liked it and may be some really did.&lt;/p&gt;

&lt;p&gt;Yesterday it came too me that a blog would probably be a much better place for &lt;a href="http://docs.google.com/Doc?id=dhhhfhqm_13qncpw9"&gt;all the ramblings&lt;/a&gt; I wanted to share, so here we are. This is the first post I'll try to publish at least one post weekly (hopefully this time I won't lose interest after the first few weeks)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3914252298360181750-6347698525180533?l=foobarbazqux.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DimitarsBlog/~4/OHjyhrYVuiw" height="1" width="1"/&gt;</content><link rel="related" href="http://ninjava.jp/" title="Ninjava Presentation" /><link rel="replies" type="application/atom+xml" href="http://foobarbazqux.blogspot.com/feeds/6347698525180533/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=3914252298360181750&amp;postID=6347698525180533" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6347698525180533?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3914252298360181750/posts/default/6347698525180533?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DimitarsBlog/~3/OHjyhrYVuiw/first-post-ninjava-presentation.html" title="Ninjava Presentation" /><author><name>Dimitar</name><uri>http://www.blogger.com/profile/12617849889258468076</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://userserve-ak.last.fm/serve/160/1163368.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://foobarbazqux.blogspot.com/2007/10/first-post-ninjava-presentation.html</feedburner:origLink></entry></feed>

