- Corrective: diagnosing and fixing errors, possibly ones found by users
- Perfective: implementing new or changed user requirements which concern functional enhancements to the software
- Adaptive: modifying the system to cope with changes in the software environment (DBMS, OS)
- Preventive: increasing software maintainability or reliability to prevent problems in the future
“Corrective” and “perfective” maintenance are very visible and bring value to the customer. The need for “adaptive” and “preventive” maintenance on the other hand is harder to defend.
Customer value or waste?
The customer will demand any “corrective” change to be executed by the software developers with high priority, especially when it impacts his business. Any customer will also have a (wish) list of “perfective” enhancements to be executed and the client is willing to pay and prioritize this maintenance.
“Adaptive” maintenance on the other hand brings no (direct) value to the customer. It will be hard to get the customer to pay or even prioritize an operating system upgrade. Customers do like to argue “it works, do not touch it”. But the Internet has changed our world. We live in an all-connected world where security fixes need to be applied monthly. At some point the vendor stops providing (security) updates. At this point the product is called end-of-life (EOL). Not upgrading is considered a risk nowadays. This is why software developers can often argue that upgrading needs to get priority and the costs are justified. Examples of “adaptive” maintenance:
- Dependency upgrades
- Framework upgrades
- Operating system upgrades
- Database upgrades
“Preventive” maintenance is even harder to defend. Like “adaptive” it does not bring (direct) value to the customer. In the Agile methodology everything not adding value to the customer is called “waste”. Examples of “preventive” maintenance:
- Small code refactoring
- Big code refactoring
- Database refactoring
What is refactoring?
Wikipedia has a rather long definition that I tried to compact to:
Refactoring: technique for restructuring, altering internal structure without changing external behavior, undertaken to improve maintainability and extensibility
It may be trivial to conclude that refactoring is waste. Refactoring does not change behavior (functionality) and does therefor not bring value to the customer. Interestingly it is not mentioned as a waste in The Seven Wastes of Software Development by Matt Stine nor in the How to Manage the “7 Wastes” of Agile Software Development by Vijaya Kumar Bandaru. These posts are both referring to the 2006 book Implementing Lean Software Development: From Concept to Cash by Mary and Tom Poppendieck. Vijaya only says that “not refactoring” can lead to “partially done work”. From this remark we can conclude that not properly refactored code is not “done”. This is confirmed by Mayank Gupta who writes that “A common mistake is to not keep refactoring in the definition of done.”
Refactoring needs unit tests
Changing code without a functional reason, seems counter-productive at first. You spend money and take a risk to break the software, without promising any business benefits. This is why in software development the change management “change committee” should include software architects and security engineers, not only business people. The truth is that refactoring leads to lower costs for fixing bugs and extending with new features. This is mainly, because refactoring leads to software developers “touching” (and thinking about) the code. To counter the negative effects of refactoring (breaking software) one can introduce (and require) unit tests. These are programmed (automated) tests that ensure that after refactoring the code still works as before.
Selling refactoring to the business
Refactoring code that is touched by user stories in the sprint is easily done, since people are working on that code anyway. Making refactoring part of your definition-of-done encourages refactoring every time a piece of code is touched. To ensure high-quality, make sure the touched code also checks all the other marks on your definition-of-done. Some of our important definition-of-done topics:
- Unit tests written/ran
- Refactoring done
- Documentation updated
- Comitted to Git
- Functional tests written/ran
- Accepted by customer
Refactoring code unrelated to user stories in the sprint needs to be sold to the customer. Otherwise the customer will not understand why certain bugs suddenly arise. If you do not succeed to do so you must have patience. Every time you touch a part of the code for a user story, take the chance to refactor the related code or database. This way after a year or two you are able to renew your code base and data structure one feature or table at a time. Just make sure every user story is a little more expansive, so that you can squeeze in the preventive maintenance needed.