Recent reshuffling in my team brought up the division between maintenance and new development that many long-term software projects have and I started thinking about Software Maintenance itself. I realised:
Software isn’t maintained. There is no such thing as software maintenance.
Buildings and bridges need to be maintained. The Sydney Harbour Bridge has a team constantly repainting it. But this was planned when it was built. It was understood that some parts wear out and need replacement every few years, some coatings weather and need repainting every few years.
Cars need maintenance. The oil needs changing, tyres get damaged and need to be replaced. Whole gearboxes wear out eventually and need to be replaced. But again this was expected when the car was built. It was known what parts would need replacement after a certain amount of driving. And these parts are replaced with identical parts that are just newer and less worn.
Software is not maintained. Software doesn’t wear out. It doesn’t get fragile if you run it every day for 10 years. It doesn’t lose its colour if you leave it in the sun all summer.
Software needs to be changed.
Some changes are planned for when the application is written. The tax rate changes, the user wants a different colour scheme. These are either made configurable or at least simple and obvious to change.
But most changes are not planned for. The tax system changes with an extra tax band, but that band only applies to savings income not salary income. The company starts sales in a different country with extra currency conversion and import duties the company has never needed to calculate before. Users of the system see new things it could be extended to do.
Software is not maintained. Software is continuously redesigned and re-implemented.
There is a repeat here of the old trap of using the wrong metaphor and restricting our thinking. This affects both software teams and their sponsors (internal management or external customers).
Just like calling unit-tests "tests". In a toy factory testing is a quality control step applied after something is built. It doesn’t in itself improve quality, quality comes from care in design and in the actual manufacturing process. But for software unit-tests change your design and give you greater understanding of the code and the requirement that drove it; for software unit-tests directly improve software quality – but only if they are done properly. Recognition of this broken metaphor led to Behaviour Driven Development (BDD), calling the activity something else that better implies what it is really for, or at least stops us limiting our view of the activity.
Maintenance for cars and bridges is a straight-forward known piece of work. You can discuss who has to pay for the work and what quality of materials to use but the work is understood: inspect, repair, replace existing components. If a building is being repurposed (when a new shop or company moves in) it’s not thought of as "maintenance", you get an architect and "redesign" it. It’s seen as a completely different activity, expected to be more costly than regular maintenance and with more chance of things going wrong or needing to re-plan along the way. So calling software changes "maintenance" confuses both software developers and the people asking for the changes, makes it sound like a straight-forward, low-risk activity when it is completely the opposite.
Metaphors are good things, they help us understand the world. But they are shortcuts, and the wrong metaphor limits our thinking and leads to the wrong assumptions. The wrong metaphor limits the language we use, restricts and confuses what we can say to members of our team and to our sponsors.
When we say "test", they hear "task to do afterwards that won’t immediately affect quality if we skip it".
When we say "maintenance", they hear "simple task that should be quick and won’t need much testing".
Danger Will Robinson!
Because maintenance changes are expected to be low-risk they are given to less experienced developers and can even lead to software teams being split into separate maintenance and development teams, with the maintenance team being the less skilled developers or even replaced with developers with no prior knowledge of the system.
Because of the lack of knowledge of the system, changes will be made without understanding the full effects, which leads to new problems.
Because maintenance changes are expected to be low cost they are done as quickly as possible and with as small a change as possible.
The developer doing the change knows it’s expected to be done quickly so will do the first change they think of without exploring options, which can give a poor solution and spaghetti code. Because the developer knows the change is expected to be simple they’ll just fix that problem, without evolving the system design, which leads to the core design getting lost under expedient fixes making each new change more expensive. The bar for "good enough" on the project gets lower with ever with every poor fix, with every tangled design, with every "broken window" until it’s so low you trip over it every time you try and make any change.
An experienced developer, or one with knowledge of the system will know to look for possible problems, will know what changes need more attention and will push back on management expectations of a quick fix. But if small changes are routinely given to junior developers they may not have yet built up the knowledge or the confidence to ignore those expectations.
While looking for quotes to illustrate my point I found this in The Mythical Man Month:
"The changes after delivery are called program maintenance, but the process is fundamentally different from hardware maintenance."
"Any attempt to fix it with minimum effort will repair the local and obvious, but… the far-reaching effects of the repair will be overlooked. Second, the repairer is usually not the man who wrote the code, and often is a junior programmer or trainee."
So as usual I feel bad because my thoughts are not original (not for 40 years), and then I feel worse because we’re still fighting the same problems (after 40 years!).
Expect change, don’t fight it.
Yes, of course you should strive to design components and services so many changes will be localised. Yes, you should plan clean interfaces between components. Yes, you should build automated tests to prove the current behaviour and the current requirements.
But don’t treat the current architecture of your system as something permanent. Don’t treat the current interfaces between components and services as carved in stone.
Don’t squeeze changes into the smallest space just to avoid changing an interface – it will just make the interface more mysterious. Don’t be afraid to add and remove dependencies – hiding them or going via several existing links just makes the dependency invisible. Every hidden, mysterious condition or special case inside your code is going to make the next change harder. Every hidden dependency will mean you don’t know what needs testing after the next change.
So don’t be afraid to change things. Don’t be afraid to take more time, to do more testing. Making this change clean and visible will mean the next change is easier.
And when they say "maintenance", you say "software change", you say "redesign", you say "re-implement". Reframe it in your own head so you don’t box yourself into "simple, quick" changes. Reframe it out loud to help your team and sponsors get free of the assumptions and expectations imposed just by a choice of words.
Don’t get trapped in a broken metaphor.
- Mythical Man Month (Frederick P. Brooks, Jr.): http://www.goodreads.com/book/show/13629.The_Mythical_Man_Month
- XKCD – Goto: http://xkcd.com/292/