Tip of the Week: Remove Unused Code to Avoid Software Decay
Tip of the Week: Remove Unused Code to Avoid Software Decay
Each week we seek to provide a software tip of the week geared towards helping you achieve your software goals. Views expressed in the content belong to the content creators and not the organization, its affiliates, or employees. If you have any software questions or suggestions for an upcoming tip of the week, please don’t hesitate to reach out to #software-engineering on Slack or email DBMISoftwareEngineering at olucdenver.onmicrosoft.com
The act of creating software often involves many iterations of writing, personal collaborations, and testing. During this process it’s common to lose awareness of code which is no longer used, and thus may not be tested or otherwise linted. Unused code may contribute to “software decay”, the gradual diminishment of code quality or functionality. This post will cover software decay and strategies for addressing unused code to help keep your code quality high.
TLDR (too long, didn’t read); Unused code is easy to amass and may cause your code quality or code functionality to diminish (“decay”) over time. Effort must be taken to maintain any code or artifacts you add to your repositories, including those which are unused. Consider using Vulture, Pylint, or Coverage to help illuminate sections of your code which may need to be removed.
Code Lifecycle and Maintenance
stateDiagram direction LR removal : removed or archived changes : changes needed [*] --> added added --> maintenance state maintenance { direction LR updated --> changes changes --> updated } maintenance --> removal removal --> [*]
Diagram showing code lifecycle activities.
Adding code to a project involves a loose agreement to maintenance for however long the code is available. The maintenance of the code can involve added efforts in changes as well as passive impacts like longer test durations or decreased readability (simply from more code).
When considering multiple parts of code in many files, this maintenance can become untenable, leading to the gradual decay of your code quality or functionality. For example, let’s assume one line of code costs 30 seconds to maintain (feel free to substitute time with monetary or personnel aspects as an example measure here too). 1000 lines of code would cost 500 minutes (or about 8 hours) to maintain. This becomes more complex when considering multiple files, collaborators, or languages.
Think about your project as if it were on a hiking trail: “Carry as little as possible, but choose that little with care.” (Earl Shaffer). Be careful what code you choose to carry; it may impact your ability to address needs over time and lead to otherwise unintended software decay.
Detecting Unused Code with Vulture
Understanding the cost of added content, it’s important to routinely examine which parts of your code are still necessary. You can prepare your code for a long journey by detecting (and removing) unused code with various automated tools. These tools are generally designed for static analysis and linting, meaning they may also be incorporated into automated and routine testing.
$ vulture unused_code_example.py
unused_code_example.py:3: unused import 'os' (90% confidence)
unused_code_example.py:4: unused import 'pd' (90% confidence)
unused_code_example.py:7: unused function 'unused_function' (60% confidence)
unused_code_example.py:14: unused variable 'unused_var' (60% confidence)
Example of Vulture command line usage to discover unused code.
Vulture is one tool dedicated to finding unused python code. Vulture provides both a command line interface and Python API for discovering unused code. It also provide a rough confidence to show how certain it was about whether the block of code was unused. See the following interactive example for a demonstration of using Vulture.
Interactive Example on Unused Code Detection
Further Code Usefulness Detection with Pylint and Coverage.py
In addition to Vulture, Pylint and Coverage.py can be used in a similar way to help show where code may not have been used within your project.
Pylint focuses on code style and other static analysis in addition to unused variables. See Pylint’s Checkers page for more details here, using “unused-*” as a reference to checks it performs which focus on unused code.
Coverage.py helps show you which parts of your code have been executed or not. A common usecase for Coverage involves measuring “test coverage”, or which parts of your code are executed in relationship to tests written for that code. This provides another perspective on code utility: if there’s not a test for the code, is it worth keeping?