As software applications grow, they can have areas that become unused. Identifying and addressing this code can give customers a cleaner experience, make engineering more efficient, and reduce surface area to attacks.
CAUSES OF UNUSED CODE
There are a number of potential causes of unused code in a software application, including:
- Feature flags that never went live
- Code that customers never discover
- Features developed for a client that “churns”
- Code that customers never found useful
- Low quality (or outright broken) features
- Features that never got traction
- “One-shot” features that were used at a point in time but are no longer relevant
IDENTIFYING UNUSED CODE
Going “outside-in” is the best way of identifying unused code - if there’s unused code the user is not exposed to, then that’s not a high priority issue. If, however, some code is exposed and never used, then it’s “clutter”.
As such, a great place to start is instrumenting the ingresses to your application. Now, all applications are different, but an MVC style web application (or anything with a controller) will have controller actions that can be instrumented. So will an API. So, we use a tool like Segment to instrument those actions.
DEALING WITH UNUSED CODE
So, you found some code that isn’t used! Now what? Generally, it comes down to improve it or remove it!
Option 1: Improve it
It might be that the unused code was a failure of training - perhaps it’s a great feature that your customers have never used simply because they don’t know about it, or it wasn’t clear!
Sometimes, the unused code may be “a feature whose time has come”, something that has slipped through the cracks in the past, but that your customers can now utilise.
Conversely, maybe the feature is simply not up to the task, but perhaps with a bit of work it could be a feature your customers could use?
Option 2: Remove it
This is the engineer’s favourite! Removing unused code reduces the size and complexity of a software system. This can result in a faster build and deployment loop, smaller checkout, and help us see the wood for the trees.
Don’t rush to rip out: there is always risk!
We can remove controller endpoints and UI elements with reasonable confidence, but perhaps the code that those endpoints invokes is used by other features that ARE in active use.
Unused “deep code” down in the back end has less tangible impact - removing it doesn’t directly benefit customers. It’s still worth removing because it cleans up the developer experience, amongst other benefits, but it doesn’t need to be done right now. So, we can take our time and be cautious as we remove it.
Mitigating risks when removing “deep” code
To mitigate the risks of removing “deep” code, we can use a mixture of proactive and reactive tactics.
Proactive: once removing a controller endpoint, tooling in many languages such as IDEs can identify unused code.
Proactive: an extensive automation test suite is a powerful line of defence - often, it will show up any code you rip out that was needed by some other module.
Proactive: consult with colleagues “hey, the data shows that module X was only used by endpoint Y, which we removed last month. Any objections to us removing it?”
Proactive: instrument the code more deeply when not sure if code is really unused. If there’s an area of code that I am pretty sure I can remove, I can add telemetry to the code blocks to record its usage. Then, I simply let data gather for a couple more months, measure, and make my decision then.
Reactive: deploy little and often. The smaller the delta between releases, the better chance we have of rapidly identifying and reverting a breaking change. So, we advocate “drip feeding” removal of unused code - treat it like any other roadmap item and schedule it as part of development iterations. As we’ve identified, there’s no huge rush to remove code, so think of it as occasional housekeeping. If something DOES go wrong, we can immediately revert.
Reactive: include the removal of features in the release notes. Customers may take this opportunity to say “hey, that would have been useful to us!”
Over time, some code may fall into disuse.
Disused code exerts drag on software development. If that code is in the UI, it exerts cognitive load on customers and degrades their user experience.
Through instrumentation and analysis, we can identify unused code and make an informed decision on whether to improve it or remove it.
“Little and often” is the best way to remove code, as small deltas can be reverted immediately in case something goes wrong.