Author: Chris Newton
Published: 9 Jan 2010
Length: 2,382 words
“Everyone knows” are dangerous words. When everyone knows, no-one thinks.
For example, have you ever met a professional software developer who said maintainability didn’t matter? Of course not. Everyone knows maintainability is important!
But what does that really mean? What is maintainability, and how can we improve it?
Why does it matter?
In short, because this is where the effort on your next software project might go:
1 See, for example, the work of Barry Boehm on cost estimation.
Maintenance typically claims 40–80% of all project costs, usually toward the higher end.1
So, if we know how maintenance works and what affects our ability to do it, then we can improve those things to make better software, faster.
Reasons for performing maintenance
First, let’s be clear about what software maintenance is for.
Lientz and Swanson surveyed nearly 500 data processing groups, and identified four distinct types of maintenance and the proportion of time typically spent on each:2
Corrective maintenance is work to fix any kind of defect.
Adaptive maintenance responds to environmental changes, such as porting to new hardware or a different OS, but without affecting functionality.
Perfective maintenance includes any functionality changes to meet new requirements, as well as performance improvements.
Preventive maintenance is work to improve maintainability itself, such as refactoring an awkward design or adding comments.
Surprisingly, perhaps, maintenance in the narrow sense of “fixing bugs” represents less than one-quarter of the total time spent working on existing code. Keeping up with changing requirements and operating environments takes a much greater proportion of the maintenance effort over the lifetime of a typical software system.
3 Broy, M. et al, Demystifying Maintainability, in WoSQ ’06: Proceedings of the 2006 International Workshop on Software Quality, ACM, 2006.
Despite the importance of maintainability, just 3% of maintenance time is spent improving it. Moreover, only 20% of respondents to a recent survey of software maintenance practices said they carried out specific checking for maintainability as part of their QA process.3 No wonder code so often degenerates into spaghetti…
Lientz and Swanson’s paper may be three decades old, but it remains widely influential. IEEE standard 1219 defines software maintenance to be:
The modification of a software product after delivery to correct faults, to improve performance or other attributes, or to adapt the product to a modified environment.
The corresponding ISO standard, 14764, classifies maintenance using the same four types, as do many modern papers, though sometimes with slight variations in the definitions.
So, we have some data about why we need maintain our code. However, Lientz and Swanson’s approach is not very useful as a predictive tool to help us make decisions or work more effectively. For that, we need to look at how maintenance is performed.
The small-scale maintenance process
Let’s consider a single maintenance task in isolation, say implementing a particular feature or fixing a set of closely related bugs.
The beginning and end of the development process probably differ from initial development. For example, corrective maintenance tends to be driven by some sort of bug triage process, and the changes from any kind of maintenance may need to be deployed to existing installations in the field. Most concerns that arise at these times are non-technical.
What about the technical steps that form the core of the process?
We start with understanding what we want to achieve. As with initial development, this involves analysis to establish the specific requirements implied by the change. During maintenance, we also have an isolation step (sometimes called impact analysis), when we identify the area(s) of existing code affected.
Then comes modification, consisting of design and implementation steps. These, too, are like initial development, but with a change in emphasis because any new work must integrate with the established design.
Finally, we have various forms of testing. Because we are modifying existing code during maintenance, we add regression testing.
Like other software development processes, maintenance is often iterative, and these steps may form part of a cycle that runs several times before a particular task is complete.
Supporting all of these steps is program comprehension, the work of understanding and extracting useful information from our code. This is a very important underlying activity in software maintenance, and the comprehension element may use over 50% of the total time.4
5 van Vliet, H., Software Engineering: Principles and Practice, Wiley, 2007.
Van Vliet suggests that overall time spent on the code-related steps is split roughly equally between isolation, modification and testing.5 However, the distribution of time across the different steps varies greatly with the type of maintenance. For example, during adaptive maintenance, isolation may be a relatively minor part of the work, but for corrective maintenance, the isolation step includes tracking down the source of the defect, and may consume a much greater share of the time.
Information sources during maintenance
Did you ever get the feeling that you were writing a lot of documentation that no-one was ever going to need later? Well, it turns out that you were probably right. Industrial studies suggest a consistent order of importance for information sources during software maintenance, and documentation is way down the list:
Code is the main resource. Singer found that 7 in 10 industrial development groups looked to the code as their primary source.6 However, this emphasis does come with a caveat: it applies only when the maintenance developer is already somewhat familiar with that code.
Coworkers are the other major source of information. If the developer doing the maintenance work is unfamiliar with the code, or if they can’t readily see how to proceed, they will often consult the original programmer or another coworker who knows that part of the code better. As well as Singer, another study by Ko et al observed coworkers providing diverse kinds of information.7
Database tools such as bug trackers can be valuable secondary resources. They tend to accumulate wisdom gained by the development team as the project evolves, in relatively concrete and searchable forms.
Documentation does matter, but its value depends very much on what is being described. Typical low-level documentation is widely distrusted by developers, who expect it to be out of date or to present conflicting information. However, higher-level documentation, giving an overview of a feature or describing its original intent, was cited as valuable in Singer. Documentation was also the most common source of information in Ko to answer questions of the form “How do I use this data structure or function?”.
A larger scale: the laws of software evolution
8 Lehman, M.M., Programs, Life Cycles, and Laws of Software Evolution, in P. IEEE 68(9), Sept 1980.
Now let’s consider a longer-term perspective. Lehman has also studied software evolution, and over the years has proposed several laws to describe it.8 Here is the first:
Law of Continuing Change: A program that is used and that as an implementation of its specification reflects some other reality, undergoes continual change or becomes progressively less useful. The change or decay process continues until it is judged more cost-effective to replace the system with a recreated version.
And here is the second:
Law of Increasing Complexity: As an evolving program is continually changed, its complexity, reflecting deteriorating structure, increases unless work is done to maintain or reduce it.
Stages in a software project’s life
9 Bennett, K. and Rajlich, V., Software Maintenance and Evolution:
A Roadmap, in ICSE ’00: Proceedings of the Conference on The Future of Software Engineering, ACM, 2000.
Bennett and Rajlich build on these ideas, suggesting that in reality software projects pass through up to five distinct stages over their lifetime, each with unique maintenance characteristics:9
Initial development produces the first version of the product. During this stage, the architecture is determined. Also during this stage, the development team acquire a great deal of knowledge, from user requirements and understanding the application domain to the pros and cons of the architecture and familiarity with the data structures and algorithms used.
Following successful initial development, the project enters the evolution stage. During this period, the full range of maintenance tasks is available, to keep up with changing requirements and operating environments, and to fix defects. This depends on a combination of good software architecture and knowledge within the development team.
As changes are made to the code and the development team, the architecture and knowledge base may start to decay. If either degrades far enough, substantial changes to the software are no longer practical. The project then enters a servicing stage, where only small, tactical maintenance such as patching to fix a bug is viable. Bennett and Rajlich argue that this is normally a one-way transition: once a project has degenerated and entered servicing, it is no longer possible to return to effective evolution.
Eventually, a project may reach a point where it is no longer actively maintained at all, but is still in operation (phase out). At this stage, users must work around known bugs and limitations for themselves. Finally, some projects may be retired completely (close down).
The same staging principle holds for projects that release a string of major versions over an extended period, such as most off-the-shelf software: the main development path continues to evolve and produce new versions, but branches for older versions eventually diverge to the point where they enter their own servicing stage, and ultimately die out.
These staged models have powerful implications for how we develop software: good maintainability is not just about making changes easier and developers more productive, it is about whether making substantial changes is even possible. To borrow Ward Cunningham’s brilliant metaphor, if we accumulate too much technical debt, we can become technically bankrupt. Then the only way back is to start over, which incurs heavy penalties.
To avoid this fate, so that a project can continue to evolve for as long as we need it to, we must preserve both the integrity of the software architecture and the knowledge base available to the development team.
Principal factors affecting maintainability
Now that we’ve looked at both the short-term and long-term views of software maintenance, we can identity some important contributory factors for maintainability:
We have seen that understanding relies primarily on program comprehension, drawing information from the source code itself. It is therefore important that the code present useful information as clearly as possible.
Preservation of knowledge
Understanding is reinforced by the knowledge base built up by a development team over the course of a project and particularly during the initial development. Teams tend to lose knowledge over time, unless steps are taken to preserve it, through effective communication, good tools, and good documentation.
Testing takes many forms: unit testing, integration testing, high-level functional tests, code inspections… To these we add regression testing once we begin maintenance. Again, any steps we can take to make testing faster or more reliable will enhance maintainability.
It almost goes without saying that any steps we can take to make designs more adaptable and ease the mechanical implementation of changes will improve maintainability.
This is not intended to be an exhaustive list. In particular, it focuses on technical factors affecting the code, and to some extent on the documentation and tools that directly support development. Organisational and project management issues are for another day.
1. Why does it matter?
- Maintenance commonly uses the majority of a software project’s development resources. A 3:1 ratio of maintenance to initial development work is not unusual.
2. Reasons for performing maintenance
- Maintenance can be classified as perfective, adaptive, corrective or preventive.
- Around 75% of maintenance work is responding to changing requirements and operating environment. Most of the rest is bug-fixing.
- Only 1 in 5 development groups surveyed made a point of checking maintainability during QA, and just 3% of maintenance time is spent improving maintainability.
3. The small-scale maintenance process
- There are mostly non-technical differences between maintenance and initial development at the start and the end of the process.
- The technical steps are similar: understanding, modification and testing.
- Understanding includes an extra “isolation” step during maintenance, to identify where in existing code changes need to be made.
- Testing methods will now include regression testing.
- Program comprehension is a vital underlying activity.
4. Information sources during maintenance
- The code itself is the primary source of information for developers.
- Consulting other developers is also common.
- Database tools such as bug trackers are valuable secondary sources.
- Developers distrust low-level documentation, but some other types can be useful.
5. A larger scale: the laws of software evolution
- Programs undergo continuous change or become progressively less useful.
- Program complexity tends to increase over time unless actively controlled.
6. Stages in a software project’s life
- Projects pass through up to five stages:
- initial development
- phase out
- close down.
- During evolution, a full range of maintenance work can be performed.
- During servicing, maintenance is restricted to local, tactical changes.
- Once a project enters its servicing stage, further evolution is not possible.
- The key factors in extending the evolution stage are integrity of the software architecture and preservation of the developers’ knowledge base.
7. Principal factors affecting maintainability
- Important technical factors affecting maintainability include:
- preservation of knowledge
- To improve productivity and quality during maintenance, and to avoid moving to servicing prematurely, it is important to support all four of these areas.
© 2010 Chris Newton. Redistribution is prohibited without explicit consent from the author.