« RDF, meet SmartFrog | Main | C# code conventions I'll be breaking for the time being »

Seven more ways to improve legacy Java

After reading Robert Simmons article on O'Reilly and the sample online chapter, I'll definitely be buying Hardcore Java. I don't agree with everything he says, but I like the way he thinks about dealing with existing code:

Use a Stronger Compiler for Your Code

What I read came across more as "use Eclipse or IDEA", which is fine ;) The example given could be caught with unit tests or even better with a field prefixing convention (instead of the this keyword):

public class SomeClass {
    private String itsSomeValue;
    public SomeClass(final String someValue) {
        itsSomeValue = someValue;
    }
    public void setFirstName(final String value) {
        itsSomeValue = itsSomeValue ;
    }
}

My convention is to use 'its' for fields and 'the' for statics (some folks use 'my'). I've never managed to self-assign a field. Just look at the code above - it's not hard to spot the problem. This also has the advantage that accessing object fields directly looks painfully stupid (as it should). I believe some folks deal with this issue by only accessing internally through get/sets.

However, if your developers depend on diffs instead of code documentation to determine problems, then you probably already have a serious problem in your code base.

No, documentation isn't worth that much in legacy code - I'd consider taking it too seriously as a project risk. Diffs are worth more. Behaviour is worth more again. We have problems when the tests don't pass after checkin, not whether we're leveraging documentation.

Remove Commented-Out Code

Absolutely. But we should ask why that comment is being left there at all. Blocks of commented-out code can be a sign that version control isn't being used well.

Replace Listeners with Weak Listeners

Ok. A problem I've seen with Listeners is thread safety, not so much GC. I tend to replace listeners with queues (but this might not be practical in Swing code).

So here are seven other ways to improve legacy code, some of which are not so cheap (think of them as investments ;):

  1. Get the build under control. Owning the build is job number one. "Builds in my IDE" doesn't count. Use ant or makefile to build code, not an IDE. Once we've got the build down, then we can start levaraging the IDE, but the build process has to be IDE independent. Dysfunctional build and deployment processes are a good way to derail legacy maintainance projects.
  2. Do a one time reformat over the class and check in. Thereafter stick with that format. Most time spent with legacy code is spent reading it, so make this comfortable.
  3. Prefix fields. See above for an idiom that works.

  4. Buy a copy of Martin Fowler's Refactoring. Buy two copies, and read both of them. It's Money well spent. Refactoring has a list of techniques that can help get the structure of the code under control before we start changing behaviour. As important as the techniques, are the discipline and shared vocabulary this will bring.
  5. Search the code for empty catch blocks. Get them them to output something. But we need to be careful about getting them to throw on the production system until the consequences of doing so are understood.
  6. Start taking version control seriously. The biggest mistake we can make with version control is to treat as a glorified backup system - it's not called backup control for a reason. Version control, used well, is there to help us manage change, not just to have a place to dump the source code. Build a habit of frequent checkins and updates - keep checkins small - you're doing it right when comments seem superfluous.
  7. Add unit tests. This is especially important when upgrading legacy systems that have no regression tests. There are two approaches here. We can do this against the existing code base first to capture its actual behaviour, on the basis that what a functioning production system is supposed to do is another matter again to what it actually does (which also gets the nub of the issue with taking comments seriously - comments don't execute). But if we have clear requirements for new behaviour we can think about capturing that in tests instead and working to make the code pass them - we'll go faster of course - but if the code base is shall we say, intricate, this won't help with the non-local bugs we introduce, however unintentional :)


May 3, 2004 04:04 PM

Comments

Keith Sader
(May 4, 2004 07:35 PM #)

/me nods head vigorously to most all points.

As a self-proclaimed 'software mechanic', I've done the things you suggest with alarming regularity. I don't particularly condone #3, but that's my own personal goulash phobia :-)

The other thing one might do is to search for all the catch(Exception e) blocks and remove them.

On #6 I started the local mantra of 'If it's not in it doesn't exist!' We had way to many cases of 'This code is over on this machine.'

Bill de hra
(May 4, 2004 08:52 PM #)

"The other thing one might do is to search for all the catch(Exception e) blocks and remove them."

Ah, yes; very good idea.

Randy Charles Morin
(May 7, 2004 11:47 PM #)

Legacy Java? I feel old.

keith ray
(May 8, 2004 02:50 PM #)

Good advice.

I would add "review the code with someone else" and "write some unit tests if the code doesn't have any or doesn't have enough".

Trackback Pings

TrackBack URL for this entry:
http://www.dehora.net/mt/mt-tb.cgi/1286