Friday, 29 April 2011

Why do teams fail to sustain code quality?

Code quality always seems to get worse and worse. Even when a team is actively fighting against it, complexity inevitably wins in the end. What's going on? Why is this pull towards complexity such a powerful force?

In my view, a lot of the problem stems from the wrong actions being taken, with the best of intentions in mind.

Code quality quickly spirals down

Developers don't want to introduce bugs, so they naturally take actions to avoid doing so. Making changes to working code is risky, so developers make heavy use of conditional logic ("in my particular case do this, otherwise, do the same as before") and duplication to minimise the changes to existing code.

There's a good intention behind it. Unfortunately, it makes the code increasingly difficult to work with—to understand the ramifications of a change— and subsequently increases the pressure to tread carefully and avoid making those bigger and bolder changes to the design that are really needed to keep the code clean.

Automated regression tests aren't enough to stop it

Agile teams tend to make heavy use of automated regression tests. This not only allows the team to release code frequently, but allows them to refactor it and keep the design in good shape. The tests should catch any bugs introduced when the design is reworked.

That's the theory, but, in practice, the developers don't keep the design clean. Why? Because their old "don't make unnecessary changes" habit is so deeply-ingrained. And so, the vicious circle continues.

You have to change the habits too

How do you change habits? Education, constant reminders, code reviews, management oversight, tie a knot in your handkerchief... whatever it takes because if you don't change the habits your code quality will deteriorate and your team's agility will disappear with it.

"Circuit Diagram" for Options

After drawing the diagrams for my last post, I'm playing with ideas for a notation for describing options. What I've come up with so far isn't very good — I'm not even very clear on what the dimensions are... I think it's roughly time along the x-axis and choices along the y-axis, though I think I may be mixing other concepts in as well — but, anyway, I thought I'd put it out in the hope that someone else might help me improve it.

Here's a real-life example from my last project (read it from left to right):

We actually followed these steps. The team in Hong Kong worked on improving the speed of the database reports, while, in London, I built an alternative report generator that wasn't as flexible, but was very fast. By release time the Hong Kong team had ironed out all the problems with the queries and optimised the databases indexes so their reports were adequately fast. In the end, we went with a mixture of the two.

I also got in trouble by trying to be too clever. I put code in to the test environment to do live cross-checking of the reports generated by the two methods. It did reveal some discrepancies. But I got in trouble because they were trying to do speed tests at the time. Communication, communication, communication...

Let me know if you have any ideas about a notation for describing options (I'm talking about real-life options, not financial options).

Thursday, 28 April 2011

Always have a plan 'B'

You cannot predict exactly what's going to happen in the future. Having options allows you to respond quickly as different situations arise.

Option to Abandon

Lifeboats on an ocean liner are an example of the option to abandon. The same with backups of your software. With luck you'll never need them, but it's worth creating the option just in case.

Option to Backtrack

The option to backtrack is similar to the option to abandon, except that you don't abandon the direction completely, you go back to a previous "safe" point ready to try again.

If you release a new version of some software and then find it's unstable, you want to be able to go back to the previous version. Any kind of "rollback" or "undo" capability is providing the option to backtrack.

Being able to backtrack is important for learning. To experiment with a piece of software, try out a new refactoring, or test the boundaries of a technique you want to feel safe that you can go back to where you were.

Option to Choose

This option is about alternatives. To travel between cities you might take a train, but if the train drivers are on strike you'll need to find another way. By thinking about your choice of options in advance, you won't need to panic.

An example in software is where the business logic is decoupled from the data storage technology, so that users can choose between several different databases. This can create value by widening the potential market.

Option to Defer

This option is about timing. Do we have to decide now or can we decide later? The option to defer is about pushing back decision points, to allow more information to come in, or being able to put something on hold, with the possibility of returning to it later on — for example, postponing a space shuttle launch due to icy conditions.

Traditional software development methods force the development team to commit to features a long time before they are developed or deployed. Agile methods let you defer commitment (see this article by Chris Matts and Olav Maassen for a more in-depth explanation of how options-thinking relates to agile).

Option to Expand (or Contract)

This option is about resources. If a customer wants to place a huge order with you, can you accommodate it? Can you recruit quickly? Can you move resources from a less successful project to another more successful one?