September 13th, 2007

fuck code

With these ropes I tied can we do no wrong?

Last week I did a big refactor of some Java code, massively simplifying the flow and making things clearer, faster, more extensible and more secure. In general I'm hugely happy with it and I'm also pretty happy with my Java. It was a long time ago when I last did Java professionally and so this past year I've always been a bit wary that my code wasn't idiomatic.

Idiomatic code, like patterns, is interesting. Sometimes brevity or whatever can and ought to be sacrificed for clarity. If nothing else then idiomatic code makes the next maintainer's job easier. And that could well be you. Remember, you always code for three people - you now, you in the future and the person who comes after you. And idiomatic code tends to integrate better with with external libraries (as long as they're largely idiomatic of course). Plus, they're usually idioms for a reason.

So, the first cut at refactoring went incredibly quickly and I excised all the old baroque, rotten code that had built up as new wrinkles in underlying libraries came up and as old assumptions had been discredited and new requirements had come up. Not that the old code was bad it just needed a spring clean and a new wardrobe.

I then rebuilt the functionality in a much saner way working to a general plan in my head and filling in the details as I went along. That went incredibly quickly - I had working code by the end of the first day and had filled out the details by the end of the second day. All in all, about a 5000 line diff.

So far so good.

Then I took a step back, sketched my class diagram on a white board and started thinking about making things more idiomatic. And in Java that means Interfaces. To paraphrase The Rhyme of the Ancient Mariner - "Interfaces everywhere and all the compilers did shrink. Interfaces everywhere and not a drop to drink. Because they're doing my head in and I have a powerful thirst for some alcohol".

The debate about multiple-inheritance versus interfaces has been done to death elsewhere and by better, wiser and more scarily obsessive people than me. I've come across a few occasions when I could really have done with multiple inheritance but mostly I've been able to work around it and I can understand the arguments against it so we'll just leave it at that.

But I'm beginning to wonder if I made a mistake. Should I just have left it at the old code with the leaky abstractions? Has separating it out into interfaces tricked me into over engineering things, made me jump through conceptual hoops which, whilst correct in a very 'pure' way have actually made things worse.

A while back I was talking with someone about writing a book - "Java for Scripting Language Programmers". One of the things we talked about was the fact that programmers who are frolicking in a language which isn't their normal one will find warts that habitual users of the language never come across, in much the same way that a user can find a bug in 30 seconds that the programmer of an app hasn't come across in 6 months of testing - there's an underlying conceptual model and you instinctively steer away from doing stuff wrong "The bug happened because they tried to add a Frob to a Bleep! Why would they ever do that?!"[1]

In short I'm wondering if my issue is because I'm trying to program Java like Perl. Or I expect Java to be like Perl and then get upset when it's not.

Or maybe it's just that Bondage and Discipline languages are just annoying (although Piers Cawley once remarked "Perl let's you program in a Bondage and Discipline style ... it just lets you have safe words".

I've often thought that programming is like Architecture - it's not for nothing that we stole the concept of a pattern language off Christopher Alexander's books "The Timeless Way of Building" and "A Pattern Language . Building a whole system is like building an estate with roads and parks and shops and places to live. You need some discipline because otherwise people just swarm everywhere and it's annoying to get everywhere but, ideally, adding new functionality in the form of a new building or communal area should be an easy task with an obvious course of action.

However if the system is irritating to use you start getting ugly brown marks across the middle of your parks as people take short cuts across the grass. Sure you can then pave that path to prevent further damage but that screws up your design aesthetic and really it should have been obvious that was going to happen and the situation should have been dealt with in advance.

In short I think you should accept that your users are going to occasionally want to do stuff that you never dreamed that they'd want to do. Or that occasionally breaking the rules will be necessary and should be prepared to deal with that. Give the programmer a mechanism to do it and at least let them know what the consequences are. More than once I've had to do
    #define private public
    #include <somelibrary.h>
which is obviously bad and wrong and has horrific long term consequences. Much nicer if I could that within a tight scope in much the same way Perl allows you to do
         no strict 'refs';
         *$sub_name = sub { print "Hello World\n" };
In short, trust the programmer and let him, her or it have enough rope to shoot themselves in the foot if they really want to. They may have a damn good reason and it's not up to you to second guess them, only to give them a warning then let them get on their merry way when they brush you aside.

Actually, what I should be doing is finishing off this code instead of procrastinating about it on LJ. But there you go.

[1]Apparently it's not uncommon for tourists to blunder into riots happening in cities whereas natives subconciously stay away, warned off by environmental clues. A little trivia for you there. Read "Sources of Power" by Gary Klein. It's really good.