After being dropped straight into working on production code, I spent the first day making a balls of a couple of servlets with my partner. The next day, we asked our boss-supervisor-mentor-guru guy (Alan) for a bit of guidance, upon which it became clear that we had indeed ballsed it up.
So Alan took us through a guided attempt at constructing a controller servlet with the test-first design approach, and handily enough, it seemed the right thing to create a few more controllers (one for each step of the interaction with the user).
Thus, we had a chance to immediately try this test-first design ourselves, unit testing and adding in functionality (and fixing various bits) to each controller and any new classes we built (a 'business object', or something - basically the class that handles the action, with the controller simply calling it with parameters extracted from the http request, then packaging the output and sending it on to the appropriate view). Note to self: Waffling on about this is helping my understanding!
Soon, our developing business object needed for us to modify the existing data access objects to do stuff in the database, which we did, uncovering a couple of bugs in the process (and a completely untested but crucial class, so we created a series of unit tests for it which, a bit disappointingly, all passed). We noticed that testing for equality between java.util.Date and java.sql.Timestamp objects isn't commutative (saving Date objects through hibernate into the postgres database seems to automatically pass them through a java.sql.Timestamp object, which loses the locale setting, or some other weird shit), and implemented a workaround by overloading an existing isEquals(Object, Object) method, providing an isEquals(Date, Date) method which converts the dates to longs (milliseconds since 1970), which seemed to compare correctly.
This change allowed our integration test on the DAO to pass nicely, and we went on to finish the controllers, then writing our UAT test to run through about 80% of the process, which works so far.
We'll build the final form-based element to the UAT tomorrow, hopefully - we've tested the stuff manually and it's looking fine, though.
I can't emphasise how much I've rapidly come to enjoy this test-first development style; not only does it help to clarify and simplify development and avoid bugs (by mocking dependencies as much as possible, so the responsibility can be deferred and individual elements can be unit-tested cleanly and the location of possible defects made easier to determine) - it's also extremely satisfying.