Doing it right can mean doing it wrong

Relax. Good code comes to those who wait.

4 minute read


I’ve found that one of the best ways to describe how it feels to be doing software development properly is that it’s like a continuous unclenching of the buttocks.

There’s a wondrous sense of sphincter-release when you realise that doing it well means mostly doing all the things that got you to fall in love with it in the first place. In essence, you are free to kick back and get on with the job of making good, working, extensible, lovely-looking code - as long as you constantly carry a syringe loaded with reality-juice, to be taken at regular intervals. That dose of reality requires only that you admit that good, working, extensible, lovely-looking code is part the end result, and not always the immediate aim.

It goes a bit pear-shaped when you get to thinking all strategic and enterprise, and not enough tactical and immediate.

Even on the biggest projects, you don’t need a complex IDE, tediously prescriptive requirements, a plan that itemises every hour of your life, micro-management, endless reports and metrics, performance related bonuses, etc. You might have to suffer them, but you don’t need them. What you do need is to replicate, in a group environment, all the characteristics of how you would work on your own thing, on your own.

Remember when software was fun? And you didn’t tense up wondering whether your dependency injections were far reaching enough, or whether your factory patterns were so widely applied that in nine years, when you are working somewhere else, someone won’t be swearing at how crap your code is.

When you work alone, you operate in incredibly small cycles of think-a-bit, spec-a-bit, try-a-bit, change-your-mind, enhance-a-bit, test-a-bit, release-a-bit, and so on. Maintaining conceptual integrity and good communications in a group of one is the default, rather than something to aim for.

It’s fun because other people can’t immediately see what you are doing. You can try things out. Odd things. Bad things. Things that might work, but that you wouldn’t admit to in the office.

One of the reasons I have lately grown to love Ruby is that it’s fun to use in this way - there’s no need for an IDE made up of hundreds of thousands of lines of code to support me writing my own thousands (or hundreds, or even tens as I get more into the idiomatic aspects of it) of lines of code. There’s something curiously warming in that.

You can address a lot of of the communication aspects quite easily. When a group of people, sit next to each other and talk often, to replicate all those something-a-bit iterations, great things can happen. Enterprise things. Highly performant things. Distributed transactional things. Ok, perhaps not with Ruby just yet, but it will get there.

This isn’t a trumpet blow for Ruby though. I just happen to be writing some yesterday, with a smile on my face, when it occurred to me that once you really relax your keyster you can do things in the name of productivity that would normally be heresy even to talk about. You can deliberately write some pretty bad code.

We strive to write good code because good code is easier to read, maintain, fix and extend than poor code. Elegant code often performs better too. There’s no doubt that good code makes an enormous difference to live systems, but to systems in development, I think you have a bit more leeway than might otherwise be acknowledged.

I was writing some fairly basic Rails code last week to extract some data from a database, munge it around a bit and then send it on email to the user. Nothing massively challenging except that I really needed access to some helper functions I’d written as part of the application’s DSL. The ActiveMailer pack in Ruby isn’t what they call a ‘first class’ resident of the Rails environment so doesn’t have access to standard helpers in the same way that controllers and views might. Because I was on a roll and wanted to get to working, testable, code quickly (and I didn’t know the simple trick that I do today to make helpers available) I committed the major sin of just copy/pasting my function code to where it could be accessed. It worked of course but I had broken the DRY principle and let myself down, my team down, and software designers everywhere.

To compound this, I checked the code in and went to work on some unrelated issues elsewhere. Later I needed to extend one of the helper functions, and of cource I had to do it in two places. Isn’t that about as as crappy as it gets?

But here’s where arse-cheek relief kicks in. I had made a note on my to-do list, to find out how to resolve the function-scope issue and made sure everybody knew what was going on.

Today I refactored (properly), re-ran the tests just to make sure I hadn’t done anything silly, and all is well.

The code that was bad is good again. My tactical and immediate goals were met (working software), and now the enterprise and strategic ones are too (extensible, lovely-looking, etc code). I certainly could have got distracted finding the optimum solution at the time, but I would have lost my train of thought, and the email code would have been the worse for it. As it turned out, my domain-specific language verbs are enhanced for the future and I got important end-user feedback on where to go next. Because I stayed in the zone, I think my model code is cleaner too.

So relax, I wouldn’t recommend this as a standard approach, doing it right first time is certainly better, but when we work together lets cut each other some slack.

As long as your refactor pile doesn’t get too high, and you test frequently and early, you needn’t be the only one in the office who, when they fart, only dogs can hear it.