Software spends most of it’s time in maintenance state. I have seen figures that up to 90% of all cost comes from the maintenance. It becomes more important as time goes on.
If you think about it, you can see how it is happening. Some sort of enterprise (business, government, etc) experiences a need for software. Then software is crafted. After that, software is deployed and it runs. Now it produces value for the enterprise. Now it is in maintenance state.
If software was crafted really well, then there will be few bugs. By well-crafted I mean:
- Problem was understood;
- Solution to the problem is acceptable to those that experience problem;
- Infrastructure fits the software;
- Code is healthy enough to be kept around.
Maybe in some time it will need some scaling work to be done. Maybe some new features will need to be developed. But in general, it will be a good asset for the organization.
Let’s consider another alternative. Imagine engineers produce crappy software that still solves the problem. Inevitably bugs will come, but they should be resolved fairly quickly as code is still well understood. After release, a constant stream of bugs appears. They are resolved in timely maner.. It’s good that engineers still have the context. They fix everything with duct tape and glue.
After many months, world changes. So does requirements. So should software. At this point, fixes and changes become really expensive. Engineers do not have this fresh context anymore. Maybe they left the organization. Now a real problem is dealing with issues in such software.
Let me share a story with you.
My team has inherited codebase. It was crafted by a single engineer when startup was being built. No code reviews, no proper CI/CD, no automated tests, no documentation, code duplication. Company identified that this was a problem. Bus factor equals 1 for critical piece of software. Moreover, engineer switched teams.
When team was onboarding into the codebase, we had the ability to consult with that engineer. He was really helpful. With time and our changes, he lost the context as we gained more. However, noone really felt comfortable with the codebase:
- We were firemen fighting the fires most of the time;
- We learned about the system from bug reports;
- We knew more how it behaved from bugs than from the code;
- It was so horrible that even support agents found their ways to fix issues for customers. We would consult them on how our system works..
Such unmaintainable software was pain for customers, company and engineers. Everybody suffered.
I hope you understand the importance of maintainability. I hope you feel the pain.
How to measure maintainability?
Since maintenance is done by humans, and humans are subjective creatures – it is fairly difficult to measure mainainability directly.
For example, software and documentation may not change, but maintainability might decrease. In the example presented previously, software became more difficult to maintain because people lost the context.
For an integrated measure, I guess you could discount that as time goes. But do you also integrate engineers leaving the company? There are so many variables impacting maintainability. It is a tough challenge to arrive at a single metric.
However, with some human intelligence we may use some proxies to better understand how maintainable the software is.
Size
Simplest measurement is a measurement of size. Imagine a business running on 50 lines of code. That would be pretty easy to maintain. In a few days you have almost complete understanding of what is going on.
Now imagine it being 50M lines of code. You probably will never be capable of understanding everything in such huge codebase.
Hey – if you reduce the number of lines of code, your software will get more maintainable, right? That would be awesome. JavaScript minifiers then would be ultimate maintainability boosters.
However reality is not like that. In reality, businesses build software to serve their customer needs, so some code is necessary.
You could look at lines of code together with code duplication. It should give you better view if novel code is being produced. If half of your code is same as the other half, then reducing lines of code might be worth looking into.
Another way you could supplement lines of code is with dead code. Dead code is code that is not being used in any circumstances. If quarter of your code is not used, then why is it here? To distract engineers? Heh, it might help to just remove that if you have no reason for it.
You could start thinking about sizes of functions. If codebase is littered with 200-liner functions, it might get challenging to work on that. Of course some areas are destined to be big. I do not believe that there should be a cap on function size. However, most of your code should be understood quickly. You could target 95th percentile to be small, or even 99th percentile. I haven’t seen this in action, but maybe you did? Let me know if you tried such metric.
Simplest measurement is a measurement of size. Imagine a business running on 50 lines of code. That would be pretty easy to maintain. In a few days you have almost complete understanding of what is going on.
Now imagine it being 50M lines of code. You probably will never be capable of understanding everything in such huge codebase.
Hey – if you reduce the number of lines of code, your software will get more maintainable, right? That would be awesome. JavaScript minifiers then would be ultimate maintainability boosters.
However reality is not like that. In reality, businesses build software to serve their customer needs, so some code is necessary.
You could look at lines of code together with code duplication. It should give you better view if novel code is being produced. If half of your code is same as the other half, then reducing lines of code might be worth looking into.
Another way you could supplement lines of code is with dead code. Dead code is code that is not being used in any circumstances. If quarter of your code is not used, then why is it here? To distract engineers? Heh, it might help to just remove that if you have no reason for it.
You could start thinking about sizes of functions. If codebase is littered with 200-liner functions, it might get challenging to work on that. Of course some areas are destined to be big. I do not believe that there should be a cap on function size. However, most of your code should be understood quickly. You could target 95th percentile to be small, or even 99th percentile. I haven’t seen this in action, but maybe you did? Let me know if you tried such metric.
Complexity
Another possible way to look into maintainability is through complexity perspective. More complex code → harder to understand for engineers → harder to maintain.
Complexity can be measured through cyclomatic complexity. It tells how many different paths a function has. Just like with sizes of functions, some code is destined to be complex. You could also target 95th percentile to be of a reasonable size.
This could surely mislead you if used incorrectly. However, it could also enrich your understanding and lead towards more maintainable code.
Other
There are other ways to measure maintainability.
For example see how much time team spends on maintenance activities late into process. If software needs a lot of attention to operate, then it is a sign of low maintainability.
Or simply count how many times team mentions that software is crappy. You really do not want engineers leaving with the knowledge of crappy codebase. And they are the ones to make it right.
There are many signals, just listen to them. And then make a decision to solve the problems.
How to have more maintainable software?
There are many ways to increase maintainability of software.
I believe most potent one is to invest into automated testing. Tests act as a documentation. Moreover, this documentation is exercised and up-to-date. It also shortens the feedback loop of engineers. But most importantly, it reduces chances of introducing bugs. Earn and keep that trust between you and the customer!
Another big one is actually resolving bugs and issues of customers. But not for that one time – for all. Make sure that issue happens only once. Add tests for it. This will reduce your support workload, need for engineer ↔ support communication and time to engineer thus increasing maintainability.
Another way to make software more maintainable is refactoring. It helps with code health very much. Reduce size of functions, make names better, clean up bad stuff. Engineers will be grateful for it, so will your wallet. Also, having classical documentation really helps. Draw diagrams, track decisions and reasoning, etc. It will get out of date, but it helps to build the context.
Conclusion
In general, the more maintainable software is, less time to maintain it is needed. Some time needs to be spent upfront, but payoff is huge. Most importantly, it means more time to improve business rather than keeping it going. It is much better investment than bonds.