Junk code refers to code and dependencies that bring no benefit to a project but increase its size, build time, and cognitive load on the team. Unlike dead code that never executes, junk may work but does so inefficiently or redundantly: duplicate libraries, unused imports, commented-out blocks, outdated polyfills, and decorative abstractions. According to the CodeScene Code Health Report (2025), on average 15 percent of dependencies in mobile projects are not used directly and only pull transitive packages. Junk code is the “extra weight” of a project: it makes the codebase thicker but not stronger. Regular dependency audits and removal of redundant abstractions directly improve build speed and code quality.
Key Takeaways
Junk (junk code) is a collective term for code, configurations, and dependencies that exist in a project but provide no functional value. Junk is not necessarily broken or unused — the problem is that its presence worsens project metrics without adequate justification.
Junk falls into four categories. First — redundant dependencies: libraries added for a single feature that could be implemented with standard tools. Second — dead weight: commented-out blocks, TODO without tickets, empty methods, and stub classes. Third — duplicate solutions: two libraries doing the same thing (for example, Gson and Kotlin Serialization in one project). Fourth — over-engineering: architectural layers that are not used but maintained “just in case.”
According to Stripe Engineering Productivity (2025) research, removing 10 percent of junk from a typical project reduces full build time by an average of 22 percent. The reason: every extra dependency increases the build graph, every empty abstraction takes time to understand, every commented-out block distracts attention.
The main difficulty in fighting junk is the lack of immediate consequences. A project with junk code compiles and runs. Problems accumulate gradually: builds slow down, the number of transitive dependencies grows, and after a year adding a new feature takes twice as long as it should.
Junk dependencies are libraries and packages added to a project that are not used directly in the code, or are used only for a single feature that would be simpler to implement with standard APIs.
Typical examples: a library for JSON processing when the project already uses Kotlin Serialization (two parsers is junk); the Apache Commons Lang library for a single StringUtils.isEmpty call that could be replaced with a Kotlin extension isNullOrBlank; a DI library used in one module out of ten, while the others receive dependencies via constructor manually.
Every extra dependency is not just extra code in the binary. It increases the surface area for vulnerabilities: according to the GitHub Advisory Database (2025), 40 percent of critical CVEs in mobile projects come from transitive dependencies that developers do not control. The fewer dependencies, the smaller the attack surface.
// View Gradle dependency tree
./gradlew app:dependencies --configuration releaseRuntimeClasspath
// Find unused dependencies (Gradle plugin)
plugins {
id "com.autonomousapps.dependency-analysis" version "2.0.0"
}
// Generate unused library report
./gradlew buildHealth
For iOS, use the swift package show-dependencies command, which outputs the full dependency tree. The Xcode Build Timeline tool shows how much build time each library adds. If a library takes 30 percent of compilation time but is used on a single screen, it is a candidate for removal or replacement.
For Node.js (React Native), use depcheck — a utility that finds unused dependencies in package.json, and npm-check, which additionally shows outdated versions. Introduce a rule: every new dependency must pass code review with a justification of “why standard tools cannot be used.”
Dead imports are the most common type of junk. They do not affect runtime but increase compilation time: the compiler processes every import, even unused ones. In large projects, removing unused imports reduces build time by 5–10 percent.
Modern IDEs automatically highlight unused imports in gray. Set up auto-cleanup on file save: in IntelliJ IDEA — Optimize Imports on the fly, in Xcode — Editor > Remove Unused Imports. Add a CI check: the linter should block commits with unused imports.
Commented-out code is another type of junk. Developers comment out blocks to “not lose” functionality during refactoring. However, git stores the full history of changes: any removed code can be restored with a single git revert or git log -S
The rule: there is no commented-out code in the repository. If code is not needed, delete it permanently. If code is needed but temporarily disabled, use a feature toggle with a ticket and an expiration date. Comments like // TODO: remove after migration — do not leave without a deadline. Set a date and remind yourself with a calendar.
Over-engineering is creating architectural layers that do not solve current problems but require maintenance. This is one of the most insidious types of junk because formally the code is “correct”: it follows SOLID, is covered by tests, and conforms to the architecture. The problem is that it is unnecessary.
A classic example is an abstract UseCase class with a single invoke method that simply calls a repository. If the UseCase adds no logic (caching, retry, transformation) and only passes the call through, it is an extra entity. It increases navigation in the project: a developer opens the UseCase, sees invoke → repository, and closes it. Time wasted, zero benefit.
Another example is excessive parameterization. A generic interface with six type parameters used in only one place. Each type parameter adds cognitive load: when reading the code, you have to keep six types in mind while only two are actually used. If an abstraction is not reused, it is redundant.
The cutoff criterion: if an abstraction is not reused in three different contexts, remove it. An abstraction is justified when it actually solves a duplication problem, not when it predicts hypothetical future scenarios. YAGNI (You Ain’t Gonna Need It) is the best principle for preventing over-engineering.
Junk auditing requires a combination of static analysis, dependency analysis, and manual review. It is impossible to fully automate the detection of redundant abstractions, but technical junk (dead imports, unused libraries, commented-out code) can be found with tools.
| Category | Tool | What It Checks |
|---|---|---|
| Unused dependencies | dependency-analysis (Gradle) | Libraries not used in code |
| Unused dependencies | depcheck (Node.js) | Packages from package.json without imports |
| Unused dependencies | swift package --show-dependencies | SwiftPM dependency tree |
| Dead imports | IDE (Optimize Imports) | Unused import statements |
| Commented-out code | grep -r “//” / rg “^\s*//” | Comment blocks with code |
| Empty methods/classes | SonarQube / CodeClimate | Methods with empty or no body |
| Duplicate libraries | Gradle lint (duplicate classes) | Class conflicts from different libraries |
For a full audit, run buildHealth (Android) or depcheck (Node.js) once per sprint. Create a CI dashboard showing the dependency count trend across sprints. If the count grows but functionality does not grow proportionally, the team is accumulating junk.
Pay attention to duplicate classes — an error that occurs when two libraries contain the same class. This is not only junk but also a direct source of build conflicts. In Gradle, such conflicts are resolved via force or exclude, but each such resolution is a signal that one of the libraries is unnecessary.
Junk cleanup is not a one-time action but a regular process. Without a procedure, junk returns within two to three sprints. The best practice is to allocate 10–15 percent of each sprint’s capacity to technical cleanup, including junk auditing.
The process consists of four steps. First — diagnostics: run tools, get a report, prioritize. High priority: dependencies with known CVEs and duplicate libraries. Medium priority: dead imports and commented-out code. Low priority: redundant abstractions (require manual analysis).
Second — cleanup: remove dead dependencies, replace duplicate libraries with one, delete commented-out code. Each change should be a separate commit with a clear message: “remove unused dependency: gson (replaced by kotlinx.serialization)”, “delete commented code in LoginViewModel.”
Third — verification: build the project, run tests, check the UI. If tests pass after removing a dependency, the dependency was indeed unnecessary. If tests fail, there is a hidden reference somewhere that the static analyzer did not detect.
Fourth — prevention: update the code review checklist, add a rule “no new dependency without justification” to the Definition of Done, set up automatic checks in CI. Prevention is the only way to prevent junk from accumulating again.
Frequently Asked Questions
Technical debt is a conscious compromise (fast but low quality) that is planned to be fixed. Junk is not a conscious decision but accumulated garbage: extra dependencies, commented-out code, empty abstractions that no one planned or wants to maintain.
The optimal rhythm is to allocate 10 percent of each sprint to technical cleanup. This keeps junk under control without accumulating critical mass. If a project has a lot of junk, start with one big cleanup sprint and then switch to a regular rhythm.
Measure and show the numbers: measure build time before and after removing 3–5 extra dependencies. A reduction of 15–30 seconds per build multiplied by the number of builds per day gives hours of saved team time. Numbers convince better than abstract calls for cleanliness.
Yes, especially if the dependency has a CVE. Even if the project is stable, a vulnerability in a transitive dependency is a security risk. Moreover, when updating an SDK or language, an old dependency may become incompatible, and removing it before the upgrade will save hours of migration time.
Every TODO without a ticket is junk. Set a rule: TODO is written only in the format // TODO(PROJECT-1234): fix linked to a task in the tracker. Regularly check TODOs and close those that have lost relevance. Remove expired TODOs — if the problem did not surface in six months, it is not critical.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also