<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4869268408030448256</id><updated>2012-01-04T10:26:29.371+01:00</updated><category term='linux'/><category term='hibernate'/><category term='java'/><category term='opinion'/><category term='python'/><category term='web'/><category term='REST'/><category term='spring'/><category term='WebSphere MQ'/><category term='design'/><category term='JMS'/><category term='testing'/><category term='ubuntu'/><category term='architecture'/><category term='web services'/><category term='general'/><category term='humor'/><title type='text'>Erwin Vervaet</title><subtitle type='html'>Programming in practice</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>34</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-8318925505016991485</id><published>2012-01-04T10:26:00.000+01:00</published><updated>2012-01-04T10:26:29.378+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Spring bean definition profiles and web.xml</title><content type='html'>&lt;a href="http://blog.springsource.org/2011/12/13/spring-framework-3-1-goes-ga/"&gt;Spring 3.1&lt;/a&gt; was released a few weeks ago. One of the interesting new features is the first-class support for &lt;a href="http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/"&gt;bean definition profiles&lt;/a&gt;: you can define beans as part of a profile and than activate that profile if required. Bean definitions that are part of a profile that has not been activated are simply skipped.&lt;br /&gt;&lt;br /&gt;Last week, I spent a few days upgrading our application to Spring 3.1 and updating it to make use of bean definition profiles. As most other sizable Spring based apps, we had devised our own &lt;i&gt;configuration switching system&lt;/i&gt; based on a combination of Maven resource filtering and XML &amp;lt;import/&amp;gt; elements containing ${placeholders}. This works well enough but it would obviously be better to directly use the bean definition profile feature of Spring 3.1, if only because it's better documented.&lt;br /&gt;&lt;br /&gt;By default, the list of active bean definition profiles will be determined by looking at a &lt;tt&gt;spring.profiles.active&lt;/tt&gt; property. Out-of-the-box, a Spring &lt;tt&gt;WebApplicationContext&lt;/tt&gt; will setup a &lt;tt&gt;PropertySources&lt;/tt&gt; list containing the servlet config parameters, servlet context parameters, JNDI properties, system properties and environment variables, in that order. This implies that you can define the &lt;tt&gt;spring.profiles.active&lt;/tt&gt; property in any of those locations, the most obvious one being servlet context parameters in web.xml:&lt;br /&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt; &amp;lt;param-name&amp;gt;spring.profiles.active&amp;lt;/param-name&amp;gt;&lt;br /&gt; &amp;lt;param-value&amp;gt;foo-profile, bar-profile&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;br /&gt;&lt;/pre&gt;We wanted to use Maven profiles to switch between Spring bean definition profiles, so the initial idea was to simply do &lt;a href="http://blogs.webtide.com/sbordet/entry/property_substitution_in_web_xml"&gt;Maven resource filtering on web.xml&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;context-param&amp;gt;&lt;br /&gt; &amp;lt;param-name&amp;gt;spring.profiles.active&amp;lt;/param-name&amp;gt;&lt;br /&gt; &amp;lt;param-value&amp;gt;${spring.profiles.active}&amp;lt;/param-value&amp;gt;&lt;br /&gt;&amp;lt;/context-param&amp;gt;&lt;br /&gt;&lt;/pre&gt;It turns out doing resource filtering on web.xml leads you to a world of &lt;a href="http://ev9d9.blogspot.com/2011/04/software-and-mud.html"&gt;pain&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Jetty plugin for Maven assumes the web.xml is static and simply uses the one in the source folder. You can explicitly tell it to use the web.xml from the target folder (using the &amp;lt;webXml&amp;gt; config element), but that results in other problem: by default resource filtering does not process the &lt;tt&gt;src/main/webapp&lt;/tt&gt; directory. Of course you can specify filtering for that directory in your POM, but that again given problems: the Maven war plugin will overwrite the filtered web.xml with a copy from the source folder while packaging the web application. You can fix this by adding a &amp;lt;webResources&amp;gt; definition to your POM for the war plugin. Clearly this situation is far from ideal: it's complex and requires an explicit &lt;tt&gt;mvn package&lt;/tt&gt; just to be able to do &lt;tt&gt;mvn jetty:run&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;Idem ditto for Tomcat.&lt;/li&gt;&lt;li&gt;Eclipse &lt;a href="http://eclipse.org/webtools/"&gt;WTP&lt;/a&gt; also directly uses the web.xml from the sources folder. Maybe there are ways around this, but I have no idea how that would work.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In the end we decided to forgo Maven resource filtering on web.xml and simply use an application specific properties file:&lt;br /&gt;&lt;pre class="brush: plain;"&gt;spring.profiles.active=${spring.profiles.active}&lt;/pre&gt;To get Spring to pick up this additional properties file, we simply add a property source to the application context using an &lt;tt&gt;ApplicationContextInitializer&lt;/tt&gt;:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class MyAppCtxInitializer&lt;br /&gt;  implements ApplicationContextInitializer&amp;lt;ConfigurableApplicationContext&amp;gt; {&lt;br /&gt; public void initialize(ConfigurableApplicationContext applicationContext) {&lt;br /&gt;  try {&lt;br /&gt;   applicationContext.getEnvironment().getPropertySources()&lt;br /&gt;     .addLast(new ResourcePropertySource("classpath:/myapp.properties"));&lt;br /&gt;  } catch (IOException e) {&lt;br /&gt;   // properties file cannot be found: ignore and just continue without these properties&lt;br /&gt;   logger.info("Unable to load fallback properties: " + e.getMessage());&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This approach avoids all the downsides of doing filtering on web.xml (web.xml is now completely static and &lt;tt&gt;mvn package&lt;/tt&gt; no longer required). The only negative aspect is that it introduced an application specific properties file instead of simply relying on standard Spring conventions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-8318925505016991485?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/8318925505016991485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2012/01/spring-bean-definition-profiles-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8318925505016991485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8318925505016991485'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2012/01/spring-bean-definition-profiles-and.html' title='Spring bean definition profiles and web.xml'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-1978710744492799081</id><published>2011-12-25T09:08:00.000+01:00</published><updated>2011-12-25T09:08:05.657+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Good code and good wine</title><content type='html'>I've discussed the "&lt;a href="http://ev9d9.blogspot.com/2010/05/what-is-good-code.html"&gt;What is good code?&lt;/a&gt;" question before. This is such a broad topic that people come up with all kinds of interesting analogies to describe beneficial traits of good code. For instance, Uncle Bob often compares good code to a good book: it's important to have a good story (design/architecture), introduce key characters (concepts) at appropriate times and so on. Another interesting analogy that I've heard is that good code is like a leather glove: over time it becomes more flexible in areas where it needs to be flexible and more rigid in places that need more rigidity, exactly the way good code should behave and evolve (I'm not sure where I first heard this analogy and who I should credit for it).&lt;br /&gt;&lt;br /&gt;Another analogy I (? -- I've never heard it before so I'll be so bold as to take credit myself) came up with recently is comparing good code with good wine. An important characteristic of good wine, maybe even the most important one, is that it tastes good. Likewise, good code needs to function properly and deliver the required functionality. However, as wine aficionados will tell you, tasting good is not the only important trait of a good wine: great wine also has things like an interesting texture, a complex taste palette and so on (not being a wine connaisseur myself, I won't dwell on it). Similarly, having a functional program doesn't imply good source code. Good code needs to exhibit extra characteristics such as flexibility, testability, adhering to the &lt;i&gt;principle of least astonishment&lt;/i&gt; and so on.&lt;br /&gt;&lt;br /&gt;I'd love to hear about more analogies used to describe good code!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-1978710744492799081?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/1978710744492799081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/12/good-code-and-good-wine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/1978710744492799081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/1978710744492799081'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/12/good-code-and-good-wine.html' title='Good code and good wine'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-3764112705488615509</id><published>2011-11-24T21:31:00.004+01:00</published><updated>2011-11-24T21:35:11.357+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>JDK8 and the future of JVM based languages</title><content type='html'>Last week at &lt;a href="http://devoxx.com"&gt;Devoxx&lt;/a&gt; 2011 I attended a number of sessions covering new JVM based programming languages such as &lt;a href="http://confluence.jetbrains.net/display/Kotlin/Welcome"&gt;Kotlin&lt;/a&gt; and &lt;a href="http://ceylon-lang.org/"&gt;Ceylon&lt;/a&gt;. Of course there were also a number of sessions talking about the usual suspects: &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;, &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; and &lt;a href="http://jruby.org/"&gt;JRuby&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There were also a considerable amount of talks covering &lt;a href="http://openjdk.java.net/projects/jdk8/"&gt;JDK8&lt;/a&gt; and how that's shaping up. I got the strong impression that Oracle certainly doesn't want to see JDK8 turn into another multi-year debacle. Progress on JDK8 (vitual extension functions, closures, ...) seems impressive and I got a real sense of direction and focus from those involved.&lt;br /&gt;&lt;br /&gt;I've been following the whole &lt;i&gt;other languages on the JVM&lt;/i&gt; movement that has been going on the last couple of years with interest, but mostly as a by-stander: I'm not a hard-core, opinionated programming language expert like some. However, if I look at the input I gathered at Devoxx I can't help but make a few observations:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Although some of the new JVM languages have interesting ideas and are definately a step up from Java, they didn't trigger that &lt;i&gt;aha-erlebnis&lt;/i&gt; I had when I first started using Java 1.02 after having used C.&lt;/li&gt;&lt;li&gt;The infectuation with dynamic typing seems to be largely over: everybody is back in agreement that strong static typing is the way to go.&lt;/li&gt;&lt;li&gt;Scale &lt;a href="http://blog.joda.org/2011/11/scala-feels-like-ejb-2-and-other.html"&gt;can't get any love&lt;/a&gt; and seems destined to remain an interesting language experiment.&lt;/li&gt;&lt;li&gt;Oracle is on somewhat of a mission to deliver JDK8 sooner rather than later.&lt;/li&gt;&lt;/ul&gt;All of this makes me wonder if &lt;a href="http://www.theserverside.com/feature/The-Future-of-Java-forking-death-or-stasis"&gt;Java's successor&lt;/a&gt; will actually be &lt;a href="http://www.jroller.com/scolebourne/entry/the_next_big_jvm_language1"&gt;Java itself&lt;/a&gt;, but in it's 8th incarnation, and whether or not Java 8 will effectively blow all new contenders out of the water? I'm looking forward to seeing how this unfolds!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-3764112705488615509?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/3764112705488615509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/11/jdk8-and-future-of-jvm-based-languages.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3764112705488615509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3764112705488615509'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/11/jdk8-and-future-of-jvm-based-languages.html' title='JDK8 and the future of JVM based languages'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-9070606600734429933</id><published>2011-10-28T14:43:00.000+02:00</published><updated>2011-10-28T14:43:52.000+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Java puzzler</title><content type='html'>Take a look at the following piece of code:&lt;br /&gt;&lt;pre class="brush: java;"&gt;package test;&lt;br /&gt;&lt;br /&gt;import java.util.Date;&lt;br /&gt;&lt;br /&gt;public class Test {&lt;br /&gt;&lt;br /&gt; public static String format(Date date) {&lt;br /&gt;  return String.valueOf(date);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public static String format(long millis) {&lt;br /&gt;  return format(new Date(millis));&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public static String format(Instant instant) {&lt;br /&gt;  return format(instant == null ? null : instant.getMillis());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public static class Instant {&lt;br /&gt;&lt;br /&gt;  private long millis;&lt;br /&gt;&lt;br /&gt;  public Instant(long millis) {&lt;br /&gt;   this.millis = millis;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public long getMillis() {&lt;br /&gt;   return millis;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;  Instant instant = null;&lt;br /&gt;  format(instant);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Any idea what the output will be? Turns out this throws a &lt;tt&gt;NullPointerException&lt;/tt&gt;:&lt;br /&gt;&lt;pre class="brush: plain;"&gt;Exception in thread "main" java.lang.NullPointerException&lt;br /&gt; at test.Test.format(Test.java:16)&lt;br /&gt; at test.Test.main(Test.java:34)&lt;br /&gt;&lt;/pre&gt;Interesting. Line 16 is clearly fishy: The idea is that if the &lt;tt&gt;instant&lt;/tt&gt; is null, the &lt;tt&gt;format(Date)&lt;/tt&gt; method should be called, while &lt;tt&gt;format(long)&lt;/tt&gt; should be called otherwise. It turns out things are much more contrived at the bytecode level (use &lt;tt&gt;javap -c&lt;/tt&gt;):&lt;br /&gt;&lt;pre class="brush: plain;"&gt;public static java.lang.String format(test.Test$Instant);&lt;br /&gt;  Code:&lt;br /&gt;   0: aload_0&lt;br /&gt;   1: ifnonnull 8&lt;br /&gt;   4: aconst_null&lt;br /&gt;   5: goto 15&lt;br /&gt;   8: aload_0&lt;br /&gt;   9: invokevirtual #35; //Method test/Test$Instant.getMillis:()J&lt;br /&gt;   12: invokestatic #41; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long;&lt;br /&gt;   15: invokevirtual #46; //Method java/lang/Long.longValue:()J&lt;br /&gt;   18: invokestatic #49; //Method format:(J)Ljava/lang/String;&lt;br /&gt;   21: areturn&lt;br /&gt;&lt;/pre&gt;This actually translates to the following Java code, which clearly explains the &lt;tt&gt;NullPointerException&lt;/tt&gt;:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public static String format(Instant instant) {&lt;br /&gt; return format((instant != null ? Long.valueOf(instant.getMillis()) : null).longValue());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Sometimes autoboxing can really rear its ugly head!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-9070606600734429933?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/9070606600734429933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/10/java-puzzler.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/9070606600734429933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/9070606600734429933'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/10/java-puzzler.html' title='Java puzzler'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-6273982257780041928</id><published>2011-09-04T08:17:00.000+02:00</published><updated>2011-09-04T08:17:24.933+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Surprise of the day</title><content type='html'>Well what do you know! It turns out &lt;a href="http://www.microsoft.com/"&gt;Microsoft&lt;/a&gt; was a bigger contributor to Linux kernel version 3.0 than &lt;a href="http://www.canonical.com/"&gt;Canonical&lt;/a&gt;, as &lt;a href="http://lwn.net/Articles/451243/"&gt;LWN reports&lt;/a&gt;. Probably a bit of a fluke but an interesting statistic nonetheless!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-6273982257780041928?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/6273982257780041928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/09/surprise-of-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6273982257780041928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6273982257780041928'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/09/surprise-of-day.html' title='Surprise of the day'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-4993692507793557367</id><published>2011-07-23T11:55:00.002+02:00</published><updated>2011-07-23T12:19:58.885+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humor'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Q_rsqrt</title><content type='html'>I still remember encountering the following piece of code while browsing through the &lt;a href="http://ioquake3.org/"&gt;Quake 3&lt;/a&gt; source code back in 2005:&lt;br /&gt;&lt;pre class="brush: c;"&gt;float Q_rsqrt( float number )&lt;br /&gt;{&lt;br /&gt;  long i;&lt;br /&gt;  float x2, y;&lt;br /&gt;  const float threehalfs = 1.5F;&lt;br /&gt;&lt;br /&gt;  x2 = number * 0.5F;&lt;br /&gt;  y  = number;&lt;br /&gt;  i  = * ( long * ) &amp;y;  // evil floating point bit level hacking&lt;br /&gt;  i  = 0x5f3759df - ( i &gt;&gt; 1 ); // what the fuck?&lt;br /&gt;  y  = * ( float * ) &amp;i;&lt;br /&gt;  y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration&lt;br /&gt;  // y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed&lt;br /&gt;&lt;br /&gt;  #ifndef Q3_VM&lt;br /&gt;  #ifdef __linux__&lt;br /&gt;    assert( !isnan(y) ); // bk010122 - FPE?&lt;br /&gt;  #endif&lt;br /&gt;  #endif&lt;br /&gt;  return y;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;That comment on line 10 pretty much sums it up: WTF!?!?&lt;br /&gt;&lt;br /&gt;I again ran across this piece of code while browsing an amuzing list of the &lt;a href="http://stackoverflow.com/questions/184618/what-is-the-best-comment-in-source-code-you-have-ever-encountered"&gt;&lt;i&gt;best&lt;/i&gt; comments in source code&lt;/a&gt; you've encountered, over on Stackoverflow. &lt;del&gt;It turns out the original author of this illustrious piece of code is still unknown&lt;/del&gt; (it's not John Carmack as you might have assumed). A nice write-up of the &lt;a href="http://www.beyond3d.com/content/articles/8/"&gt;likely history of this hack&lt;/a&gt; can be found on Beyond3D. Interesting reading for sure!&lt;br /&gt;&lt;b&gt;UPDATE&lt;/b&gt;: The &lt;a href="http://www.beyond3d.com/content/articles/15/"&gt;original author is actually known&lt;/a&gt; and it is Greg Walsh. &lt;a href="http://en.wikipedia.org/wiki/Fast_inverse_square_root"&gt;Wikipedia&lt;/a&gt; also has a lot of background.&lt;br /&gt;&lt;br /&gt;Talking about funny comments in code, my personal favorite from the Stackoverflow list must be the following:&lt;br /&gt;&lt;pre class="brush: java;"&gt;stop(); // Hammertime!&lt;/pre&gt;Not so much the comment, but the &lt;a href="http://tasty.soylentsoft.com/images/halt_hammerzeit.jpeg"&gt;german version&lt;/a&gt; really cracked me up!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-4993692507793557367?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/4993692507793557367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/07/qrsqrt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/4993692507793557367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/4993692507793557367'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/07/qrsqrt.html' title='Q_rsqrt'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-168117626294028837</id><published>2011-07-19T19:03:00.000+02:00</published><updated>2011-07-19T19:03:55.274+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Java SE 7</title><content type='html'>It was a long time in the making but all JSRs constituting Java SE 7 have &lt;a href="http://mreinhold.org/blog/java-se-7-fr"&gt;crossed the finish line&lt;/a&gt;! The actual Java SE 7 software release is just around the corner (July 28th). Exciting stuff!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-168117626294028837?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/168117626294028837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/07/java-se-7.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/168117626294028837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/168117626294028837'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/07/java-se-7.html' title='Java SE 7'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-248955032104451611</id><published>2011-07-02T07:43:00.000+02:00</published><updated>2011-07-02T07:43:51.798+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Tech support interference</title><content type='html'>It's a well known fact that developers and tech support people typically don't get along. The developers want freedom to do as they like with their machines, while the tech support guys want to close everything down, mainly for &lt;i&gt;security reasons&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Sometimes this can get quite ridiculous. I recently heard a story about a development team building a web app that required Firefox compatibility, yet they were not allowed to install Firefox on their machines! Another typical example which recently came up at &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=62562"&gt;TSS&lt;/a&gt;, is developers going to great lengths to disable virus scanning software because it makes their IDEs unbearably slow.&lt;br /&gt;&lt;br /&gt;As always, solving this conflict requires a middle-of-the-road solution. I agree that giving developers unlimited privileges on machines that are connected to production networks is an unwanted security violation. Similarly it's unacceptable to bog down a development machine to the point where the developer can no longer properly do his job. One of the better solutions I have encountered is a separate &lt;i&gt;development network&lt;/i&gt;. This development network is an isolated sandbox where the developers reign supreme without putting other parts of the network or organization at risk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-248955032104451611?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/248955032104451611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/07/tech-support-interference.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/248955032104451611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/248955032104451611'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/07/tech-support-interference.html' title='Tech support interference'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-6413882599834995439</id><published>2011-05-27T15:01:00.000+02:00</published><updated>2011-05-27T15:01:42.117+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Slow Java platform evolution</title><content type='html'>It's fascinating to read the &lt;a href="http://openjdk.java.net/projects/jigsaw/doc/draft-java-module-system-requirements-12"&gt;Java Module-System Requirements&lt;/a&gt; document that &lt;a href="http://mreinhold.org/"&gt;Mark Reinhold&lt;/a&gt; has drafted to see just why a platform of Java's size and complexity (both code and community wise) is hard to evolve. The requirements document puts the bar quite high for what a Java Module-System needs to be able to do. You also clearly see the influence of systems like Maven and OSGi, and how the experiences with those systems has impacted the requirements.&lt;br /&gt;&lt;br /&gt;The end result of all of this is that a Java Module-System can't start off small and simple and grow over time. Instead, the designers are faced with a complex and extended set of requirements right from the start. Slow progress is inevitable. Nevertheless, I'm hoping Java SE 8 will include this Module-System because it would bring a lot of interesting new possibilities to the Java platform!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-6413882599834995439?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/6413882599834995439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/05/slow-java-platform-evolution.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6413882599834995439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6413882599834995439'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/05/slow-java-platform-evolution.html' title='Slow Java platform evolution'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-3086210480274220486</id><published>2011-04-22T20:25:00.000+02:00</published><updated>2011-04-22T20:25:17.009+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Properties file troubles</title><content type='html'>I stumbled over a stupid properties file gotcha the other day trying to get a Spring &lt;tt&gt;META-INF/spring.schemas&lt;/tt&gt; file working. Spring uses this file to translate an XML Schema &lt;tt&gt;schemaLocation&lt;/tt&gt; into the name of a classpath resource. This allows Spring to load the schema directly from the classpath instead of downloading it from a remote server which might not be reachable from your deployment environment (e.g. because of firewalls). So for instance, suppose you have the following in your XML:&lt;br /&gt;&lt;pre class="brush: xml;"&gt;&amp;lt;beans xmlns="http://www.springframework.org/schema/beans"&lt;br /&gt;  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;  xmlns:demo="http://www.ervacon.com/schema/demo"&lt;br /&gt;  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.ervacon.com/schema/demo http://www.ervacon.com/schema/demo/demo.xsd"&amp;gt;&lt;br /&gt;&lt;/pre&gt;If you combine this with the following &lt;tt&gt;META-INF/spring.schemas&lt;/tt&gt; file, Spring will load &lt;tt&gt;demo.xsd&lt;/tt&gt; directly from the classpath without even trying to access &lt;tt&gt;http://www.ervacon.com/schema/demo/demo.xsd&lt;/tt&gt;:&lt;br /&gt;&lt;pre class="brush: plain;"&gt;http\://www.ervacon.com/schema/demo/demo.xsd=demo.xsd&lt;br /&gt;&lt;/pre&gt;The key thing to notice in the properties file is the escaping backslash before the colon! This is necessary because a colon is a valid delimiter in a Java properties file:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public static void main(String[] args) throws IOException {&lt;br /&gt; StringReader propsIn = new StringReader("http://my.server.com/foo.xsd=foo.xsd");&lt;br /&gt; &lt;br /&gt; Properties props = new Properties();&lt;br /&gt; props.load(propsIn);&lt;br /&gt;&lt;br /&gt; for (String propName : props.stringPropertyNames()) {&lt;br /&gt;  System.out.println(propName + " --&gt; " + props.getProperty(propName));&lt;br /&gt;  // prints: http --&gt; //my.server.com/foo.xsd=foo.xsd&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Keep in mind that &lt;b&gt;all&lt;/b&gt; colons need to be escaped! So don't forget the colon in front of the port number:&lt;br /&gt;&lt;pre class="brush: plain;"&gt;http\://my.server.com\:8080/foo.xsd=foo.xsd&lt;br /&gt;&lt;/pre&gt;Doh!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-3086210480274220486?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/3086210480274220486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/04/properties-file-troubles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3086210480274220486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3086210480274220486'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/04/properties-file-troubles.html' title='Properties file troubles'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-3602122075604089565</id><published>2011-04-07T13:39:00.001+02:00</published><updated>2011-04-07T13:40:46.711+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>Software and Mud</title><content type='html'>There seems to be a strange relationship between software and mud. Many will be familiar with the &lt;a href="http://www.laputan.org/mud/"&gt;Big Ball of Mud&lt;/a&gt; architectural style and there are &lt;a href="http://thedailywtf.com/"&gt;countless&lt;/a&gt; &lt;a href="http://gojko.net/2011/04/05/how-is-it-even-possible-code-to-be-this-bad/"&gt;examples&lt;/a&gt; of code that resembles mud more than anything else.&lt;br /&gt;&lt;br /&gt;A while ago a colleague of mine used an analogy between a software related problem he was facing and &lt;i&gt;wading through mud&lt;/i&gt; (or as we say in Dutch: "door de moose ploegen"). I'm amazed at how poignant this analogy actually is. Think of a situation where the first thing you notice is that you have mud on the soles of your shoes. As you trot on you quickly end up knee deep in mud. At this point you can either back out and retreat to solid ground, or persevere, in which case you often end up stuck!&lt;br /&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_nh5c0gLCNDk/SBckvsGE3EI/AAAAAAAAAa4/vWGhaE5I0sM/s400/tractor-mud.jpg"/&gt;&lt;br /&gt;Of course you might also make it through, as &lt;a href="http://en.wikipedia.org/wiki/John_carmack"&gt;John Carmack&lt;/a&gt; once noted:&lt;br /&gt;&lt;blockquote&gt;Yes, you can make windows do anything you want to if you have enough time to beat on it, but you can come out of it feeling like you just walked through a sewer. [&lt;a href="http://rmitz.org/carmack.on.operating.systems.html"&gt;.plan&lt;/a&gt;]&lt;/blockquote&gt;&lt;br /&gt;Many software related situations come to mind that closely follow this story:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Merging exercises gone wrong&lt;/li&gt;&lt;li&gt;Refactoring plans that start simple but spiral out of control&lt;/li&gt;&lt;li&gt;Anything to do with character encoding&lt;/li&gt;&lt;li&gt;...&lt;/li&gt;&lt;/ul&gt;Feel free to add this mud analogy to your software vocabulary!&lt;br /&gt;&lt;br /&gt;(As an aside: some people can wade through mud more elegantly than others, as Kate Moss &lt;a href="http://www.dailymail.co.uk/home/you/article-1023675/Festival-dos-donts-survive-festival-season.html"&gt;illustrates&lt;/a&gt;.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-3602122075604089565?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/3602122075604089565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/04/software-and-mud.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3602122075604089565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3602122075604089565'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/04/software-and-mud.html' title='Software and Mud'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nh5c0gLCNDk/SBckvsGE3EI/AAAAAAAAAa4/vWGhaE5I0sM/s72-c/tractor-mud.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-6080374918342034444</id><published>2011-02-05T17:49:00.000+01:00</published><updated>2011-02-05T17:49:04.037+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='hibernate'/><title type='text'>Hibernate hurdles</title><content type='html'>I've been using Hibernate for the better half of 10 years now (since Hibernate 2), and while I really like Hibernate it still surprises me from time to time how complex things can get. This post highlights a few of these hurdles. I'm pretty sure other ORMs have the same or similar issues, but I'll use Hibernate here because that's what I know best. To demonstrate things I will use the classic &lt;tt&gt;Order&lt;/tt&gt;/&lt;tt&gt;LineItem&lt;/tt&gt; example:&lt;br /&gt;&lt;pre class="brush: java;"&gt;@Entity&lt;br /&gt;@Table(name = "T_ORDER")&lt;br /&gt;public class Order {&lt;br /&gt;&lt;br /&gt; @Id&lt;br /&gt; @GeneratedValue&lt;br /&gt; private Long id;&lt;br /&gt;&lt;br /&gt; @ElementCollection&lt;br /&gt; @CollectionTable(name = "T_LINE_ITEM")&lt;br /&gt; private Set&amp;lt;LineItem&amp;gt; lineItems = new HashSet&amp;lt;LineItem&amp;gt;();&lt;br /&gt;&lt;br /&gt; public Long getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Set&amp;lt;LineItem&amp;gt; getLineItems() {&lt;br /&gt;  return lineItems;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public int getTotalPrice() {&lt;br /&gt;  int total = 0;&lt;br /&gt;  for (LineItem lineItem : lineItems) {&lt;br /&gt;   total += lineItem.getPrice();&lt;br /&gt;  }&lt;br /&gt;  return total;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Embeddable&lt;br /&gt;public class LineItem {&lt;br /&gt;&lt;br /&gt; @ManyToOne(fetch = FetchType.LAZY)&lt;br /&gt; private Product product;&lt;br /&gt; &lt;br /&gt; private int price;&lt;br /&gt; &lt;br /&gt; @SuppressWarnings("unused")&lt;br /&gt; private LineItem() {&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public LineItem(Product product, int price) {&lt;br /&gt;  this.product = product;&lt;br /&gt;  this.price = price;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public Product getProduct() {&lt;br /&gt;  return product;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public int getPrice() {&lt;br /&gt;  return price;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Entity&lt;br /&gt;@Inheritance(strategy = InheritanceType.SINGLE_TABLE)&lt;br /&gt;@Table(name = "T_PRODUCT")&lt;br /&gt;public abstract class Product {&lt;br /&gt;&lt;br /&gt; @Id&lt;br /&gt; @GeneratedValue&lt;br /&gt; private Long id;&lt;br /&gt; &lt;br /&gt; private String name;&lt;br /&gt; &lt;br /&gt; protected Product() {&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; protected Product(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public Long getId() {&lt;br /&gt;  return id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;  return name;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Entity&lt;br /&gt;public class PcProduct extends Product {&lt;br /&gt; &lt;br /&gt; @SuppressWarnings("unused")&lt;br /&gt; private PcProduct() {&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public PcProduct(String name) {&lt;br /&gt;  super(name);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Entity&lt;br /&gt;public class MacProduct extends Product {&lt;br /&gt; &lt;br /&gt; @SuppressWarnings("unused")&lt;br /&gt; private MacProduct() {&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public MacProduct(String name) {&lt;br /&gt;  super(name);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;That's pretty straightforward stuff. Assume we have an order stored in the database:&lt;br /&gt;&lt;pre class="brush: java;"&gt;Product pc = new PcProduct("Dell XPS M1330");&lt;br /&gt;session.save(pc);&lt;br /&gt;Product mac = new MacProduct("Apple MacBook Pro");&lt;br /&gt;session.save(mac);&lt;br /&gt;&lt;br /&gt;Order order = new Order();&lt;br /&gt;order.getLineItems().add(new LineItem(pc, 1000));&lt;br /&gt;order.getLineItems().add(new LineItem(mac, 2000));&lt;br /&gt;session.save(order);&lt;br /&gt;&lt;/pre&gt;Now let's look at some surprising pieces of code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Beware of fetch joins&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;Suppose you have a business transaction processing orders involving Dell XPS M1330s:&lt;br /&gt;&lt;pre class="brush: java;"&gt;List&amp;lt;Order&amp;gt; results = session.createQuery(&lt;br /&gt;  "from Order as o join fetch o.lineItems as li where li.product.name = 'Dell XPS M1330'").list();&lt;br /&gt;for (Order result : results) {&lt;br /&gt; System.out.println(result.getTotalPrice());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;What do you think this prints out for our sample order containing both a Dell XPS M1330 and an Apple MacBook Pro? If you guessed &lt;b&gt;1000&lt;/b&gt; you would be right... oopsie! The &lt;tt&gt;fetch&lt;/tt&gt; in the query combined with criteria on the joined relation causes the &lt;tt&gt;lineItems&lt;/tt&gt; collection of the resulting &lt;tt&gt;Order&lt;/tt&gt; entities to be incomplete! Unfortunately, there is no way to tell that those &lt;tt&gt;Order&lt;/tt&gt; objects are crippled. Worse still, they will end up in the Hibernate session so you might inadvertently end up using them later on in the same transaction, unaware that they are damaged goods. This can lead to very hard to diagnose bugs, because the cause of the problem (the &lt;tt&gt;join fetch&lt;/tt&gt;) and the effects (incorrect results) might be far apart in the code. It's interesting to note that normal joins (so not using fetch) do not have this adverse side effect. So my advice is:&lt;br /&gt;&lt;blockquote&gt;Be very wary of &lt;b&gt;fetch&lt;/b&gt; joins. Only use them if you are sure the resulting objects will not be reused later on in the same session for different purposes.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;b&gt;Beware of inheritance mapping&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Let's look at another order processing transaction:&lt;br /&gt;&lt;pre class="brush: java;"&gt;long orderId = ...;&lt;br /&gt;Order order = (Order) session.get(Order.class, orderId);&lt;br /&gt;Product product = order.getLineItems().iterator().next().getProduct();&lt;br /&gt;&lt;br /&gt;PcProduct pcProduct = (PcProduct) session.get(PcProduct.class, product.getId());&lt;br /&gt;&lt;br /&gt;System.out.println(pcProduct.getId().equals(product.getId()));&lt;br /&gt;System.out.println(pcProduct == product);&lt;br /&gt;&lt;/pre&gt;If you run this piece of code, Hibernate will spit out a warning:&lt;br /&gt;&lt;pre&gt;1463 [main] WARN org.hibernate.engine.StatefulPersistenceContext.ProxyWarnLog&lt;br /&gt; Narrowing proxy to class com.ervacon.order.PcProduct - this operation breaks ==&lt;br /&gt;&lt;/pre&gt;And indeed, the output is &lt;tt&gt;true&lt;/tt&gt; / &lt;tt&gt;false&lt;/tt&gt;, confirming that the session can now no longer guarantee that primary key equality is equivalent with reference equality (&lt;tt&gt;==&lt;/tt&gt;). This is a dangarous situation that could again lead to hard to diagnose bugs, especially if some parts of the code (e.g. the &lt;tt&gt;lineItem.getProduct()&lt;/tt&gt; call) are only executed is certain situations. There are other problems with mapping inheritance hierarchies (e.g. the fact that &lt;tt&gt;instanceof&lt;/tt&gt; in unreliable), so my advice here is:&lt;br /&gt;&lt;blockquote&gt;When using Hibernate, &lt;b&gt;avoid mapping inheritance hierarchies&lt;/b&gt;. There are often better ways to factor your code that do not require mapping an inheritance hierarchy to the database, for instance by introducing an common interface to facilitate polymorphism.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;There are other non-obvious head-scratchers you run into when using an object-relational mapper like Hibernate. If you know about an interesting one, I'd love to hear about it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-6080374918342034444?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/6080374918342034444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2011/02/hibernate-hurdles.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6080374918342034444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6080374918342034444'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2011/02/hibernate-hurdles.html' title='Hibernate hurdles'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-1692471181825436585</id><published>2010-11-11T07:49:00.003+01:00</published><updated>2010-11-13T11:25:38.671+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>To reuse or not to reuse, that's the question</title><content type='html'>It's clear that code duplication is a very bad &lt;a href="http://en.wikipedia.org/wiki/Code_smell"&gt;code smell&lt;/a&gt;. As a result you use things like  &lt;i&gt;extract method&lt;/i&gt; refactoring to keep your code &lt;a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt;. This brings up the question if this can be taken too far? Should &lt;b&gt;all&lt;/b&gt; code duplication be avoided at all times?&lt;br /&gt;&lt;br /&gt;Let me illustrate. Assume you have a bit of code like this:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public static void notNull(Object obj) throws IllegalArgumentException {&lt;br /&gt; if (obj == null) {&lt;br /&gt;  throw new IllegalArgumentException("Argument cannot be null");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This method is clearly designed for reuse. It's a small building block of code that can be used thoughout a piece of software to avoid duplicating null-checking code in several places. In this case there are also no real downsides to consider.&lt;br /&gt;&lt;br /&gt;Now consider a somewhat higher level piece of (admittedly extremely contrived) code:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public void doSomeProcessing(String str) {&lt;br /&gt; checkPreconditions(str);&lt;br /&gt; ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void checkPreconditions(String str) {&lt;br /&gt; Check.notNull(str);&lt;br /&gt; if (!"A".equals(str) &amp;&amp; !"B".equals(str)) {&lt;br /&gt;  throw new IllegalArgumentException("Argument can only be A or B");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;As it stands right now the private &lt;tt&gt;checkPreconditions()&lt;/tt&gt; method is not designed for reuse. If another component in the system happens to require the exact same preconditions, should you try to reuse it? In some situations the answer to this question is clearly: yes! If the new component intrinsically requires the same preconditions, it's natural to try to reuse the method and highlight the fact that the two components have some functional relation. However, in other situations the fact that the two components do the same pre-condition checks might be purely accidental. In other words: there is no functional relation between the two components. In this case refactoring the code to be able to reuse the &lt;tt&gt;checkPreconditions()&lt;/tt&gt; method in both cases comes with a few downsides you should consider:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;By reusing the method, the refactored code now potentially communicates a relationship between the two components, where there really is none.&lt;/li&gt;&lt;li&gt;If the preconditions of the two components are in reality unrelated, it would not be uncommon for the preconditions&lt;br /&gt;of one of the components to change, while the other component's preconditions remain the same. When making this change in the refactored code, you need to realise you can't just change the common &lt;tt&gt;checkPreconditions()&lt;/tt&gt; method. Instead, a more complex code change will be required.&lt;/li&gt;&lt;/ul&gt;In my experience DRY code is certainly something to strive for. However, avoiding code duplication at all costs also comes at a cost!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-1692471181825436585?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/1692471181825436585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/11/to-reuse-or-not-to-reuse-thats-question.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/1692471181825436585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/1692471181825436585'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/11/to-reuse-or-not-to-reuse-thats-question.html' title='To reuse or not to reuse, that&apos;s the question'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-6921211806588685687</id><published>2010-10-30T17:34:00.000+02:00</published><updated>2010-10-30T17:34:20.393+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Installing ING Home'Bank and Belgian eID on Ubuntu</title><content type='html'>I spend some time today upgrading my laptop from Ubuntu 9.04 (Jaunty Jackalope) to 10.04 LTS (Lucid Lynx) since 9.04 reached it's &lt;a href="http://fridge.ubuntu.com/node/2132"&gt;end of life&lt;/a&gt; earlier this month. Overall this was a very smooth process except for two specific apps that I require: &lt;a href="http://homebank.ing.be/"&gt;ING Home&amp;#39;Bank&lt;/a&gt; and &lt;a href="http://eid.belgium.be/"&gt;Belgian eID&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In an attempt to help people who also need to install one of these apps on a recent Ubuntu version, here is how I did it:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Home&amp;#39;Bank&lt;/b&gt;&lt;br /&gt;ING is phasing out it's Home&amp;#39;Bank security module so the &lt;a href="https://download.ing.be/software/homebank/offline/downloadSecModule.asp"&gt;download&lt;/a&gt; is ages old and references a bunch of old libraries.&lt;br /&gt;&lt;br /&gt;Start by downloading the &lt;tt&gt;HomeBank333.deb&lt;/tt&gt; and simply install it as you would any other &lt;tt&gt;.deb&lt;/tt&gt;. Next thing to do is pin the Home&amp;#39;Bank version in Synaptec to avoid this bug: &lt;a href="https://bugs.launchpad.net/ubuntu/+source/homebank/+bug/380511"&gt;380511&lt;/a&gt;. To do that, start Synaptec, find the &lt;tt&gt;homebank&lt;/tt&gt; package and select Package&amp;gt;Lock Version.&lt;br /&gt;&lt;br /&gt;If you try to run &lt;tt&gt;/opt/HomeBank/HBSecurity&lt;/tt&gt;, it will complain about 3 missing libraries:&lt;br /&gt;&lt;ol&gt; &lt;li&gt;libtiff.so.3 is missing -- simply sym-link it:&lt;br /&gt;&lt;pre&gt;cd /usr/lib&lt;br /&gt;sudo ln -s libtiff.so.4 libtiff.so.3&lt;/pre&gt; &lt;/li&gt; &lt;li&gt;libexpat.so.0 is missing -- install and sym-link it:&lt;br /&gt;&lt;pre&gt;sudo apt-get install libexpat1&lt;br /&gt;cd /usr/lib&lt;br /&gt;sudo ln -s /lib/libexpat.so.1 libexpat.so.0&lt;/pre&gt; &lt;/li&gt; &lt;li&gt;libstdc++libc6.2-2.so.3 is missing -- this is an old Dapper Drake package that you can still &lt;a href="http://packages.ubuntu.com/dapper/libstdc++2.10-glibc2.2"&gt;download&lt;/a&gt; and install&lt;br /&gt; &lt;/li&gt;&lt;/ol&gt;Once these steps have been completed you should be able to run &lt;tt&gt;/opt/HomeBank/HBSecurity&lt;/tt&gt; and start using Home&amp;#39;Bank.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Belgian eID&lt;/b&gt;&lt;br /&gt;This is actually straightforward. A &lt;tt&gt;.deb&lt;/tt&gt; package is provided for recent Ubuntu versions that installs and runs without any problems. The only problem on my machine was that my smart card reader was not being recognized (an &lt;i&gt;Alcor Micro Corp. EMV Certified Smart Card Reader&lt;/i&gt; in my case -- do a &lt;tt&gt;lsusb&lt;/tt&gt; in a terminal to find out what type of smart card reader you have). To rectify that, I had to install the &lt;a href="http://packages.ubuntu.com/lucid/libccid"&gt;libccid&lt;/a&gt; package:&lt;br /&gt;&lt;pre&gt;sudo apt-get install libccid&lt;br /&gt;&lt;/pre&gt;Once that is done you can simply follow the &lt;a href="http://eid.belgium.be/nl/Achtergrondinfo/Handleidingen_voor_softwareupdates/index.jsp"&gt;install instructions&lt;/a&gt; provided in a PDF to configure your Firefox to use the new certificates and you should be up-and-running!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-6921211806588685687?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/6921211806588685687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/10/installing-ing-home-and-belgian-eid-on.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6921211806588685687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6921211806588685687'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/10/installing-ing-home-and-belgian-eid-on.html' title='Installing ING Home&amp;#39;Bank and Belgian eID on Ubuntu'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-5865813008061950321</id><published>2010-10-07T08:59:00.002+02:00</published><updated>2010-10-07T09:02:06.076+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>ThreadLocal naming conventions</title><content type='html'>Since &lt;a href="http://ev9d9.blogspot.com/2010/08/killer-tool-sonar.html"&gt;Sonar&lt;/a&gt; is now part of our normal build platform on the project I'm currently doing, we're keeping a close eye on the violations it identifies. One rule we violate in a couple of places is the &lt;a href="http://checkstyle.sourceforge.net/"&gt;CheckStyle&lt;/a&gt; constant naming rule. This rule simply says that the names of all &lt;tt&gt;static final&lt;/tt&gt; variables should be ALL_UPPERCASE_WITH_UNDERSCORES. This is of course a well known Java coding convention. Still, it feels a little unnatural if you apply it to &lt;tt&gt;ThreadLocal&lt;/tt&gt;s, which are technically &lt;tt&gt;static final&lt;/tt&gt; variables, but are neither immutable nor do they have a &lt;i&gt;global&lt;/i&gt; scope like typical constants. This makes code using &lt;tt&gt;ThreadLocal&lt;/tt&gt;s look a bit weird if you use normal Java constant naming, e.g. compare the following:&lt;br /&gt;&lt;pre class="brush: java;"&gt;private static final ThreadLocal&amp;lt;Date&amp;gt; TIME_FRAME = new ThreadLocal&amp;lt;Date&amp;gt;();&lt;br /&gt;...&lt;br /&gt;TIME_FRAME.set(myDate);&lt;br /&gt;&lt;/pre&gt;&lt;pre class="brush: java;"&gt;private static final ThreadLocal&amp;lt;Date&amp;gt; timeFrame = new ThreadLocal&amp;lt;Date&amp;gt;();&lt;br /&gt;...&lt;br /&gt;timeFrame.set(myDate);&lt;br /&gt;&lt;/pre&gt;For me using normal variable naming conventions for &lt;tt&gt;ThreadLocal&lt;/tt&gt;s seems to better communicate their role and intented usage in the code. Does anybody have an idea what the official Java naming conventions for ThreadLocals are?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-5865813008061950321?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/5865813008061950321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/10/threadlocal-naming-conventions.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5865813008061950321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5865813008061950321'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/10/threadlocal-naming-conventions.html' title='&lt;tt&gt;ThreadLocal&lt;/tt&gt; naming conventions'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-2468706067113173343</id><published>2010-08-27T19:38:00.001+02:00</published><updated>2010-08-27T19:41:42.369+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Killer tool: Sonar</title><content type='html'>Today a colleague at work showed &lt;a href="http://www.sonarsource.org/"&gt;Sonar&lt;/a&gt; to me, and I must say that I was really impressed! Sonar is an open source code quality analysis tool that uses a number of popular Java code analyzers like &lt;a href="http://pmd.sourceforge.net/"&gt;PMD&lt;/a&gt;, &lt;a href="http://checkstyle.sourceforge.net/"&gt;CheckStyle&lt;/a&gt;, &lt;a href="http://findbugs.sourceforge.net/"&gt;FindBugs&lt;/a&gt; and &lt;a href="http://cobertura.sourceforge.net/"&gt;Cobertura&lt;/a&gt; under the hood, and presents the metrics calculated by all of these in a consistent and integrated way. It also keeps track of all the metrics data in a database so you can see how your code quality evolves.&lt;br /&gt;&lt;br /&gt;One part of Sonar is a Web front-end for the metrics database, and the other part is a &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt; plugin that runs all code analyzers and pumps the collected data into that database. (As an aside: imagine how much harder it would be to develop a tool like this if there wasn't a dominant build solution in the Java space like Maven.)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_4CDj2OINlFk/THf3Gxra98I/AAAAAAAAABk/UP4WMBPkYkY/s1600/sonar.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_4CDj2OINlFk/THf3Gxra98I/AAAAAAAAABk/UP4WMBPkYkY/s320/sonar.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;As a package Sonar just ticks all the right boxes. It's really easy to get up and running (starting its DB/Web server and running &lt;tt&gt;mvn clean install sonar:sonar&lt;/tt&gt; in your Maven project is all there is to it), feels absolutely solid, has a friendly UI and looks very polished overall.&lt;br /&gt;&lt;br /&gt;Warmly recommended!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-2468706067113173343?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/2468706067113173343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/08/killer-tool-sonar.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/2468706067113173343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/2468706067113173343'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/08/killer-tool-sonar.html' title='Killer tool: Sonar'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_4CDj2OINlFk/THf3Gxra98I/AAAAAAAAABk/UP4WMBPkYkY/s72-c/sonar.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-5509632733817302677</id><published>2010-07-21T07:25:00.001+02:00</published><updated>2010-07-21T07:29:18.123+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>How much damage can a Java Error do?</title><content type='html'>In Java there is a clear distinction between recoverable &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Exception.html"&gt;&lt;tt&gt;Exception&lt;/tt&gt;&lt;/a&gt;s and fatal &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Error.html"&gt;&lt;tt&gt;Error&lt;/tt&gt;&lt;/a&gt;s. It's common for applications to have a &lt;i&gt;catch-all&lt;/i&gt; block so that they can continue running even if unexpected problems occur:&lt;br /&gt;&lt;pre class="brush: java;"&gt;while (true) {&lt;br /&gt; try {&lt;br /&gt;  // execute application logic&lt;br /&gt; } catch (Throwable t) {&lt;br /&gt;  // log exception and/or display to the user&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This will catch both &lt;tt&gt;Exception&lt;/tt&gt;s and &lt;tt&gt;Error&lt;/tt&gt;s. Although it's fine to catch an &lt;tt&gt;Exception&lt;/tt&gt; and have the application carry on, this is typically not a good idea when an &lt;tt&gt;Error&lt;/tt&gt; occurs!&lt;br /&gt;&lt;br /&gt;I recently saw a bug in an application that caused a &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/StackOverflowError.html"&gt;&lt;tt&gt;StackOverflowError&lt;/tt&gt;&lt;/a&gt;. However, because of a catch-all block the application tried to recover from the problem and carry on. As it turns out this caused all kinds of instability and seemingly unrelated problems: connection leaks, &lt;tt&gt;ThreadLocal&lt;/tt&gt; corruption and other such joys.&lt;br /&gt;&lt;br /&gt;If you think about it this makes sense. A &lt;tt&gt;StackOverflowError&lt;/tt&gt; indicates that the JVM ran out of stack space to properly invoke methods. Of course this has implications for things like &lt;tt&gt;finally&lt;/tt&gt; blocks, and certainly for method invocations in those finally blocks! If you can no longer rely on the proper execution of your &lt;tt&gt;finally&lt;/tt&gt; blocks you end up in a world of pain with things like messed up &lt;tt&gt;ThreadLocal&lt;/tt&gt;s. There are similar considerations for &lt;tt&gt;OutOfMemoryError&lt;/tt&gt; and certainly for the other &lt;a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/VirtualMachineError.html"&gt;&lt;tt&gt;VirtualMachineError&lt;/tt&gt;&lt;/a&gt;s.&lt;br /&gt;&lt;br /&gt;In summary: &lt;tt&gt;Error&lt;/tt&gt;s can do a lot of damage! Don't keep the application running if you encounter an &lt;tt&gt;Error&lt;/tt&gt;. Instead, try to log the problem and die. Only recover in case of &lt;tt&gt;Exception&lt;/tt&gt;s.&lt;br /&gt;&lt;pre class="brush: java;"&gt;while (true) {&lt;br /&gt; try {&lt;br /&gt;  // execute application logic&lt;br /&gt; } catch (Exception e)&lt;br /&gt;  // log error and/or display to the user&lt;br /&gt;  // =&gt; recover&lt;br /&gt; } catch (Error e) {&lt;br /&gt;  // log error and/or display to the user&lt;br /&gt;  // =&gt; exit JVM&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-5509632733817302677?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/5509632733817302677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/07/how-much-damage-can-java-error-do.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5509632733817302677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5509632733817302677'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/07/how-much-damage-can-java-error-do.html' title='How much damage can a Java &lt;tt&gt;Error&lt;/tt&gt; do?'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-7501690094929585038</id><published>2010-06-01T20:23:00.001+02:00</published><updated>2010-06-01T20:26:43.231+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Bitemporality in Python</title><content type='html'>A few years ago I &lt;a href="http://www.infoq.com/news/2008/01/bitemporal"&gt;published&lt;/a&gt; a Java framework to deal with bitemporal issues in rich domain models. The &lt;a href="https://svn.ervacon.com/public/projects/bitemporal/trunk/"&gt;code&lt;/a&gt; is freely available under a BSD style license.&lt;br /&gt;&lt;br /&gt;As a first piece of non-trivial Python programming I coded up an equivalent framework in Python 2.5, available &lt;a href="https://svn.ervacon.com/public/projects/bitemporal/trunk/src/main/python/"&gt;here&lt;/a&gt;. The framework allows you to set up a class with &lt;i&gt;bitemporal properties&lt;/i&gt; that track the &lt;i&gt;history&lt;/i&gt; and &lt;i&gt;evolution&lt;/i&gt; of the value assigned to those properties. Here's a small example that should give you a feel for what you can do:&lt;br /&gt;&lt;pre class="brush: python;"&gt;from bitemporal import *&lt;br /&gt;&lt;br /&gt;class Person:&lt;br /&gt;&lt;br /&gt; def __init__(self, name):&lt;br /&gt;  self.name = name&lt;br /&gt;  self.address = BitemporalProperty()&lt;br /&gt;&lt;br /&gt;p = Person("John Doe");&lt;br /&gt;p.address.assign("Smallville", Interval(date(1975, 4, 3), date.max))&lt;br /&gt;p.address.assign("Bigtown", Interval(date(1994, 8, 26), date.max))&lt;br /&gt;&lt;br /&gt;print p.address.now() # Bigtown&lt;br /&gt;print p.address.on(date(1980, 1, 1)) # Smallville&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I'm looking for feedback on this code, which right now is only about 300 lines long. Is this code pythonic? Or is this Java-style Python code? If so, what areas need to be improved? Personally, I have doubts about at least a few things:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The type checks in the &lt;tt&gt;TimeFrame&lt;/tt&gt; class (and a few other classes) feel iffy:&lt;br /&gt;&lt;pre class="brush: python;"&gt;@classmethod&lt;br /&gt;def set_reference(cls, value):&lt;br /&gt; if type(value) == date:&lt;br /&gt;  cls.reference = datetime.combine(value, time())&lt;br /&gt; else:&lt;br /&gt;  cls.reference = value&lt;br /&gt;&lt;/pre&gt;But how else do I ensure that a timeframe always holds a &lt;tt&gt;datetime&lt;/tt&gt;?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The &lt;tt&gt;BitemporalWrapper&lt;/tt&gt; class feels Java-like. It decorates another object with bitemporal information and functionality. Is there a better way to do this in a dynamically typed language?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;I considered using &lt;tt&gt;@property&lt;/tt&gt; for the &lt;tt&gt;assign()&lt;/tt&gt; method on the &lt;tt&gt;BitemporalProperty&lt;/tt&gt; class, but the problem is that you often want to pass in a validity interval, which rules out use of "&lt;tt&gt;=&lt;/tt&gt;".&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Does anybody have any tips how this code can be improved?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-7501690094929585038?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/7501690094929585038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/06/bitemporality-in-python.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/7501690094929585038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/7501690094929585038'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/06/bitemporality-in-python.html' title='Bitemporality in Python'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-6148625744726497636</id><published>2010-05-13T08:02:00.001+02:00</published><updated>2010-05-13T08:08:59.392+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Python default argument madness</title><content type='html'>I've been learning python recently. I'm just getting started so I'm running into all the stupid beginner problems, for instance the insane behaviour of default argument values. Take this example:&lt;br /&gt;&lt;pre class="brush: python;"&gt;from datetime import datetime&lt;br /&gt;import time&lt;br /&gt;&lt;br /&gt;class Weird:&lt;br /&gt;&lt;br /&gt; def __init__(self, dt = datetime.now()):&lt;br /&gt;  self.dt = dt&lt;br /&gt;&lt;br /&gt;w1 = Weird()&lt;br /&gt;time.sleep(1)&lt;br /&gt;w2 = Weird()&lt;br /&gt;w3 = Weird(datetime.now())&lt;br /&gt;&lt;br /&gt;print w1.dt == w2.dt # True&lt;br /&gt;print w1.dt == w3.dt # False&lt;br /&gt;&lt;/pre&gt;The &lt;tt&gt;datetime&lt;/tt&gt; in the &lt;tt&gt;w1&lt;/tt&gt; and &lt;tt&gt;w2&lt;/tt&gt; objects will actually be the same since the default argument value in the method definition is &lt;a href="http://www.network-theory.co.uk/docs/pytut/DefaultArgumentValues.html"&gt;only evaluated once&lt;/a&gt;! What!?!? This essentially renders default arguments useless since you always end up writing the following:&lt;br /&gt;&lt;pre class="brush: python;"&gt;class Weird:&lt;br /&gt;&lt;br /&gt; def __init__(self, dt = None):&lt;br /&gt;  self.dt = dt or datetime.now()&lt;br /&gt;&lt;/pre&gt;I don't understand why you would design a default argument values features in your language like this. Doing it this way certainly violates the &lt;a href="http://ev9d9.blogspot.com/2010/05/what-is-good-code.html"&gt;principle of least astonishment&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-6148625744726497636?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/6148625744726497636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/05/python-default-argument-madness.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6148625744726497636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/6148625744726497636'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/05/python-default-argument-madness.html' title='Python default argument madness'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-7225495883060015040</id><published>2010-05-01T07:24:00.001+02:00</published><updated>2010-05-01T07:34:45.849+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>What is good code?</title><content type='html'>As a project tech lead I do a lot of code review, so the "What is good code?" question comes up a lot. Of course there a many things that factor into the good code equation such as efficiency, correctness and elegance. For me the most important property of good code is that it should adhere to the &lt;a href="http://en.wikipedia.org/wiki/Principle_of_least_astonishment"&gt;principle of least astonishment&lt;/a&gt;. In other words: good code is code that does what you expect it to do in the way you expect it to be done.&lt;br /&gt;&lt;br /&gt;Following this principle has important benefits when it comes to reading, understanding and maintaining a piece of code. It also typically improves the correctness of the code: you tend to get &lt;i&gt;code that obviously has no deficiencies, in stead of no obvious deficiencies&lt;/i&gt; (as &lt;a href="http://en.wikipedia.org/wiki/Tony_Hoare"&gt;Tony Hoare&lt;/a&gt; said).&lt;br /&gt;&lt;br /&gt;I was happy to learn that I'm in good company when it comes to attributing the principle of least astonishment to good code. Both Uncle Bob (in his excellent &lt;a href="http://blog.objectmentor.com/articles/2008/04/08/clean-code-whew"&gt;Clean Code&lt;/a&gt; book) and Peter Seibel (in his very interesting &lt;a href="http://www.codersatwork.com/"&gt;Coders at Work&lt;/a&gt;) ask several famous programmers about good code. A lot of the interviewees directly or indirectly mention the principle of least astonishment (for instance &lt;a href="http://en.wikipedia.org/wiki/Ward_Cunningham"&gt;Ward Cunningham&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Joe_Armstrong_(programming)"&gt;Joe Armstrong&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Simon_Peyton_Jones"&gt;Simon Peyton Jones&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-7225495883060015040?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/7225495883060015040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/05/what-is-good-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/7225495883060015040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/7225495883060015040'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/05/what-is-good-code.html' title='What is good code?'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-5063832145483238481</id><published>2010-04-02T18:52:00.001+02:00</published><updated>2010-04-03T08:58:09.129+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>TreeSet Gotcha</title><content type='html'>Sometimes API design mistakes can make you go &lt;a href="http://en.wikipedia.org/wiki/D'oh!"&gt;d'oh&lt;/a&gt;! In the back of my mind I knew about the weird workings of Java's &lt;tt&gt;TreeSet&lt;/tt&gt;, but today I was bitten by the consequences anyway.&lt;br /&gt;&lt;br /&gt;The basic problem is that &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/TreeSet.html"&gt;&lt;tt&gt;TreeSet&lt;/tt&gt;&lt;/a&gt; implements a &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/Set.html"&gt;&lt;tt&gt;Set&lt;/tt&gt;&lt;/a&gt; in terms of &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/Comparator.html"&gt;&lt;tt&gt;compare()&lt;/tt&gt;&lt;/a&gt; or &lt;a href="http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html"&gt;&lt;tt&gt;compareTo()&lt;/tt&gt;&lt;/a&gt;, instead of the usual &lt;tt&gt;equals()&lt;/tt&gt; method (as documented in the &lt;tt&gt;TreeSet&lt;/tt&gt; JavaDoc). In strict terms this makes &lt;tt&gt;TreeSet&lt;/tt&gt; violate the &lt;tt&gt;Set&lt;/tt&gt; interface with regard to the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov substitution principle&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A quick example to illustrate the problem. Suppose you have a class holding two pieces of information. You want the objects of the class to have a natural order based on just a single piece of information, so you implement &lt;tt&gt;Comparable&lt;/tt&gt; like this:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class Foo implements Comparable&amp;lt;Foo&amp;gt; {&lt;br /&gt; &lt;br /&gt; private Object data;&lt;br /&gt; private int num;&lt;br /&gt;&lt;br /&gt; public Foo(Object data, int num) {&lt;br /&gt;  this.data = data;&lt;br /&gt;  this.num = num;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; @Override&lt;br /&gt; public boolean equals(Object obj) {&lt;br /&gt;  if (obj instanceof Foo) {&lt;br /&gt;   Foo other = (Foo) obj;&lt;br /&gt;   return this.data.equals(other.data) &amp;&amp; this.num == other.num;&lt;br /&gt;  }&lt;br /&gt;  return false;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; @Override&lt;br /&gt; public int hashCode() {&lt;br /&gt;  return data.hashCode() + num;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public int compareTo(Foo other) {&lt;br /&gt;  return this.num - other.num;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;It's natural to assume that &lt;tt&gt;compareTo()&lt;/tt&gt; only influences the order of the objects, but does not influence their equality. However, &lt;tt&gt;TreeSet&lt;/tt&gt; uses &lt;tt&gt;compareTo()&lt;/tt&gt; to test for object equality, which means the following test fails unexpectedly:&lt;br /&gt;&lt;pre class="brush: java;"&gt;@Test&lt;br /&gt;public void usageInASetWorksAsExpected() {&lt;br /&gt; Set&amp;lt;Foo&amp;gt; set = new TreeSet&amp;lt;Foo&amp;gt;();&lt;br /&gt; set.add(new Foo("bar", 1));&lt;br /&gt; set.add(new Foo("baz", 1));&lt;br /&gt; set.add(new Foo("bar", 1));&lt;br /&gt; set.add(new Foo("bar", 2));&lt;br /&gt; Assert.assertEquals(3, set.size()); // actual set size will be 2!&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;D'oh!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-5063832145483238481?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/5063832145483238481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/04/treeset-gotcha.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5063832145483238481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5063832145483238481'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/04/treeset-gotcha.html' title='TreeSet Gotcha'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-544344708681630487</id><published>2010-03-30T20:26:00.002+02:00</published><updated>2010-03-30T20:29:32.094+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='opinion'/><title type='text'>Mac Fanboys in Java Land</title><content type='html'>Could somebody explain to me why lots of Java (and Ruby, Phyton, ...) programmers seem to think Macs are the best thing since sliced bread? I'll be the first to admit that Apple hardware is excellent and that they have a UI flair that is unrivaled by any other company in the IT industry today.&lt;br /&gt;&lt;br /&gt;However, as a programmer I don't care too much about dumbing it all down to a level where my grandmother can use it. I tried the Mac thing and sure it's great for some casual usage, but a number of things just annoy me when I try to get real work done:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First of all: why does Apple treat Java as a second grade citizen?&lt;/li&gt;&lt;li&gt;Why can't I resize my windows on the left side?&lt;/li&gt;&lt;li&gt;Why can't Apple just use a standard PC AZERTY keyboard layout (used in Belgium where I live)? If they did, I would at least be able to find my curly braces and square brackets, and pipe symbol for that matter!&lt;/li&gt;&lt;li&gt;Why does OS X need to deviate from pretty much every common Unix convention like the &lt;a href="http://www.pathname.com/fhs/"&gt;FHS&lt;/a&gt;, making things like the &lt;tt&gt;hosts&lt;/tt&gt; file end up in &lt;tt&gt;/private/etc/hosts&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;Why is it that I need to copy the entire Eclipse installation just to be able to run two workspaces at the same time?&lt;/li&gt;&lt;li&gt;Why is Apple incapable of putting a standard DVI or VGA adaptor on a MacBook?&lt;/li&gt;&lt;/ul&gt;And the list goes on! (For those wondering: I currently run Ubuntu on a Dell XPS laptop: no installation or configuration hassles, and usage freedom to boot!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-544344708681630487?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/544344708681630487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/03/mac-fanboys-in-java-land.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/544344708681630487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/544344708681630487'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/03/mac-fanboys-in-java-land.html' title='Mac Fanboys in Java Land'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-276509446585380828</id><published>2010-03-05T19:00:00.000+01:00</published><updated>2010-03-05T19:00:26.215+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSphere MQ'/><category scheme='http://www.blogger.com/atom/ns#' term='JMS'/><title type='text'>MQ's MQRFH2 Header and JMS</title><content type='html'>I've known about the &lt;a href="http://publib.boulder.ibm.com/infocenter/wmqv6/v6r0/index.jsp?topic=/com.ibm.mq.csqzaw.doc/uj25440_.htm"&gt;MQRFH2&lt;/a&gt; header used by WebSphere MQ for a long time. I was also aware of the problems this header can cause when exchanging messages between JMS and non-JMS based clients, and how to suppress use of the header by using &lt;a href="http://publib.boulder.ibm.com/infocenter/wmqv6/v6r0/index.jsp?topic=/com.ibm.mq.csqzaw.doc/uj25510_.htm"&gt;targetClient=1&lt;/a&gt; (MQJMS_CLIENT_NONJMS_MQ).&lt;br /&gt;&lt;br /&gt;What I did not know before today however, is that if a JMS application receives a message not containing the MQRFH2 header, some basic JMS message properties like &lt;tt&gt;JMSDestination&lt;/tt&gt; will not be available! This makes some sense since WebSphere MQ uses the MQRFH2 header to carry JMS specific data associated with the message. If you omit MQRFH2, only the properties that fit in the default MQMD header will be transmitted, the rest will be lost. (The WebSphere MQ documentation &lt;a href="http://publib.boulder.ibm.com/infocenter/wmqv6/v6r0/index.jsp?topic=/com.ibm.mq.csqzaw.doc/uj25510_.htm"&gt;covers this in some detail&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Still, for something basic like &lt;tt&gt;JMSDestination&lt;/tt&gt; this came as a bit of a surprise since this property is set by the JMS service provider when sending the message and you expect it to be available when receiving that message, for instance to be able to do failover processing and send the message back to its original destination at some later time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-276509446585380828?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/276509446585380828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/03/mqs-mqrfh2-header-and-jms.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/276509446585380828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/276509446585380828'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/03/mqs-mqrfh2-header-and-jms.html' title='MQ&apos;s MQRFH2 Header and JMS'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-8526611849609805685</id><published>2010-02-13T09:06:00.007+01:00</published><updated>2010-03-05T20:09:34.960+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Source Code Management Friendly Design</title><content type='html'>Good software design, especially proper modularization, brings many benefits such as single points of change, encapsulation and a reduced event horizon, just to name a few. This is clearly a Good Thing at the source code level, but it also has important &lt;a href="http://en.wikipedia.org/wiki/Source_Code_Management"&gt;source code management&lt;/a&gt; (SCM) implications. Let's look at an example.&lt;br /&gt;&lt;br /&gt;Suppose your code needs to process some data in several different ways. When I say processing think about things like manipulating the data, reacting to it, and so on. The simplest thing that could possibly work would be something like this:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class DataProcessingEngine {&lt;br /&gt;&lt;br /&gt; public void process(Data data) {&lt;br /&gt;  processOneWay(data);&lt;br /&gt;  processAnotherWay(data);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; private void processOneWay(Data data) {&lt;br /&gt;  // ...&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; private void processAnotherWay(Data data) {&lt;br /&gt;  // ...&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This code has many issues. Purely at the source code level we have a class that just has too many responsibilities. At the SCM level, this class could become a merging nightmare. Imagine multiple development branches each adding new ways to process the data. Merging these branches back onto the trunk will almost certainly result in merging conflicts.&lt;br /&gt;&lt;br /&gt;Of course we can do a lot better. Let's factor out the different ways to process the data into seperate &lt;tt&gt;DataProcessor&lt;/tt&gt;s:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public interface DataProcessor {&lt;br /&gt; void process(Data data);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Each different way of processing the data would have its own &lt;tt&gt;DataProcessor&lt;/tt&gt; implementation. The &lt;tt&gt;DataProcessingEngine&lt;/tt&gt; now becomes:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class DataProcessingEngine {&lt;br /&gt; &lt;br /&gt; private List&amp;lt;DataProcessor&amp;gt; dataProcessors;&lt;br /&gt; &lt;br /&gt; public DataProcessingEngine(List&amp;lt;DataProcessor&amp;gt; dataProcessors) {&lt;br /&gt;  this.dataProcessors = dataProcessors;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void process(Data data) {&lt;br /&gt;  for (DataProcessor dataProcessor : dataProcessors) {&lt;br /&gt;   dataProcessor.process(data);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Of course we still need to configure the &lt;tt&gt;DataProcessingEngine&lt;/tt&gt; with the appropriate &lt;tt&gt;DataProcessor&lt;/tt&gt;s somewhere:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class DataProcessingEngineFactory {&lt;br /&gt;&lt;br /&gt; public static DataProcessingEngine create() {&lt;br /&gt;  List&amp;lt;DataProcessor&amp;gt; dataProcessors = new ArrayList&amp;lt;DataProcessor&amp;gt;();&lt;br /&gt;  dataProcessors.add(new OneWayDataProcessor());&lt;br /&gt;  dataProcessors.add(new AnotherWayDataProcessor());&lt;br /&gt;  return new DataProcessingEngine(dataProcessors);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;You could also use something like &lt;a href="http://www.springframework.org/"&gt;Spring&lt;/a&gt; to do this for you. In this case you would end up with bean definitions equivalent to the code above. At the code level this refactoring has pretty much solved the problem. We now have a few small classes, each with its own responsibility. However, at the SCM level, the &lt;tt&gt;DataProcessingEngineFactory&lt;/tt&gt; class (or equivalent alternative configuration) still sits in a single file causing merge conflicts. &lt;br /&gt;&lt;br /&gt;To solve this problem, we have to make the system a bit more dynamic. If the &lt;tt&gt;DataProcessingEngineFactory&lt;/tt&gt; could automagically detect all available &lt;tt&gt;DataProcessor&lt;/tt&gt; implementations, adding a new way of processing the data would be as simple as adding a new &lt;tt&gt;DataProcessor&lt;/tt&gt; to the classpath. As a result, there would be no need to change the &lt;tt&gt;DataProcessingEngineFactory&lt;/tt&gt; every time, an no more merge conflicts!&lt;br /&gt;&lt;br /&gt;In Java you have quite a few options to implement such a dynamic discovery mechanism:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html"&gt;service provider framework&lt;/a&gt; can automatically detect service implementations defined in META-INF/services.&lt;/li&gt;&lt;li&gt;Spring's &lt;tt&gt;&lt;a href="http://static.springsource.org/spring/docs/current/api/org/springframework/core/io/support/ResourcePatternResolver.html"&gt;ResourcePatternResolver&lt;/a&gt;&lt;/tt&gt; can be used for this kind of thing.&lt;/li&gt;&lt;li&gt;Maybe you can even use the &lt;a href="http://java.sun.com/javase/6/docs/technotes/guides/apt/index.html"&gt;annotation processing tool&lt;/a&gt; to do something like this?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Using the Java 6 &lt;tt&gt;ServiceLoader&lt;/tt&gt;, the &lt;tt&gt;DataProcessingEngineFactory&lt;/tt&gt; would end up looking something like this:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class DataProcessingEngineFactory {&lt;br /&gt;&lt;br /&gt; public static DataProcessingEngine create() {&lt;br /&gt;  List&amp;lt;DataProcessor&amp;gt; dataProcessors = new ArrayList&amp;lt;DataProcessor&amp;gt;();&lt;br /&gt;  for (DataProcessor dataProcessor : ServiceLoader.load(DataProcessor.class)) {&lt;br /&gt;   dataProcessors.add(dataProcessor);&lt;br /&gt;  }&lt;br /&gt;  return new DataProcessingEngine(dataProcessors);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It's interesting to note that annotation based configuration systems, which are all the rage, typically don't hold all configuration information in a single location, which helps ease your source code management as I've shown. XML based configuration is more problematic in this respect.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-8526611849609805685?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/8526611849609805685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/02/source-code-management-friendly-design.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8526611849609805685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8526611849609805685'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/02/source-code-management-friendly-design.html' title='Source Code Management Friendly Design'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-7406136842825704418</id><published>2010-02-02T15:41:00.000+01:00</published><updated>2010-02-02T15:41:36.442+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>OSGI Dependency Resolution is NP-Complete</title><content type='html'>Apparently, &lt;a href="http://stackoverflow.com/questions/2085106/is-the-resolution-problem-in-osgi-np-complete"&gt;the resolution problem in OSGI is NP-Complete&lt;/a&gt;, as are similar dependency resolution problems like apt package installation on Debian Linux systems. If you think about it it makes sense, but who would have thought!&lt;br /&gt;&lt;br /&gt;I still remember learning about P and NP problems, and the famous P = NP question at university, and being really intrigued by all of it. Lance Fortnow provides an excellent &lt;a href="http://cacm.acm.org/magazines/2009/9/38904-the-status-of-the-p-versus-np-problem/fulltext"&gt;overview of the P = NP problem&lt;/a&gt; in Communications of the ACM. It turns out that this is no longer a computer science problem, but one of the fundamental questions in all of science. Fascinating stuff! If only I could find a simple proof :-).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-7406136842825704418?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/7406136842825704418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/02/osgi-dependency-resolution-is-np.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/7406136842825704418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/7406136842825704418'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/02/osgi-dependency-resolution-is-np.html' title='OSGI Dependency Resolution is NP-Complete'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-5435732919202361654</id><published>2010-01-01T13:36:00.002+01:00</published><updated>2010-01-02T09:42:12.397+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='REST'/><category scheme='http://www.blogger.com/atom/ns#' term='web services'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>REST Reservations</title><content type='html'>I'm currently reading &lt;a href="http://oreilly.com/catalog/9780596529260/"&gt;RESTful Web Services&lt;/a&gt; by Leonard Richardson and Sam Ruby, and happened to come across an interesting QCon talk by Mark Nottingham on the &lt;a href="http://www.infoq.com/presentations/mnot-http-status-1108"&gt;status of HTTP&lt;/a&gt;. To me, this talk carries an interesting critical undertone on REST.&lt;br /&gt;&lt;br /&gt;I've followed the whole REST and RESTful Web Services hype with some interest the last few years, and genuinely like several aspects of REST:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can't go wrong with a &lt;b&gt;KISS&lt;/b&gt; approach to software development.&lt;/li&gt;&lt;li&gt;Most everybody is &lt;b&gt;familiar&lt;/b&gt; with how the Web works, so exploiting that familiarity makes a lot of sense.&lt;/li&gt;&lt;li&gt;The HTTP underpinnings of REST make it very &lt;b&gt;well supported&lt;/b&gt; by a multitude of tools.&lt;/li&gt;&lt;li&gt;By leveraging HTTP, REST has &lt;b&gt;excellent support for intermediaries&lt;/b&gt; (i.e. proxies and caches) and all the cool things they can bring to the table.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;On the other hand, I also have some reservations about the whole REST thing, and Mark Nottingham touched on several of these topics in his talk:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;As always, there is a lot of &lt;b&gt;dogma&lt;/b&gt; to go around, and everybody has his own flavour. Is using this or that HTTP method in a particular way RESTful? Mark, who's obviously intimately familiar with HTTP, seems to have a much more pragmatic view on how you can or should use HTTP (i.e. listen to his comments on POST at the very end of the talk).&lt;/li&gt;&lt;li&gt;HTTP is &lt;b&gt;deceptively simple&lt;/b&gt;. The &lt;a href="http://tools.ietf.org/html/rfc2616"&gt;spec&lt;/a&gt; is BIG, and full of ambiguities. The entire first part of Mark's talk deals with this, and I would argue that most people (me included) only have a superficial familiarity with HTTP.&lt;/li&gt;&lt;li&gt;Another thing I dislike about REST is that it's &lt;b&gt;not generally applicable&lt;/b&gt;. For instance, suppose you're developing a search service, like Google (a typical text-book RESTful Web Service example). Most everybody in the REST community agrees that you should use HTTP GET for the search and encode the query in the URI: &lt;tt&gt;http://www.google.be/search?q=jellyfish&lt;/tt&gt;. Imagine a similar search service that allows you to search for images that look like a given image. Logically this is completely in-line with the simple search service, but because of technical limitations of HTTP GET you're forced to implement this in a different way (WS-* is more consistently applicable this way).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For me, it's all about sane software engineering. If you have a well designed service, using established standards and conventions where relevant, people are going to be able to use your service without much problems. Things like REST and WS-* all have there place as tools in a developers toolbox, and it's up to us developers to make informed decisions on when to use what to build the best possible software we can.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-5435732919202361654?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/5435732919202361654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2010/01/rest-reservations.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5435732919202361654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5435732919202361654'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2010/01/rest-reservations.html' title='REST Reservations'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-1426671070415950318</id><published>2009-12-13T08:06:00.000+01:00</published><updated>2009-12-13T08:06:50.294+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>Concurrency Hides Latency</title><content type='html'>To paraphrase Brian Goetz's excellent &lt;a href="http://www.devoxx.com/display/DV09/The+Concurrency+Revolution"&gt;The Concurrency Revolution: The Hardware Story&lt;/a&gt; talk at Devoxx09: "concurrency hides latency". In other words: use concurrency to combat latency. This really seems to be the common theme in current-day software development.&lt;br /&gt;&lt;br /&gt;In his talk, Brian explained how CPU speeds have increased at a much faster pace than memory speeds the last few decades. This has resulted in a situation where going to main memory is now extremely expensive in terms of CPU time. It could take several hundred clock cycles to fetch some data from main memory. Brian captured the problem in anther very quotable statement: "memory is the new disk". Hardware designers have been trying to minimize the impact of memory latency on computer performance by clever tricks like &lt;a href="http://en.wikipedia.org/wiki/Speculative_execution"&gt;speculative execution&lt;/a&gt; and extensive caching. However, we've now come to a point where these techniques are breaking down because the gap between CPU and memory speed is just too big. As a result we're seeing more and more multi-core CPUs: slower in absolute terms but designed for concurrency so latency is less of a problem.&lt;br /&gt;&lt;br /&gt;In web applications, a round-trip to the server involves a lot of latency, so web applications are doing more things on the client in JavaScript and hide this latency by concurrently doing other things: think AJAX. In a typical back-end business processing system, a round-trip to the database also involves a lot of latency, so we use techniques like event driven architectures to process several transactions concurrently, again hiding the latency cost.&lt;br /&gt;&lt;br /&gt;More and more &lt;b&gt;performance is about data, not code&lt;/b&gt; (another quote from Brian's talk)! I've seen several situations where the efficiency of a particular piece of software is completely determined by it's data access strategy. Relatively speaking, fetching data from the database is so expensive that it doesn't matter that you process that data in a naive or unoptimized way. All of this of course also implies that a key design question is the data access patterns and data structures used by the application. If you want a fast application, data is your key concern, and you can fight the latency of getting to the data by using concurrency.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-1426671070415950318?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/1426671070415950318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/12/concurrency-hides-latency.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/1426671070415950318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/1426671070415950318'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/12/concurrency-hides-latency.html' title='Concurrency Hides Latency'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-5808386475683267501</id><published>2009-11-28T11:51:00.001+01:00</published><updated>2009-11-30T07:57:35.921+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Hidden Benefits from Commenting Your Code</title><content type='html'>In his famous book &lt;a href="http://martinfowler.com/books.html#refactoring"&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt; Martin Fowler mentions comments as a possible &lt;a href="http://en.wikipedia.org/wiki/Code_smell"&gt;code smell&lt;/a&gt;: if you need comments to explain what your code does, try to refactor it so that the comments become superfluous. Uncle Bob also mentions this same principle in his &lt;a href="http://blog.objectmentor.com/articles/2008/04/08/clean-code-whew"&gt;Clean Code&lt;/a&gt; book: most comments are bad comments, typically redundant or misleading.&lt;br /&gt;&lt;br /&gt;I largely follow this reasoning. However, I've also seen an interesting benefit from trying to comment your code, especially with &lt;i&gt;higher level&lt;/i&gt; comments, for instance JavaDoc comments on classes. Writing these kinds of comments forces you to explain things like the purpose and responsibility of the class. Personally, I've had several occasions where explaining things in plain English highlighted problems. If it's hard to explain what the class's purpose is, or what the reasoning behind the class or method names is, this typically means you have code problems. Maybe the class has unclear or too many responsibilities? Maybe the class name doesn't communicate its purpose well? Maybe the class's role in the system is confusing, and so on.&lt;br /&gt;&lt;br /&gt;Nowadays, I try to keep comments in internal code to a minimum, but I do try to write a brief JavaDoc style comment for each class, forcing myself to go through that &lt;i&gt;explaining&lt;/i&gt; exercise I just mentioned. I do the same thing for methods that are part of a public API: they also get brief JavaDoc style comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-5808386475683267501?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/5808386475683267501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/hidden-benefits-from-commenting-your.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5808386475683267501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/5808386475683267501'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/hidden-benefits-from-commenting-your.html' title='Hidden Benefits from Commenting Your Code'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-4743010223218449692</id><published>2009-11-24T17:32:00.001+01:00</published><updated>2009-11-24T17:45:59.492+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Page Flow Challenge Clarification</title><content type='html'>The Page Flow Challenge in my &lt;a href="http://ev9d9.blogspot.com/2009/11/page-flow-challenge.html"&gt;previous post&lt;/a&gt; warrants a bit of clarification. A few readers had questions about the usefulness or sanity of certain steps in the test scenario. I'll go through the scenario and highlight what is being tested in each of the steps.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Start the page flow&lt;/li&gt;&lt;li&gt;On Page 1, enter "foo" and click Next&lt;br /&gt;You should end up on Page 2 where "foo" is displayed as input from page 1&lt;/li&gt;&lt;li&gt;On Page 2, enter "baz" and click Next&lt;br /&gt;You should end up on Page 3 where "foo" and "baz" are displayed as input from the previous pages&lt;/li&gt;&lt;li&gt;Click the browser back button&lt;br /&gt;Without any browser warnings you should end up on Page 2, where "foo" is still displayed as input from page 1&lt;/li&gt;&lt;/ol&gt;The first part of the scenario sets up a basic set of data associated with the page flow: "foo" and "baz" at this point. At step 4 we're using the browser back button to backtrack. This tests POST-REDIRECT-GET behaviour: if the application does not use POST-REDIRECT-GET, the browser will show a warning before displaying Page 2 again. This is so because Page 2 is the result of posting the HTML form on Page 1, and modern browsers never automatically resubmit post data. Essentially we're protecting the user from &lt;b&gt;accidental resubmits&lt;/b&gt;. Not having the browser show ugly warnings about resubmitting also makes the application feel stable and trustworthy.&lt;br /&gt;&lt;ol start="5"&gt;&lt;li&gt;Right click the Back link on the page and do Open Link in New Window&lt;br /&gt;The new window should show Page 1 where "foo" is displayed in the input field&lt;/li&gt;&lt;li&gt;In the new window, enter "kit" (replacing "foo") and click Next&lt;br /&gt;You should end up on Page 2 where "kit" is displayed as input from page 1&lt;/li&gt;&lt;li&gt;In the new window, on Page 2 enter "kat" and click Next&lt;br /&gt;You should end up on Page 3 where "kit" and "kat" are displayed as input from the previous pages&lt;/li&gt;&lt;li&gt;In the original window, click the browser refresh button&lt;br /&gt;Without any browser warnings you should see Page 2 again with "foo" as input from page 1&lt;/li&gt;&lt;/ol&gt;Step 5, admittedly a contrived step, simulates the user branching off the page flow into two separate windows. The point of doing this is testing whether or not the two branches are &lt;b&gt;isolated&lt;/b&gt;. In steps 6 and 7 new data is entered ("kit" and "kat") that potentially interferes with the previously entered data ("foo" and "baz"). Step 8 verifies that no interference happened: the page flow in the original window still has "foo" as data.&lt;br /&gt;&lt;ol start="9"&gt;&lt;li&gt;In the original window, enter "bar" and click Next&lt;br /&gt;You should end up on Page 3 with "foo" and "bar" as input from previous pages&lt;/li&gt;&lt;li&gt;In the original window, click Finish&lt;br /&gt;You should end up on the start page of the application: the page flow has finished&lt;/li&gt;&lt;li&gt;In the original window, click the browser back button&lt;br /&gt;You should either receive an error immediately, or when you try to resubmit by clicking Finish again&lt;/li&gt;&lt;/ol&gt;In step 9 and 10, we complete the page flow and finally submit values "foo" and "bar". At this point the page flow has finished. The state and navigation management of the framework should have invalidated the page flow at this point, making it impossible to resubmit. Step 11 verifies this: if you go back using the browser back button, you should not be allowed to resubmit. This part of the scenario tests intentional &lt;b&gt;double submit&lt;/b&gt; protection (classically solved with something like a &lt;a href="http://www.javaworld.com/javaworld/javatips/jw-javatip136.html"&gt;synchronizer token&lt;/a&gt;).&lt;br /&gt;&lt;ol start="12"&gt;&lt;li&gt;(&lt;i&gt;For extra bonus points&lt;/i&gt;) In the new window, (where you still are on Page 3) click Finish&lt;br /&gt;You should receive an error of some sort (potentially a automatic page flow restart)&lt;/li&gt;&lt;/ol&gt;The final step of the scenario tests whether or not the framework tracks the two branches of the page flow as being part of the same original &lt;i&gt;conversation&lt;/i&gt;. This is an advanced form of double submit protection. In most cases this is a beneficial extra protection. In some cases this might not be what you want.&lt;br /&gt;&lt;br /&gt;To make all of this a bit more tangible, let's suppose this is an airline ticket booking flow. The scenario would go something like this:&lt;br /&gt;In step 2, on Page 1, the users fills in basic traveller information (name, age, seating class) and advances forward. In step 3, on Page 2, he selects a seating preference. Page 3 in step 4 shows an overview of the captured information and asks for confirmation. The user notices that he made a mistake and backs up.&lt;br /&gt;Steps 5, 6 and 7 has the user thinking he might want to try a seat in a different seating class and compare the prices. Page 3 in step 7 displays an overview of the price with the new seating class.&lt;br /&gt;In step 8 and 9 the user completes the page flow with the original seating class. On step 10 he compares the prices of the two alternatives and decides to submit the first of the two alternatives.&lt;br /&gt;Steps 11 and 12 verify that the user cannot accidentally book two tickets, either by resubmitting the first alternative or submitting the second alternative. If he really wants another ticket, he'll have to start the ticket booking process (the page flow) again.&lt;br /&gt;&lt;br /&gt;I hope this clarifies things a bit and shows that the test scenario is actually somewhat realistic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-4743010223218449692?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/4743010223218449692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/page-flow-challenge-clarification.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/4743010223218449692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/4743010223218449692'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/page-flow-challenge-clarification.html' title='Page Flow Challenge Clarification'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-442670109494373211</id><published>2009-11-22T11:17:00.009+01:00</published><updated>2009-11-24T17:33:40.064+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>A Page Flow Challenge</title><content type='html'>In this post I setup a &lt;i&gt;page flow challenge&lt;/i&gt; to find out if the new or up-and-coming web frameworks handle page flows well.&lt;br /&gt;&lt;br /&gt;Why am I doing this? Over the last several years I've seen quite a few blogs and discussions where people talk about how web framework X handles page flows, typically comparing the page flow functionality in framework X with &lt;a href="http://en.wikipedia.org/wiki/Spring_Web_Flow"&gt;Spring Web Flow&lt;/a&gt;. The problem with most of these comparisons is that they focus on just two parts of the page flow puzzle: expressing page flows through some kind of DSL, and reusing page flows as modules throughout the application. There is an important third piece: managing navigation and the associated state. The reason why this is often overlooked is probably because the navigation and state management is completely automatic in Spring Web Flow, so many people don't even realize that it's there.&lt;br /&gt;&lt;br /&gt;While attending a session on the &lt;a href="http://liftweb.net/"&gt;Lift&lt;/a&gt; framework last week at &lt;a href="http://www.devoxx.com/display/DV09/Home"&gt;Devoxx09&lt;/a&gt;, this issue came up again. Somebody (not me :) asked whether "Lift has page flow functionality like Spring Web Flow?". The answer was as expected: the Lift developers have a page flow DSL in the works &lt;del&gt;but seem to have missed the navigation and state management part&lt;/del&gt; (&lt;b&gt;update&lt;/b&gt;: this appears to be incorrect, Lift does have navigation and state management.).&lt;br /&gt;&lt;br /&gt;It's not enough to be able to define a page flow, the framework also needs to manage it! To help users and framework developers realize this, I've setup a &lt;i&gt;page flow challenge&lt;/i&gt;. The idea is that you develop a simple 3-page page flow in your framework of choice and test whether it can correctly run a somewhat contrived scenario that tests things like POST-REDIRECT-GET to avoid accidental resubmission, double submit protection to avoid intentional resubmission, and correct state management. In essence the page flow should behave correctly whatever the user does and protect the user from potential mistakes.&lt;br /&gt;&lt;br /&gt;Let's look at the page flow:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_4CDj2OINlFk/SwkPYP9qoUI/AAAAAAAAABQ/crzg5BwX4Rc/s1600/flow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_4CDj2OINlFk/SwkPYP9qoUI/AAAAAAAAABQ/crzg5BwX4Rc/s400/flow.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Easy peasy. This could for instance be a flow to submit a payment in an electronic banking application, or a flow to handle checkout in a web shop.&lt;br /&gt;&lt;br /&gt;The page flow challenge scenario is as follows (note: I've clarified this scenario in a &lt;a href="http://ev9d9.blogspot.com/2009/11/page-flow-challenge-clarification.html"&gt;follow-up post&lt;/a&gt;):&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Start the page flow&lt;/li&gt;&lt;li&gt;On Page 1, enter "foo" and click Next&lt;br /&gt;You should end up on Page 2 where "foo" is displayed as input from page 1&lt;/li&gt;&lt;li&gt;On Page 2, enter "baz" and click Next&lt;br /&gt;You should end up on Page 3 where "foo" and "baz" are displayed as input from the previous pages&lt;/li&gt;&lt;li&gt;Click the browser back button&lt;br /&gt;Without any browser warnings you should end up on Page 2, where "foo" is still displayed as input from page 1&lt;/li&gt;&lt;li&gt;Right click the Back link on the page and do Open Link in New Window&lt;br /&gt;The new window should show Page 1 where "foo" is displayed in the input field&lt;/li&gt;&lt;li&gt;In the new window, enter "kit" (replacing "foo") and click Next&lt;br /&gt;You should end up on Page 2 where "kit" is displayed as input from page 1&lt;/li&gt;&lt;li&gt;In the new window, on Page 2 enter "kat" and click Next&lt;br /&gt;You should end up on Page 3 where "kit" and "kat" are displayed as input from the previous pages&lt;/li&gt;&lt;li&gt;In the original window, click the browser refresh button&lt;br /&gt;Without any browser warnings you should see Page 2 again with "foo" as input from page 1&lt;/li&gt;&lt;li&gt;In the original window, enter "bar" and click Next&lt;br /&gt;You should end up on Page 3 with "foo" and "bar" as input from previous pages&lt;/li&gt;&lt;li&gt;In the original window, click Finish&lt;br /&gt;You should end up on the start page of the application: the page flow has finished&lt;/li&gt;&lt;li&gt;In the original window, click the browser back button&lt;br /&gt;You should either receive an error immediately, or when you try to resubmit by clicking Finish again&lt;/li&gt;&lt;li&gt;(&lt;i&gt;For extra bonus points&lt;/i&gt;) In the new window, (where you still are on Page 3) click Finish&lt;br /&gt;You should receive an error of some sort (potentially a automatic page flow restart)&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;UPDATE&lt;/b&gt;: I've introduced a new step 11 in the above scenario, and what used to be step 11 is now step 12.&lt;br /&gt;&lt;br /&gt;The only extra rule to keep in mind is that the HTML forms should use POST, to follow proper web design rules.&lt;br /&gt;&lt;br /&gt;I've made reference implementations of the page flow challenge in Spring Web Flow 1 and 2. The source code is available in Subversion:&lt;br /&gt;&lt;br /&gt;Spring Web Flow 1: &lt;a href="https://svn.ervacon.com/public/spring/samples/trunk/pageflowchallenge-swf1/"&gt;https://svn.ervacon.com/public/spring/samples/trunk/pageflowchallenge-swf1/&lt;/a&gt;&lt;br /&gt;Spring Web Flow 2: &lt;a href="https://svn.ervacon.com/public/spring/samples/trunk/pageflowchallenge-swf2/"&gt;https://svn.ervacon.com/public/spring/samples/trunk/pageflowchallenge-swf2/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If you have &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; and &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt; installed, getting things up and running is as simple as:&lt;br /&gt;&lt;pre class="brush: bash;"&gt;$ svn export https://svn.ervacon.com/public/spring/samples/trunk/pageflowchallenge-swf2/ pageflowchallenge-swf2&lt;br /&gt;$ cd pageflowchallenge-swf2&lt;br /&gt;$ mvn jetty:run&lt;br /&gt;&lt;/pre&gt;You can now point your browser to &lt;tt&gt;http://localhost:8080/pageflowchallenge-swf2/&lt;/tt&gt; to test things out.&lt;br /&gt;&lt;br /&gt;This challenge is solely focussed on page flow functionality, so it's not meant to reflect on the quality of a particular framework in other areas. For instance, SWF1 and SWF2 handle this scenario flawlessly, but probably have a harder time dealing with some other use-cases.&lt;br /&gt;&lt;br /&gt;If you implemented the challenge in your web framework of choice, please let me know in the comments! I'm especially interested to see how &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt;, &lt;a href="http://www.seamframework.org/"&gt;Seam&lt;/a&gt;, &lt;a href="http://liftweb.net/"&gt;Lift&lt;/a&gt; and &lt;a href="http://code.google.com/webtoolkit/"&gt;GWT&lt;/a&gt; fare. If you think this is irrelevant for your web framework because it handles things differently, I'd love to learn why you think this is the case, and how a use-case like this would then be implemented.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-442670109494373211?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/442670109494373211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/page-flow-challenge.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/442670109494373211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/442670109494373211'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/page-flow-challenge.html' title='A Page Flow Challenge'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_4CDj2OINlFk/SwkPYP9qoUI/AAAAAAAAABQ/crzg5BwX4Rc/s72-c/flow.png' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-3030568637418608960</id><published>2009-11-14T10:24:00.002+01:00</published><updated>2009-11-17T13:30:40.760+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>The Role of Entities in DDD</title><content type='html'>In his famous book &lt;a href="http://domaindrivendesign.org/books/#DDD"&gt;Domain-Driven Design&lt;/a&gt;, Eric Evans defines entities as follows:&lt;br /&gt;&lt;blockquote&gt;An object defined primarily by its identity is called an ENTITY.&lt;br /&gt;&lt;/blockquote&gt;This implies that the primary responsibility of an entity is maintaining this thread of continuity, this &lt;b&gt;identity&lt;/b&gt;.&lt;br /&gt;Implementation wise, this is typically accomplished by using an &lt;a href="http://martinfowler.com/eaaCatalog/identityField.html"&gt;identity field&lt;/a&gt;, a 'primary key' field as it were. Here is an example using JPA annotations:&lt;br /&gt;&lt;pre class="brush: java;"&gt;@Entity&lt;br /&gt;@Table(name = "PERS")&lt;br /&gt;public class Person {&lt;br /&gt;&lt;br /&gt; @Id&lt;br /&gt; @Column(name = "ID")&lt;br /&gt; @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PERS_ID_SEQ")&lt;br /&gt; @SequenceGenerator(name = "PERS_ID_SEQ", sequenceName = "PERS_ID_SEQ", allocationSize = 20)&lt;br /&gt; private Long id;&lt;br /&gt;&lt;br /&gt; @Column(name = "NAME")&lt;br /&gt; private String name;&lt;br /&gt;&lt;br /&gt; @Column(name = "DOB")&lt;br /&gt; private Date dateOfBirth;&lt;br /&gt;&lt;br /&gt; public Long getId() {&lt;br /&gt;  return this.id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @SuppressWarnings("unused")&lt;br /&gt; private void setId(Long id) {&lt;br /&gt;  this.id = id;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String getName() {&lt;br /&gt;  return this.name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setName(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Date getDateOfBirth() {&lt;br /&gt;  return this.dateOfBirth;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void setDateOfBirth(Date dateOfBirth) {&lt;br /&gt;  this.dateOfBirth = dateOfBirth;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public String toString() {&lt;br /&gt;  return this.name;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Pretty straightforward code. Still, there's a lot of it and it will baloon quickly when you add more fields, constructors and serializability to the mix.&lt;br /&gt;&lt;br /&gt;Say that we need to determine in some part of the application whether or not a person is a minor. Naively, we could put an &lt;tt&gt;isMinor()&lt;/tt&gt; method on the &lt;tt&gt;Person&lt;/tt&gt; class. However, the fact of the matter is that the core responsibility of the &lt;tt&gt;Person&lt;/tt&gt; class is maintaining identity, and determining whether or not a person is a minor is not part of that responsibility. Futhermore, the size of the &lt;tt&gt;Person&lt;/tt&gt; class indicates that it's already plenty busy with it's core responsibility.&lt;br /&gt;&lt;br /&gt;Eric Evans also hints at this in his book: &lt;br /&gt;&lt;blockquote&gt;Rather than focusing on the attributes or even the behaviour, strip the ENTITY object's definition down to the most intrinsic characteristics, particularly those that identify it or are commonly used to find or match it.&lt;br /&gt;&lt;/blockquote&gt;It's better to factor the new behaviour into a separate class. One way of doing this that I particularly like is using &lt;i&gt;interpretation wrappers&lt;/i&gt;. Here's an example:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class InterpretedPerson() {&lt;br /&gt;&lt;br /&gt; private Person person;&lt;br /&gt;&lt;br /&gt; public InterpretedPerson(Person person) {&lt;br /&gt;  this.person = person;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public Person getPerson() {&lt;br /&gt;  return this.person;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public int getAge() {&lt;br /&gt;  // calculate the age based on person.getDateOfBirth()&lt;br /&gt;  // ...&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public boolean isMinor() {&lt;br /&gt;  return getAge() &lt; 18;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This class simply interprets the data available in a &lt;tt&gt;Person&lt;/tt&gt; entity, for instance using the &lt;tt&gt;dateOfBirth&lt;/tt&gt; property to determine whether or not the person is a minor.Seperating data interpretation from the underlying entities brings several advantages:&lt;ul&gt;&lt;li&gt;The entity classes remain focussed on identity and the associated attributes.&lt;/li&gt;&lt;li&gt;You can have several &lt;i&gt;interpretation wrappers&lt;/i&gt;, doing different kinds of interpretation (for instance, another part of the application might use another definition of what it means to be a &lt;i&gt;minor&lt;/i&gt;).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Responsibilities are properly factored.&lt;/li&gt;&lt;/ul&gt;The &lt;i&gt;interpretation wrapper&lt;/i&gt; is a useful little pattern that I haven't seen described elsewhere, so here you go!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-3030568637418608960?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/3030568637418608960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/role-of-entities-in-ddd.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3030568637418608960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3030568637418608960'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/role-of-entities-in-ddd.html' title='The Role of Entities in DDD'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-8650457483922767593</id><published>2009-11-07T21:10:00.007+01:00</published><updated>2009-11-21T10:13:56.867+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>On Testing and Refactoring</title><content type='html'>The last few days there was &lt;a href="http://www.joelonsoftware.com/items/2009/09/23.html"&gt;quite&lt;/a&gt; &lt;a href="http://blog.objectmentor.com/articles/2009/10/06/echoes-from-the-stone-age"&gt;a&lt;/a&gt; &lt;a href="http://beust.com/weblog/archives/000519.html"&gt;bit&lt;/a&gt; &lt;a href="http://blogs.msdn.com/cashto/archive/2009/03/31/it-s-ok-not-to-write-unit-tests.aspx"&gt;of&lt;/a&gt; &lt;a href="http://blog.objectmentor.com/articles/2009/11/05/its-ok-not-to-write-unit-tests-not"&gt;commotion&lt;/a&gt; in the blogosphere around unit testing, TDD and testing in general. (&lt;a href="http://www.infoq.com/news/2009/11/uncle-bob-tdd-applicability"&gt;InfoQ&lt;/a&gt; has some more background.) I don't want to get into that whole debate -- I'm a big fan of testing but I don't practice TDD religiously -- but I do want to touch on an interesting subject that came up: the way testing and refactoring relate.&lt;br /&gt;&lt;br /&gt;There is a bit of a dual relationship between testing and refactoring. On one hand, good test coverage allows you to refactor with confidence: the tests tell you whether or not you broke things. On the other hand, if the refactoring you want to execute has a large impact on the test suite, you're &lt;i&gt;held back&lt;/i&gt; in two ways: the extra work required to rework the tests, and the possibility of introducing bugs in the tests while reworking them, which reduces your refactoring confidence.&lt;br /&gt;&lt;br /&gt;On the project I'm currently working on we've tackled this in an interesting way (nothing novel but worth pointing out nonetheless): next to the normal unit tests, we also have a large suite of what we call &lt;b&gt;scenario tests&lt;/b&gt;. These scenario tests operate at a somewhat higher level and run against stable abstractions. Unlike unit tests they don't test isolated units of the application. Instead they test the system as an integrated whole and run real-life scenarios through it. However, the scenario tests are not really &lt;i&gt;integration tests&lt;/i&gt;: all environmental dependencies are mocked out making it possible to run these scenario tests as part of the normal test suite with every build.&lt;br /&gt;&lt;br /&gt;To make this a bit more tangible, lets consider a fictional event processing component:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class CalculatingEventProcessor implements EventProcessor {&lt;br /&gt;&lt;br /&gt;  private SomeCalculator calculator;&lt;br /&gt;  private SomeRepository repository;&lt;br /&gt;&lt;br /&gt;  ...&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public void process(Event event) {&lt;br /&gt;    if (weNeedToCalculateSomethingFor(event)) {&lt;br /&gt;      SomeObject input = extractSomeObjectFrom(event);&lt;br /&gt;      SomeOtherObject output = calculator.calculate(input);&lt;br /&gt;      repository.store(output);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Instead of simply having unit tests for the &lt;tt&gt;SomeCalculator&lt;/tt&gt; and &lt;tt&gt;SomeRepository&lt;/tt&gt; classes, we build scenario tests at the level of the &lt;tt&gt;EventProcessor&lt;/tt&gt; interface to verify that the correct things are calculated in the expected situations.&lt;br /&gt;&lt;pre  class="brush: java;"&gt;public interface EventProcessor {&lt;br /&gt;  void process(Event event);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Such a scenario test would look something like this:&lt;br /&gt;&lt;pre class="brush: java;"&gt;public class MyCalculationScenarioTest extends AbstractEventProcessorScenarioTest {&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public EventProcessor setupEventProcessor() {&lt;br /&gt;    return ...; // instantiate, or pull from a Spring app context, or ...&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public void runScenario() {&lt;br /&gt;    // setup data as required by the scenario&lt;br /&gt;    ...&lt;br /&gt;    &lt;br /&gt;    // create a relevant event&lt;br /&gt;    Event event = ...;&lt;br /&gt;&lt;br /&gt;    publishEvent(event);&lt;br /&gt;&lt;br /&gt;    // the test infrastructure will run the event through the event processor&lt;br /&gt;&lt;br /&gt;    // assert the necessary calculations have been done&lt;br /&gt;    ...&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Note that the above test sets up all required data, typically in a throw-away database like HSQLDB. This is necessary to make sure that the scenario test can be run as a normal unit test: independent of any other tests or its environment.&lt;br /&gt;&lt;br /&gt;It takes a bit of effort to setup the required scenario test infrastructure for your project, but the pay-off is big. Once you've got a sizeable set of scenario tests, you can refactor large parts of the internal design of your application without any impact on the scenario tests, which you can run at any time to see if things are moving in the right direction. The key here is the fact that the scenario tests run against a &lt;b&gt;stable abstraction&lt;/b&gt; such as the &lt;tt&gt;EventProcessor&lt;/tt&gt; interface in the example, which is unlikely to change.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE&lt;/b&gt;: It's worth pointing out that the scenario tests described above follow the basic form of a &lt;i&gt;scenario&lt;/i&gt; in &lt;a href="http://dannorth.net/introducing-bdd"&gt;BDD&lt;/a&gt; (Behaviour-Driven Development):&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Given&lt;/b&gt; some initial context (the givens),&lt;br /&gt;&lt;b&gt;When&lt;/b&gt; an event occurs,&lt;br /&gt;&lt;b&gt;then&lt;/b&gt; ensure some outcomes.&lt;br /&gt;&lt;br /&gt;In BDD scenarios serve as an executable specification: a set of executable acceptance criteria that become proper end-to-end functional tests. The scenario tests described here serve the exact same purpose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-8650457483922767593?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/8650457483922767593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/on-testing-and-refactoring.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8650457483922767593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8650457483922767593'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/on-testing-and-refactoring.html' title='On Testing and Refactoring'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-8419193310530253011</id><published>2009-11-02T16:05:00.005+01:00</published><updated>2009-11-02T20:01:36.098+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>Event Driven Architecture for Systems that Never Stop</title><content type='html'>&lt;a href="http://www.infoq.com/"&gt;InfoQ&lt;/a&gt; posted an excellent talk by Joe Armstrong (of Erlang fame) titled &lt;a href="http://www.infoq.com/presentations/Systems-that-Never-Stop-Joe-Armstrong"&gt;Systems that Never Stop (and Erlang)&lt;/a&gt;. Joe presents 6 laws that he sees as crucial to &lt;i&gt;systems that never stop&lt;/i&gt; (i.e. systems with &lt;i&gt;X nines of reliability&lt;/i&gt;): Isolation, Concurrency, Failure Detection, Fault Identification, Live Code Upgrade, and Stable Storage.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://en.wikipedia.org/wiki/Erlang_(programming_language)"&gt;Erlang&lt;/a&gt; language and runtime were designed for exactly this kind of environment so it comes as no surpise that it shines in all areas. However, it occurred to me that an &lt;a href="http://en.wikipedia.org/wiki/Event_Driven_Architecture"&gt;Event Driven Architecture&lt;/a&gt; goes a long way in building a system that never stops with more mainstream tools like Java and a relational database.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Isolation&lt;/b&gt;: Crashing of one process should not influence any other process, effectively isolating different processes. The big boon here is that this can really improve the reliability of your system: the probability of two independent processes failing is only half that of a single process failing.&lt;br /&gt;In an event driven world events are typically handled independently of one-another. Failure to process a particular event does not affect the processing of any other event in the system.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Concurrency&lt;/b&gt;: A runtime environment should not put any undue constraints on how far you can take concurrency, i.e. the number of threads or processes in your system. Designing a system with concurrency in mind allows you to take advantage of current day hardware (multi-cores and the like), but also goes hand in hand with the first law: independent, isolated processes can run concurrently without much problem.&lt;br /&gt;In an event driver system, multiple independent event processors can run concurrently on a single machine, taking advantage of all CPU cores available on the machine. Furthermore, event driven systems scale horizontally, allowing you to easily add additional machines with even more event processors.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Failure Detection&lt;/b&gt;: You must be able to detect when things go wrong, for instance by having a nanny like process that can monitor the system and can take appropriate action when failures occur. Furthermore, you should fail early, limiting the potential impact of the failure.&lt;br /&gt;In an event driven system you typically have failover handling that holds on to events that failed processing for later analysis or retry. One system property that Joe does not mention in his talk but is very relevant in this area is &lt;a href="http://en.wikipedia.org/wiki/Idempotence"&gt;idempotence&lt;/a&gt;: being able to retry things without affecting the final result. With some effort, idempotence comes naturally in an event driven system.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Fault Identification&lt;/b&gt;: If something has gone wrong, and you've detected it as per the previous law, you need to be able to identify what went wrong.&lt;br /&gt;Again, in event driven systems this comes naturally: the event that failed processing is normally maintained by the failover system, along with error messages and the like, and can easily be used to simulate what happened.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Life Code Upgrade&lt;/b&gt;: You shouldn't need to bring down your system for an upgrade. Whether or not this is important to you is of course very dependent of the application that you're writing. Still, if you have a cluster of event processors, you can upgrade them one by one, keeping the system live at all time. On a single machine you could use things like OSGi to attain similar results.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Stable Storage&lt;/b&gt;: This essentially boils down to having transactional (&lt;a href="http://en.wikipedia.org/wiki/ACID"&gt;ACID&lt;/a&gt;) storage available. In your average enterprise application this storage will be provided by an &lt;a href="http://en.wikipedia.org/wiki/RDBMS"&gt;RDBMS&lt;/a&gt; (Oracle, ...). Most current-day &lt;a href="http://en.wikipedia.org/wiki/Message-oriented_middleware"&gt;MOM&lt;/a&gt; solutions (MQ, ...) are also completely transactional, and even &lt;a href="http://en.wikipedia.org/wiki/X/Open_XA"&gt;XA&lt;/a&gt; aware. So there should be no need to ever loose any information in an event driven system build on top of these technologies.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So in all, an event driver architecture goes a long way in bringing you a system that never stops. This of course in stark contrast with batch systems, that have a hard time living up to a number of these laws.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-8419193310530253011?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/8419193310530253011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/event-driven-architecture-for-systems.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8419193310530253011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/8419193310530253011'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/event-driven-architecture-for-systems.html' title='Event Driven Architecture for Systems that Never Stop'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4869268408030448256.post-3102487554145551278</id><published>2009-11-01T08:12:00.000+01:00</published><updated>2009-11-01T08:16:09.849+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='general'/><title type='text'>Welcome!</title><content type='html'>I've been thinking about this for quite a while but I've finally decided to start blogging! Hopefully this will prove interesting, useful or entertaining to at least a few people.&lt;br /&gt;Welcome and enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4869268408030448256-3102487554145551278?l=ev9d9.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ev9d9.blogspot.com/feeds/3102487554145551278/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ev9d9.blogspot.com/2009/11/welcome.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3102487554145551278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4869268408030448256/posts/default/3102487554145551278'/><link rel='alternate' type='text/html' href='http://ev9d9.blogspot.com/2009/11/welcome.html' title='Welcome!'/><author><name>klr8</name><uri>http://www.blogger.com/profile/13417996252591392996</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_4CDj2OINlFk/TMxvJxIXzXI/AAAAAAAAACM/DApI30yyMMI/S220/erwin_vervaet_rect.jpg'/></author><thr:total>0</thr:total></entry></feed>
