Software apoptosis

January 2014

++

One challenge with all software projects is managing growth over time. The last two teams I've joined (BBC News, The Guardian) have viewed their current platforms, both of around ~4 years old with a few dozen weekly contributors, as monoliths - a byword for something unsustainable, unmanageable, and ultimately something that is slowing the progress of the business.

But monoliths don't start out as monoliths.

A software team who builds software that is obvious to improve, simple to introduce new features, easy to do things quickly is seen to be doing a good job, and, ironically, it's only through the daily addition of code layered upon code layered upon code do things begin to seem unmanageable after a while.

Avoiding this is partly to do with even-shifting sands of good architectural practice, tools and so on, but more so, I believe, to do with the mentality of the project team.

204 additions, 2 deletions

Generally speaking, I see things added to our project every day that fall in to these three categories:-

The problem with the first thing is that we don't know if they really will provide a durable benefit. At the point of being added we almost always think they will, but I expect most software is bloated by unused or unloved features, and once the initial excitement has passed things can get ignored.

The problem with the second thing is that it's very easy to forget to remove them once you are done. When looking at our project in investigating this article I found nine features and AB tests that we no longer needed, but nobody had a diary appointment to remove them, and so the code rumbles on, growing by the day.

The last is often a matter of perspective. But a project that does not defend its ground will end up bigger, more complicated, less focussed. When we add something to the code and later realise it was a mistake it needs removing.

What is needed in each of these cases is a regular, structured review of the value of the feature and it's place in the project.

Dead man's switch

What if we could implement a dead man's switch whereby the feature in question could remove itself from operation if nobody was paying attention or it became unowned and unloved?

Helpfully, most of the features we add to theguardian.com are sat behind switches, so this provides a natural place to add a life span to everything we do.

Our switch model has an id, description, a default state, and now a sellByDate.

val ReleaseMessageSwitch = Switch(
    "release-message",
    "If this is switched on users will be messaged ...",
    safeState = Off
    sellByDate = new DateMidnight(2014, 4, 1) 
)

To enforce this behaviour across the project we've added a check to the function that the whole application (both Scala and JavaScript) uses to know if the feature is on or off.

def isSwitchedOn: Boolean = delegate.isSwitchedOn && new DateMidnight().isBefore(sellByDate)

If a feature has expired, two things happen.

At this point someone should remove it or seek justification as to why it should live on.

It's an opportunity to talk about the feature with the team.

With these simple additions the application is now animated. Each thing we add has a programmed life span and needs humans, vigilance, and a small amount of effort/investment in order to stay alive.

It asks people to think how long a feature should last in production, rather than an indefinite default.

Early warning

It's a bit unfair to have something just turn itself off without notice, so we've implemented an early warning system as part of our daily routine.

The dashboard the hovers above the team now displays features with an expiry date of less than seven days.

As with anything red on the dashboard we take note and organise among ourselves to fix it.