Reviving Agiledox

In a galaxy far, far away there was a tool that I really liked, but never pushed into my builds. Nevertheless, it changed the way that I thought about code, and how I thought about my tests.

That tool? Agiledox.

The idea is simple: a class under test ("Foo") is normally tested in a class that's named after the class under test ("FooTest"). If the test names reflect roles and responsibilities, we can automatically generate documentation. The way to do this is to take the test names, strip the word "test" from them and un-camelcase the names. That is:

public class FooTest extends TestCase {
  public void testShouldDoThis() {}
  public void testShouldDoThat() {}
  public void testOnTuesdayShouldMeltdown() {}
}

becomes:

Foo

  • Should do this
  • Should do that
  • On tuesday should Mmeltdown

Now, the twist is that there's something missing here: an explanation as to why the Foo class was written in the first case. The class under test sometimes contains a meaningful top-level javadoc. It makes sense to drag that in too.

Voila! Documentation!

Docs on their own are pretty meaningless, but I like the fact that this is a handy way to drive a conversation about OO design, testability and code quality.


Simon Stewart on Tuesday, 31 March, 2009

Posted in: /tech

Leave This Place Alone for Three Minutes

Well, it's been seven days, and I'm now back from holiday and plugged into the Net again. Looks like it was a big week: IE 8 was released, as was Street View in the UK (finally!), IBM is in talks to buy Sun (for Java and the consultancy revenue it generates, presumably?) and Battlestar Galactica comes to an end (though it's still not available on itunes yet, so no spoilers please!)

Perhaps I should take some time out more frequently?


Simon Stewart on Sunday, 22 March, 2009

Posted in: /play /tech

WebDriver Release

Just a quick blog post: there's a new WebDriver release out. The files are on the Google Code site. Features include:

  • New IE driver (based on JNA rather than JNI)
  • First release of the remote webdriver (though I should really build a WAR of the server-side :)
  • Improved handling of profiles in Firefox
  • Numerous bug fixes

Woot! The next release should be a clean up release, rolling through our open issues and closing as many as we can.


Simon Stewart on Thursday, 12 March, 2009

Posted in: /tech/webdriver

WebDriver Tips: SELECTs

One of the hidden gems of webdriver is the support library. This contains useful classes and utilities for dealing with common situations and cases. We recently checked in a wrapper for SELECT elements. Beforehand, interacting with a SELECT could be a little verbose:

WebElement select = driver.findElement(By.tagName("select"));
List<WebElement> options = select.findElements(By.tagName("option);
for (WebElement option : options) {
  if ("want this".equals(option.getValue()) {
    option.setSelected();
    break;
  }
}

With the Select support class, this becomes:

Select element = driver.findElement(By.tagName("select"));
Select select = new Select(element);
select.selectByValue("want this");

This does the same job, but someone reading your test can now gather the intent that little bit more easily.

The Select class will be made more widely available when do our next release, hopefully near the end of this month.


Simon Stewart on Thursday, 19 February, 2009

Posted in: /tech/webdriver

Portakabins

Portakabins are wonderful things. Temporary buildings that are designed to fill a certain need, but only for a well defined period. They are also terrible things: they're "good enough" to the point where people sometimes use for far too long, despite the fact that as permanent accommodation a properly designed building is far better.

Of course, there's a software development analogy in here. Teams often throw in a temporary fix to a problem that's "good enough" for now. Life would be a lot more pleasant if the job was done properly, but perhaps the team is bridging to a new architecture, or time pressures mean that as long as "this code-path here" works fine then it's okay.

The problems start when that portakabin is never removed --- who has time to go back and clean up things that are working? Someone comes along, looks at this thing that was created as temporary hack and decides that, actually, yes, that is how code should be written. Oh! The pain of Example Driven Development! Suddenly, what should have been a quick fix turns out to be how things are done.

Perhaps this explains my visceral dislike of seeing temporary hacks being thrown into a code base; we're just saving up long term pain at the cost of doing something we're not happy with today. Reminds of the saying "Of course a shortcut takes more effort. If it didn't it wouldn't be a shortcut, it would The Way"


Simon Stewart on Saturday, 07 February, 2009

Posted in: /tech

Open Source Libraries: Forking Forever

You've maintained a temporary fork of a library for a while, but you need to ship your product to external customers, or the developers of the library aren't interested in your fixes, or you're just feel that what you'd like to do most with your precious free time is to maintain a library.

The only decent thing to do is make the fork permanent.

There's a whole bunch of choices to make here, but they all start with the same action: changing the package name. Unless you're officially taking a project over, this single action means that other teams can make a reasoned choice about migrating from the original version to yours. It also means that as your fork and the original diverge teams don't have to fight about which library they should be using.

If you're forking so that you can ship a product or project, then changing the package name decouples your project from the forked library's release schedule: you become free to ship with snapshots with your fixes applied. If you're forking because the underlying library has some major issue that's not being properly addressed, you put yourself in a great position to open that project up to other contributors and allow yourself the freedom to change APIs as you see fit. Lovely.

Actually, the case where you're forking to allow your product to be released is an interesting one. It's similar to the case where you want a temporary fork, in that you probably want to continue tracking the current HEAD release so that you can fall back to the original library as soon as possible. In this case, the best thing to do is to automate the package renaming; write a script that does the grunt work of renaming the packages. You can then hook it into the process described in my previous post, meaning that you have the advantages of your own private world with the opportunity to fall back to the original library when necessary.

Which is nice.


Simon Stewart on Sunday, 01 February, 2009

Posted in: /tech

Open Source Libraries: Handling a Fork

So, you've finally run into a situation where you want to upgrade one of your project's dependencies but one of your other dependencies prevents you from doing so. In the ideal world, things would just work seamlessly, and you could just grab the latest version, but sometimes life's just not like that.

Oh well. Time to fork that library!

Before we begin, we have a choice to make: is this a temporary thing, or are we never planning to return from whence we came? It's extremely unlikely that you're actually interested in maintaining your own fork of a library indefinitely, so let's work our way through a temporary parting of the ways. Life is made simpler because there's probably just a few things that are wrong or need changing and we'd be pleased to roll back to the original library once those small issues are fixed. Everything should centre on allowing us to get back to the ideal situation.

The first step when forking is to write a failing test that exposes the missing functionality. Maybe this test is just "when I new up this object, the constructor throws an exception". Maybe it's "when this method is called, the wrong value is returned" Whatever it is, encapsulate it, because once this test passes with a later version of the original library we're going to drop our fork. Write a test per feature of bug that you're planning on adding or fixing.

Until then, we're going to need the source. Check it out from the project's source repository. If you can't do that, figure out how to get the source. You're going to need it, because the next thing to do is to fix a single failing test. Not all of them. Not five of them in one go. One failing test. Create a patch between the original source and the version that causes your test to pass. Keep that patch under your source control system, next to the library. Now repeat the process for each failing test. This way, there's a patch per feature of bug.

The reason for doing this becomes clear when we upgrade the library. The process becomes:

  • Check out the new version of the library source
  • Run your tests. Delete the patches associated with any passing tests.
  • If you have no patches to apply, delete your fork!
  • Apply your patches, one at a time. Run the associated test until it passes. You may need to "freshen the patch" once you're done.
  • Rinse and repeat for each failing test

Taking a step back, the whole process boils down to three steps:

  1. Identify what's wrong
  2. Automate proving that it's wrong.
  3. Fix the problem and maintain the delta.

As part of being a "good citizen", and to minimise the amount of time that your forked version of the library exists for, send the failing test and the fix to the project owner.

But what would we do if we want to ship with a forked library? Or what happens when your differences are too great? That, dear reader, will be what the next post is about....


Simon Stewart on Sunday, 01 February, 2009

Posted in: /tech

Pettiest Joke of the Day

The Killers? Are they human? Or are they dancers?

I've seen the video. They're human. They're not dancers. Though that coat was once part bird.


Simon Stewart on Thursday, 29 January, 2009

Posted in: /play

Open Source Libraries: What Not to Do

How hard can it be to use an Open Source java library in your project? I mean, all you need to do is drag the JAR on to your CLASSPATH and your done. Oh right, yeah, fine. You need the dependencies too. And the dependencies of any dependencies. And so on.

But I mean, it's not hard is it?

Certainly not to start with. But then there's a new version of the library that you could use. And it deletes an API you use. Or you're not sure whether it'll work properly. Or it's a bad day to upgrade the entire codebase. Or you have no idea whether something will work or not. So what do you do? What do you do?

Don't do this: have a second copy of the library in your source tree. That's dumb. That's dumb because you're depending on classpath ordering, which may or may not happen consistently.

Which means that you need to have only one copy in your source tree at any one time. This also means that if you need the latest and greatest feature from a library, you're effectively becoming something like the Apache Gump, and sometimes something's not going to play well with something else. That's when it gets fun. That's what I'll cover tomorrow....


Simon Stewart on Wednesday, 28 January, 2009

Posted in: /tech

Getting the Ball Rolling

Well, I fell off the blogging wagon quite hard. Time to get the ball rolling again. They say the best way to get back into the swing of things is to practice, so let's see if I can manage a post a day for the rest of the week.

Until the weekend.

No point aiming too high!

Now, where to start....


Simon Stewart on Tuesday, 27 January, 2009

Posted in: /play

Older posts: 1 2 3 ... 42

Categories