«    »

How to Create Maintainable Software

My previous article talked about the importance of maintainable software. In this article I provide some recommendations on how to create software that is maintainable - easy to change with minimal risk and impact.

What are the specific challenges facing developers maintaining software?

  1. They probably did not originally develop the software, and may not even have access to the people who did. This is due to several factors. In some organizations the software maintenance group is separate from the software development group. Even when the same organizational group develops and maintains the software, it is common for the development team to be much larger than the number of people allocated to maintain the software, so the majority of the development team moves on to other projects. Another factor is that the lifespan of the software (five or more years) is usually longer than the lifespan of employees with the organization (average of three years).
  2. They may need to make emergency fixes or release defect fixes quickly, while concurrently working on new features.
  3. They must ensure that the software operates properly in its production environment, while developing and testing defect fixes and new features.

So how to address these challenges?

  1. Make code readability a primary goal when writing code (after correctness). Rapid Development by Steve McConnell, page 255-256, relates an interesting experiment in which five development teams were tasked with writing the same piece of software. Each team was given a different objective (memory use, output readability, program readability, minimum statements, minimum programming time). Four of the five teams came in first place with respect to their objective, but no team came in first place in more than two of the objectives. The lesson: clearly define your objective, and make sure it is the right objective.

    Why is readability so importance for maintenance? Code you write is likely obvious to yourself, but try waiting a few months without looking at it, and then see what you think. And when it is another developer who has to look at the code, without the ability to ask you what you did, then readability becomes even more important. Since developers spend more time reading code than writing it, it makes sense to optimize the most frequently used path.

  2. Use automated testing. Automated suites of tests using tools such as JUnit have been widely popularized in the last seven years, yet I still encounter developers not using this practice. In a discussion last year on automated unit testing, a senior developer stated that he did not see the need for such testing - he had no problems getting his code to work. While I doubt the validity of this reason - I find automated unit testing to be quite beneficial in catching defects in my code - more important are the developers who inherit this individual's code and must make changes. Automated testing is one of the best practices for reducing the risk of introducing new defects when changing the code. Another benefit of automated unit testing is that the unit tests serve as a form of documentation to new developers that shows how the code being tested is expected to be used.
  3. Use version control software to its full potential. Most projects I have been involved with have used version control software, yet few have used it to the fullest extent possible. One example of this is the use of branching. It is a common practice in open source software development teams to use branching to manage changes to the currently released version of the software while implementing new features in the new version - exactly the situation faced in maintenance. Yet in commercial development, I have encountered many developers who either are completely unfamiliar with the concept of branching, or who are uncomfortable with performing branching and related activities in the version control software they use. For such developers, I recommend reading the book Software Configuration Management Patterns by Stephen Berczuk - it does an excellent job covering the concepts and recommended practices concerning the use of version control software (which is a subset of configuration management). I also recommend experimenting with branching with your version control software to become comfortable with the process. Create a test project with some files in your version control repository. Make a branch of this project, then modify files in both the original version and the branch. Then try merging / copying changes between the branch and the original version.

    Another case where version control software is not used to its full potential concerns which files associated with the application are actually being stored using version control. All projects using version control store the code, but many projects do not store other files associated with the application, such as web pages, online help, build scripts, database scripts, and technical documentation. Instead I have seen such projects use what I call the Common Server Directory anti-pattern. A set of directories on a file server is made accessible to the team, and everyone adds and modifies files in this common area. Sometimes an effort is made to track versions, via directory or file names, and sometimes not. Since a file system is not designed with the features of version control software, the end result is not surprising. The list of problems I have seen or encountered personally spans the entire spectrum: one person's changes overwritten by another, file corruption (on Windows servers), accidental moving of a sub-directory, confusion over previous versions of a file - who made which changes at what time, among others. Unfortunately, the solution is simple - use version control software - but hard to implement. Many of the other files associated with an application are created and/or owned by non-developers: web designers, business analysts, database administrators, testers, or technical writers. It is quite uncommon for such individuals to be familiar with the concepts of version control, let alone be comfortable using it. And such individuals are often in different groups than the development team, making it difficult to mandate the use of version control. If you had success implementing version control in this kind of situation, I'd like to hear how you accomplished it.

  4. Ensure that the software is well-designed. Some qualities of a good design in the context of software maintenance are: as simple as possible, easy to understand, easy to make changes, easy to test, and easy to operate (i.e. easy to deploy and monitor for problems). Unfortunately, if you inherit an existing piece of software to maintain, then you will have to deal with the existing design, which may not be all that you'd like it to be. Even with well-designed software, as you add new features, you may find that portions of the original design are no longer appropriate, or that additional capabilities have to be included in the design. This is when the technique of refactoring is useful. Refactoring is a disciplined approach to modifying software code without changing its external behavior. A great book on this topic is Refactoring: Improving the Design of Existing Code by Martin Fowler. The more new features you need to add to an existing application, the more important refactoring becomes.

These recommendations should ideally be carried out when the software is first being developed, but it is never too late to start implementing these ideas. For those who have some say in the deliverables produced by a development project, please make sure items such as the automated test suite are included and are verified as part of the delivery. In one architectural review I did of a development project, I found evidence that JUnit unit tests were used by the developers, but they were not supplied in the release. On another maintenance project, the JUnit tests were present, but the configuration information necessary to connect to the database when running the tests was not documented or preserved in version control. I never was able to determine the configuration used (the individual able to run the tests had moved on before I joined the project), and I had to redesign the database connection code as a result.

This article is long enough that I deliberately did not go into details on how to implement each of the recommendations. If you are interested in reading more about any of these topics, let me know.

If you find this article helpful, please make a donation.

«    »