From Best to Good - Re-evaluate your practices again

Posted by Pål Brattberg on June 5th, 2008

When looking to improve your work environment or pushing to use a new method, it’s not uncommon to go looking for what might be considered Best Practice in that area. It’s as natural and common as it is problematic and dangerous.

First of all, the very notion of a Best Practice is that there is some way of performing a task or method that is superior to all other possible ways of performing that task or method. It is also suggested that the practice is superior in all aspects, meaning it delivers the most value and costs the least resources (if applicable).

So, what’s the problem with wanting to find, and ultimately putting to use, best practices? Wouldn’t it be a great thing if we could find more best practices and let all interested parties in the world share as many best practices as possible? In theory; yes. In practice; no thanks.

The problem with many things marketed as best practices is that it’s not. It is extraordinarily uncommon for a technique och method to be so absolutely, overwhelmingly better than all other ways in which you could perform a task that it could be declared a true and undisputed Best Practice. That’s not to say there aren’t any Best Practices, I’m believe there are at least a few lurking about in this great universe of ours, it’s just that they’re not so common as we would think.

Take the field I’m working in (and probably you as well, since you’re stuck reading this): IT. Software Development. What’s the best way to develop software? What’s the best way to handle source code? What’s the best way to make sure we stay on track, do the right thing and always deliver maximum business value for the least amount of resources while boosting the user and developer experience and maximizing shareholder profits? Please let me know the best practice for that! No really, please do!

The obvious answer is that IT is a way to complex field to have any large, powerful Best Practices that all can agree upon. If you don’t agree, tell me the best computer language the world agreed upon. Or the best web framework. The catch being here that different people and organizations have different best practices, which serves to make them anything but unequivocally best. Of course, there is no single best computer language or web framework that is best for all cases.

So, if best practices are super-rare, bordering on non-existant, what should we do when we want to know how people smarter than us have solved a recurring problem we have just faced? We should do like other industries, look for Good Practices. In many industries there are several agreed upon Good Practices that form the basis for making sure we do not all spend obscene amount of times reinventing an inferior wheel.

Focusing on Good Practices instead of the mythical Best Practices has many benefits: A practice that has proven to work in a good fashion for a team doesn not have the burden of proof as to wether it is also the absolute best practice concievable meaning there should be more good practices to choose from. As there are many, competing good practices you are encouraged to constantly inspect, adapt and revise any decisions to go with any particular practice, which is great since that causes you to pay ongoing attention to how you work and how your practices are working for your particular environment and people. Focusing on good practices also removes the stigma of trying on a Best Practice and finding it doesn’t deliver for your needs. If it truly was best, you must be doing something wrong. If the practice you tried was merely good, you can just keep looking or adapting the practice.

To round up: stop looking for Best Practices and embrace imperfection and ongoing improvement by going for Good Practices. I’ll follow this up by posting some good practices I’ve used in projects over the following months. Stay tuned!

Initial Derby-support in DbFit

Posted by Pål Brattberg on May 30th, 2008

DbFit does heavy lifting!This just in: you can now run FitNesse tests with DbFit using Derby/JavaDB as your database of choice.

Have a go and download it from Subversion here: https://dbfit.svn.sourceforge.net/svnroot/dbfit/dbfit/dist/dbfit-20080530.jar

It’s not terribly complete which you can tell from the limited set of acceptance tests available, but it works for the basic cases.

Notable omission: Stored Procedures. My current project doesn’t need it so it’s not yet implemented.

If you are missing something, let me know and I will add it. (To get it fixed fast, also supply a failing DbFit-test case.

JtestR 0.2 out now

Posted by Pål Brattberg on April 17th, 2008

Ola Bini+friends’ cool tool, JtestR has just been released in a 0.2 release that adds some nice features and fixes a few bugs as well.

JtestR, for those of you who haven’t heard about it yet, is a tool to enable testing of java code using alot of the cool ruby tools available for testing such as rspec, test/unit and more.

As if that wasn’t enough, it’s also integrated nicely with Ant and Maven and can also run your existing junit and testng tests.

Any day now I’ll try to find some time to put together a post on my experiences with using ruby to test java code. But for now, go take a look at jtestr!

Painless backups - solved for now

Posted by Pål Brattberg on March 6th, 2008

If you’re anything like me, you’ve dabbled in various solutions for your personal (and professional) backup of data. Being the geek that I am, these are some of the different solutions I have used in the past:

  • External harddrive (on my fifth (!) drive now, they keep crashing)
  • CD/DVD-backups (takes time and they’re fragile)
  • Extra internal drive (What was I thinking? Hacker’s paradise)
  • External server with plenty of storage space (Setup my own with 750 GB RAID’ed; linux, rsync, ssh, cron and all that jazz. But it also gets hacked…)
  • Flickr.com Pro (Good for my photos, but what about the rest?)
  • Cheap web hosting (Yeah, this works, although a bit unreliable, and messy to FTP every now and then)

So, I was thinking it was time for something new, something that doesn’t bother me and something that just works, automagically. What I’m using right now, and have been using for some months, is Mozy. It’s a service owned by EMC and it’s a no-frills automatic backup tool.

It has clients for Windows and Mac (found none for Linux yet) and just works. I has all the stuff I want such as encryption, incremental, block-level syncing, support for several computers on one account etc.

There’s a free version which I suggest you start with, to see if the program and service suits you (you get 2 GB for life) and the full version is about $5 / month for unlimited storage. I think it beats my other solutions and about the only other thing I would like now, is to have the client backup to both Mozy and Amazon S3 (for the paranoid person lurking inside me), but I’ll wait a bit for the S3-part. (There’s plenty of tools for doing just that though)

I’m not one to spam, but if you would like to try Mozy and get 256 MB extra, feel free to use this link. By using that link, I also get some extra love from Mozy.  On the other hand, if you don’t like me, just go to https://mozy.com/ and spare me the love! ;)

Manually adding MD5 checksum to files using Ant

Posted by Pål Brattberg on March 5th, 2008

I just added some JAR’s from the DctmUtils project to my local Maven repository to be able to use it like anyother dependency. In doing so I had to create a POM and the structure for the JAR. This in itself works like a charm, but if you do not supply valid checksum-files (SHA1 or MD5) for the POM and JAR Maven 2 will give you warnings.

Solution:
Save the following in a build.xml file in your folder and run ant md5 to generate MD5-files for all files in the folder. Easy peasy.

<project>
  <target name="md5">
    <checksum forceOverwrite="yes" fileext=".md5">
      <fileset dir="." excludes="**/*.md5"/>
    </checksum>
  </target>
</project>

Getting a handle on custom WebTop components using Spring

Posted by Pål Brattberg on March 2nd, 2008

When customizing an EMC Documentum WebTop application and using the Spring Framework to tie everything together, you find yourself wishing you could use Dependency Injection at all places in the existing WebTop source.

I don’t yet know of a workable way to achive that sort of plumbing with a WebTop application (especially for all types of existing components and tags) to just expose any new dependencies and let Spring handle it all.

Another way to achive interoperability with Spring and still use most of what’s good there is to allow our legacy components to have access to a Spring ApplicationContext, but setting one using Spring is not feasible because of the same reasons as above. Thus we introduce the StaticSpringApplicationContext.

The StaticSpringApplicationContext works simply by containing a static reference to the Spring ApplicationContext and exposing a static helper method to get beans configured by Spring.

Configure the helper class by defining it in your web.xml like so:

<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

And at least the following in your WEB-INF/applicationContext.xml file:

<bean id="StaticSpringApplicationContext" 
  class="com.palbrattberg.spring.StaticSpringApplicationContext" />

This will make sure Spring itself configures the StaticSpringApplicationContext on startup.

Now you can simply get your configured beans (preferably in your constructor) like this:

MyBean myBean = (MyBean) StaticSpringApplicationContext.getBean("myBean");

Now you are free to use Spring for configuring all your future code.

Source code for StaticSpringApplicationContext

Problems with JUnit 4 tests with Spring 2.5.1 and Maven

Posted by Pål Brattberg on February 19th, 2008

I recently upgraded one the projects I’m working on to Spring 2.5.1 and at the same time decided to start using JUnit 4 for that same project. We use Maven and so a simple change to pom.xml makes it reality. However, I encountered troubles:

-------------------------------------------------------------------------------
Test set: com.acando.zircon.unit.core.test.dctm.AbstractTestCaseJunit4Test
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.031 sec <<< FAILURE!
initializationError0(com.acando.zircon.unit.core.test.dctm.AbstractTestCaseJunit4Test) Time elapsed: 0.016 sec <<< ERROR!
java.lang.NoSuchMethodError: org.springframework.core.annotation.AnnotationUtils.findAnnotationDeclaringClass(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Class;
at org.springframework.test.context.TestContext.retrieveContextLocations(TestContext.java:159)
at org.springframework.test.context.TestContext.(TestContext.java:115)
at org.springframework.test.context.TestContextManager.(TestContextManager.java:107)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:107)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.(SpringJUnit4ClassRunner.java:79)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.junit.internal.requests.ClassRequest.buildRunner(ClassRequest.java:33)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:28)
at org.apache.maven.surefire.junit4.JUnit4TestSet.(JUnit4TestSet.java:45)
at org.apache.maven.surefire.junit4.JUnit4DirectoryTestSuite.createTestSet(JUnit4DirectoryTestSuite.java:56)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.locateTestSets(AbstractDirectoryTestSuite.java:96)
at org.apache.maven.surefire.Surefire.createSuiteFromDefinition(Surefire.java:209)
at org.apache.maven.surefire.Surefire.run(Surefire.java:156)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)

Another error I got when trying to fix this was:

[INFO] ————————————————————————
[ERROR] BUILD FAILURE
[INFO] ————————————————————————
[INFO] Compilation failure
C:\Work\WS\zircon-core-dctm\src\main\java\com\acando\zircon\core\test\dctm\AbstractTestCaseJunit4.java:[13,39] package org.springframework.test.context does not exist
C:\Work\WS\zircon-core-dctm\src\main\java\com\acando\zircon\core\test\dctm\AbstractTestCaseJunit4.java:[14,46] package org.springframework.test.context.junit4 does not exist
C:\Work\WS\zircon-core-dctm\src\main\java\com\acando\zircon\core\test\dctm\AbstractTestCaseJunit4.java:[15,46] package org.springframework.test.context.junit4 does not exist
C:\Work\WS\zircon-core-dctm\src\main\java\com\acando\zircon\core\test\dctm\AbstractTestCaseJunit4.java:[33,53] cannot find symbol
symbol: class AbstractJUnit4SpringContextTests
public abstract class AbstractTestCaseJunit4 extends AbstractJUnit4SpringContextTests {
C:\Work\WS\zircon-core-dctm\src\main\java\com\acando\zircon\core\test\dctm\AbstractTestCaseJunit4.java:[32,1] cannot find symbol
symbol: class ContextConfiguration
@ContextConfiguration(locations = { “classpath:/zircon-core-dctm-defaultConfig.xml”, “classpath:/spring-testConfig.xml” })
C:\Work\WS\zircon-core-dctm\src\main\java\com\acando\zircon\core\test\dctm\AbstractTestCaseJunit4.java:[31,9] cannot find symbol
symbol: class SpringJUnit4ClassRunner
@RunWith(SpringJUnit4ClassRunner.class)

These errors seem to indicate an older version of Spring in my classpath, and to track it down I removed all the Spring jars from my ~.m2/repository folder and ran mvn clean test again.

Aha! Some dependancy still downloads Spring 2.0.7 which in turns comes before my dependancy on Spring 2.5.1. Turns out it was the spring-oxm-tiger version 1.0.3 dependancy from Spring Web Services’ (spring-ws) project that bit me. I could now either exclude that transitive dependancy to Spring or look for a newer version with support for Spring 2.5.

Looked at the Spring WS download page and saw 1.5.0-m2 as the latest version but this version is not available at the default Maven repository, instead only at the Spring milestone repository that you connect to by adding the following to your pom.xml:

<repositories>
<repository>
<id>spring-milestone</id>
<name>Spring Milestone Repository</name>
<url>http://s3.amazonaws.com/maven.springframework.org/milestone</url>
</repository>
</repositories>

The dependency to spring-oxm looks like this:

<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-oxm-tiger</artifactId>
<version>1.5.0-m2</version>
</dependency>

A simple mvn clean test will now make your project smile again I hope!

Using JadClipse when developing with closed source dependencies considered required

Posted by Pål Brattberg on February 13th, 2008

This is so required to keep your sanity while working with any closed source, third party dependancies like I’m doing right now, with EMC Documentum’s WebTop.

You may already be familiar with JAD, the fast JAva Decompiler, which is great to check the source of those pesky no-source JAR files that pollute your CLASSPATH. A typical pattern to enable debugging has been to decompile those binary, class-file only dependancies and add the corresponding Java source files to your CLASSPATH instead, thereby making it way easier to debug.

Now, with JadClipse dancing around inside my Eclipse, this is done on the fly. Now I simple mark my dependancy, press F3 and Jad decompiles the class and let’s me look at the code right away. Oh sweet joy.

Minor gripe: no update site for JadClipse, but it seems I’m not alone in this, so here are the sites for Eclipse 3.2 and 3.3:

  • http://webobjects.mdimension.com/jadclipse/3.2
  • http://webobjects.mdimension.com/jadclipse/3.3

Documentum broke my Ant build!

Posted by Pål Brattberg on January 3rd, 2008

Hi there and happy new year!

This nasty error kept biting me when I tried to run my old ant files:

BUILD FAILED
java.lang.NoSuchMethodError: org.apache.tools.ant.util.FileUtils.getFileUtils()Lorg/apache/tools/ant/util/FileUtils;

A quick google lets me know this is because of an old version of ant, so I download Ant 1.7.0, make sure to replace my old version, make sure to set ANT_HOME, and make sure ANT_HOME/bin is first in my PATH.

So, then why does ant -version say 1.6.2?!

Hmm, maybe corrupt download I think, so I try a few different mirrors, all bad.

Hmm, maybe bad release, I check the bugzilla. No bugs on this.

Hmm, let's try 1.6.5. Downloaded. Installed.

ant -version? 1.6.2 core, 1.6.5 optional tasks! doh!

Turns out, my recent installation of Documentum Application Builder 6 added a few nice JARs to my PATH (yay!) and those were wreaking havoc on my machine. For now, I've moved the ant*.jar files away from my C:\Program Files\Documentum\Shared folder and things seem ok. Lets see if Documentum will bring the hate soon.

image_science not found using attachment_fu on Windows

Posted by Pål Brattberg on September 12th, 2007

I’m using the attachment_fu plugin for Ruby on Rails for a project I’m working on and the plugin works just great on the test and deployment platform using GNU/Linux (Fedora) but I had some troubles getting it to play nicely on my Windows workstation (yeah, yeah, I should get a Mac, and can’t we all just get along? …).

The problem I had was with the ImageScience processor which just doesn’t like the line: require 'image_science'

Fix is easy enough, edit vendor/plugins/attachment_fu/ lib/technoweenie/attachment_fu/ processors/image_science_processor.rb by replacing require 'image_science' with

if RUBY_PLATFORM =~ /mswin32/
  require 'imagescience'
else
  require 'image_science'
end

Copyright © 2007 Bits and bites from Pål Brattberg. All rights reserved.