Code maintenance is generally viewed as a separate task in the development lifecycle. The hard work of designing and implementing the product has been performed, and although software tests did their best to get in the way and kept finding issues with the program, the product shipped. Now comes the maintenance. Let's move our best engineers to the next product, and the junior engineers will maintain this product, indefinitely. While I am being a bit facetious and completely sarcastic, this pattern seems to occur frequently in our industry. This attitude towards software code maintenance actually sets up the product for failure down the road.
Software Maintenance is a Misnomer
I first learned of this idea in Bjarne Stroustrup's book, The C++ Programming Language, Special Edition. Software is not like hardware in that it has physical parts that can wear out and must be replaced. Software is an abstract idea that one or more programmers have expressed in a way the computer will understand. The fact is, any change to software becomes an act of re-engineering. Some changes can be rather simple, and others are quite challenging. To make any type of change to a software application is more like replacing a component in the design and manufacturing of an electrical device, such as a phone.
A straight-forward example of a hardware design change would be replacing an unreliable capacitor with a similar capacitor from a more reliable manufacturer. A more challenging modification would be something such as including a larger battery for a device that has no space left inside the case. The components in the case may need to be re-engineered, or the case may need to be made larger. Either solution requires much more work than simply using the larger battery. This will surely require a bit of re-engineering of the original product in order to simply fix a hardware defect, or add a small upgrade.
With a physical product, a quick fix akin to using alligator clips to create a connection between two points of a circuit, or adding duct tape to hold a component in place to prevent movement will easily be spotted. Software is a fairly unique type of product because quick fixes may give the appearance that the software has been improved, as the desired behavior is present. The quality of the fix cannot be seen by the end user or even QA before the product is qualified and released. What seems to be an innocuous change could actually have devastating side-effects if the engineer does not have enough knowledge of a products architecture. It's possible for a solution eventually to be derived from the existing product, but at what cost? The integrity of the original design may be compromised with the working solution. This cycle tends to happen one change, one line at a time.
The abstract nature of software design, architecture and implementation makes it very difficult for most people to grasp the amount of effort that is required to make a robust change to existing software, this includes the software engineers performing the work. A robust change requires a thorough understanding of the existing implementation, and how the proposed changes will fit in with the overall architecture. One poor change will not necessarily manifest itself as obvious mistake. However, these changes add up over time, and eventually create a mire of tangled code that is difficult to modify without making it worse.
The Longevity of a Software Codebase
The software that we write, tends to live longer than we anticipate and even plan for. Therefore, you should write every line of code as if it will live forever. One example of this trend is prototype or demo code:
- Code is written quickly and intended to demonstrate a proof of concept
- A brilliant demo is then given
- Management or the customer then says,
"Perfect, I'll take three of them"
How well does it go when you try to explain to management that the product is only one-third of the way done and won't be available for sale until next year? This is one of the worst possible scenarios in development; the project starts off with the prototype code. Generally, this means that input validation, error handling, secure coding and other robust practices were neglected.
Attempting to shoe-horn a piece of logic from an open source module without fully understanding how it works is another poor start for a maintenance project. This type of solution is very similar to the prototype. It is usually a first implementation of a product or feature, and will generally be marred with schedule overruns, and quirky side-effects. Using code that is not encapsulated and well understood will only become more difficult to maintain as time passes. Looming deadlines often pressure developers to let more of the mess out, rather than cleaning it up and making it better.
So here we are, attempting to start with a run-once and throw away demo, and create a solid computer program. Most people would label this as an engineering effort. The scope of changes may be much larger than fixing one defect, or adding a small feature to a stable application. However, changing software is very unpredictable. Any change could possible introduce risk. This is why software maintenance is a new cycle of re-engineering the application. The quality of the code you begin with is the only difference in the examples above.
Software Development Lifecycle
Like it or not, if you are part of a project that requires software to be developed, you will enter a software development cycle. It may only be one pass through, it may turn into a product that has many different releases. Either way, to build something, you need these minimum elements that are part of the life cycle.
Software Development Cycle
- Gather Requirements
This list could be broken down further, however, this list is complete enough to demonstrate my point. First, the quality of attention given to each stage helps determine the quality of the final product. That will be a topic I save for another day.
Take note of the maintenance phase placed after the release of a product. Many companies will continue to work on a software product after it is released and send out patches. Companies like Adobe take this to the extreme, especially for their PDF reader. Most will call this software maintenance. What does the Maintenance phase look like if we break that down?
Software Maintenance Phase
- Gather Requirements
- "We found a bug that needs to be fixed"
- Search for the cause of the bug
- Search for the best way to resolve this issue
- This may also require a little bit of debug and experimenting
- Test that the bug is gone
- Hopefully a more formal verification also recertifies the entire system
The types of activities that occur during the Software Maintenance Phase may differ from the development of a brand new product, or a planned next version. The same phases still occur, and care must be taken when changing something that previously worked correctly. Entry level programmers may be able to maintain software and discover ways to fix the problems, or add small features. However, the solutions may not always be simple; the data required to solve the problem may not always be accessible; something may be in the code that looks incredibly stupid, yet it serves a purpose and should not be changed. For these reasons, there should always be an experienced developer on the team that guides the continued software maintenance.
I think it's important to mention a few thoughts regarding a developers ability level and where they fit into the software development life cycle. First and foremost, nothing beats experience. Time spent development is not necessarily the best gauge of experience either. An experienced developer will have worked on a variety of different projects and teams. A few of them should be for periods of time of at least 2 or 3 years. This is because in my experience, code rot starts to set in around 18 months. An experienced developer should know how to manage code rot. Finally, the experienced developer will need to have made and learned from many mistakes. This will help them choose judiciously when creating a new design or trying to determine how to fix a delicate defect in the code.
An existing codebase is an excellent place for less experienced engineers to learn how to solve problems in a production environment; they can learn by example. However, the guidance of an experienced mentor will always be more beneficial compared to instructing the junior engineer to "learn the code" and create a solution that is similar to what exists. Contrast this with how is a developer supposed to learn how to design software systems unless they get experience and guidance for that? The conclusion that I have reached is that it simply makes sense to place new developers on projects or tasks where they can work closely with experienced developers.
The mentorship and guidance are what are important in learning how to develop and maintain software. It's unfortunate that many developers want to jump onto a new project the moment the current one is complete. It's also unfortunate that the Software Maintenance step is often relegated to the less experienced developers on staff. I believe that creating a robust addition to an existing software base is one of the more difficult tasks in software development. To get the task done is one thing. To add something to a piece of software that it was never intended to do, and retain all of the behavior and properties of the original product is entirely another.
Software Maintenance is a misnomer that undermines and misrepresents the importance of the task for a software product. The name makes the process sound like cleanup work, or tightening bolts. When in fact it is actually a micro-development cycle, which should be given every bit as much attention to change and verification that was given to the original product. Until this realization is made by both management and the developers, the result will continue to be the more experienced engineers move on to the next great thing. This leaves the less experienced engineers to pay their dues learning the existing code mostly unguided.
In many trades and career types, this is the way things are done and it works. However, please consider that unless you see the mistakes you make, you will never know that you are doing anything wrong. I believe one of the most valuable experiences a programmer can live through, is develop and maintain the continued development of a piece of code for a minimum of three years. That will give you enough time to see the mistakes that you and others make, attempt to correct the mistakes, and witness how well the corrections performed. Otherwise, the developers that we call experienced (the ones with the most years coding) will continue to make the same mistakes. Which leaves the junior developers to start a career unguided, set to make the same mistakes as the previous generation.