FORM NOT VOID, MIND NO CORE

Chapter 12 Regular Garbage Collection: Don't Let the System Carry AI's Debt

2026.08.10

In Chapter 11, we built a solid "test grid" for our project. This grid goes a long way toward guaranteeing the "correctness" of our codebase. As long as the grid stays powered, we can be sure that the system's core behavior will not drift under AI's modifications.

However, "correct" code is not the same as "healthy" code.

A software system is like a living organism. Beyond a strong skeleton (architecture) and reliable behavior (tests), it also needs an efficient "metabolic" system. A healthy organism is constantly expelling old, useless, and even harmful cells, making room and freeing resources for new, vibrant ones.

If an organism only takes things in but never lets them out, endlessly accumulating metabolic waste, then even if it can still function normally for now, it will eventually grow bloated and sluggish from internal "congestion" and "poisoning," and finally decline.

In the AI programming era, we enjoy an unprecedented speed of "creation." The "growth" of code has been greatly accelerated. But at the same time, if we do not have a matching, equally efficient "cleanup" mechanism, then the rate at which "metabolic waste" -- that is, technical debt -- accumulates in the codebase will also be unprecedented.

In this chapter, we will learn how to become a "janitor" and a "gardener" of the software world. We will establish a regular "garbage collection" mechanism to proactively and systematically identify and remove the "code garbage" inadvertently created by AI (and by ourselves) during rapid iteration. Our goal is to let our system, across successive version iterations, not only grow more powerful in functionality but also become purer and more refined in its code, ultimately reaching a state of enviable "reverse growth."

12.1 Why Do AI-Written Programs Contain So Much "Dead Code"?

After collaborating with AI for a while, you will keenly notice a pattern: the code AI generates seems especially prone to "dead code" -- functions, variables, classes, or imports that are defined but never called anywhere.

In addition, AI has a particular fondness for leaving behind "redundant logic branches" that look reasonable on their own but, in reality, will never be executed in the current business flow.

This phenomenon is no accident. It stems from two core innate tendencies of AI: "probabilistic association" and "a lack of global awareness."

Tendency One: Probabilistic Association Built on "Pattern Completion"

AI does not write code the way humans do, driven by a clear "intent-driven" logic that runs from A to B. At its core is a "pattern completion" mechanism.

When you ask AI to write a function that handles user-uploaded images, its neural network is activated by the keyword "image upload." It then retrieves, from its training data, the most common code snippets associated with the "image upload" pattern.

  • It knows that handling image uploads usually requires "file type validation." So it may write an isValidFileType() helper function.
  • It knows that "file size limits" are usually needed. So it may write an isWithinSizeLimit() helper function.
  • It even knows that a "robust" image upload feature may also need to handle "image compression," "thumbnail generation," and "watermarking." So it may "thoughtfully" generate compressImage(), createThumbnail(), and addWatermark() for you as well.

Now here is the problem: in your specific business requirement, you may only need "file type validation" and "size limits." You do not need compression, thumbnails, or watermarking at all.

But AI does not know that. Driven by "probability," it merely completed for you the code pattern it considered the most "complete" and "common" for "image upload processing." And so compressImage(), createThumbnail(), and addWatermark() become "dead code." They are defined, their syntax is perfectly correct, and they may even have corresponding unit tests -- but they have never been called once in your business's main flow.

Tendency Two: A Local Field of Vision Constrained by the "Context Window"

As we discussed in Chapter 5, AI's "cognition" is limited by its "context window." Even with an extremely long context, its understanding of the code remains "flat," lacking the human's layered "mental model" of the project's overall architecture.

This "local field of vision" makes AI especially prone to creating "orphan code" during modifications.

[A Typical Scenario]

  1. Initial State: The project has a V1_ReportGenerator.js module, referenced by both DashboardPage.js and AdminPanel.js.
  2. Your Instruction: "We are now upgrading the report system. Please create a V2_ReportGenerator.js and make DashboardPage.js use this new module."
  3. AI's Action: AI executes your instruction perfectly. It creates V2_ReportGenerator.js and changes the import statement in DashboardPage.js to point to the new module.
  4. The Problem Created: AI's "context" contains only DashboardPage.js. It has no idea that, in another distant corner of the project, there is an AdminPanel.js still referencing the old V1_ReportGenerator.js.
  5. Subsequent Evolution: Some time later, you ask AI to refactor AdminPanel.js. During this refactoring, AI notices that the report-generation functionality in AdminPanel.js closely resembles that in DashboardPage.js, so it (correctly) decides to have AdminPanel.js also use V2_ReportGenerator.js.
  6. "Dead Code" Is Born: At this moment, the V1_ReportGenerator.js module is no longer referenced anywhere in the project. It has become a complete orphan. But no one (including AI) will realize this. A file containing hundreds of lines of old logic will remain in your codebase forever, like a "ghost," taking up space and creating immense confusion for any future developer reading the code.

The Characteristics of AI-Generated "Technical Debt"

The "dead code" and "redundant logic" created by AI usually share the following characteristics:

  • Syntactically correct: They pass all linter and compiler checks.
  • Logically plausible: Looked at in isolation, they all seem to be doing something meaningful.
  • Functionally isolated: Their problem is not that the code is "written incorrectly," but that it is "never used."

This kind of technical debt is extremely insidious and hard to detect through conventional code review and automated testing. Tests can only guarantee that "the code that is called" is correct; they cannot tell you "which code has never been called."

For this reason, we must build a dedicated, regular "garbage collection" mechanism to proactively and systematically sweep away these "metabolic wastes" that accompany AI's high-velocity creativity.

12.2 Building a Regular Scanning and Cleanup Mechanism: Redundant Logic, Invalid Fallbacks, Outdated Comments

You cannot fight "code entropy" on a whim. It must be proceduralized and institutionalized, becoming an indispensable "ritual" in the development cycle of you and your team.

This "ritual" can be scheduled before each iteration begins, or after each major version is released. Its goal is not to develop new features, but to deliberately pause and give the existing codebase a thorough "spring cleaning."

This spring cleaning focuses on three types of "garbage."

First Type of Garbage: Structural Redundancy

This type of garbage refers to parts of the code that are structurally wholly useless. Cleaning it up requires static code analysis tools.

Dead Code

  • Identification Tools:
  • JavaScript/TypeScript: You can use ts-prune or ESLint's no-unused-vars rule (though the latter is weaker). Webpack's tree shaking can remove dead code at build time, but we want to catch it at coding time.
  • Python: vulture is an excellent tool designed specifically for finding dead code.
  • Go: go vet includes some built-in checks, and the community offers tools like deadcode.
  • IDE Assistance: Modern IDEs (such as VS Code or GoLand) typically use color (e.g., a gray shade) to flag unused imports and variables. This is an important signal.
  • Cleanup Process:
  1. Add a dedicated "Dead Code Scan" step to the CI pipeline.
  2. Run tools like ts-prune or vulture, and emit their output as build artifacts.
  3. Initial stage: The results can be emitted as "warnings," periodically reviewed by team members and cleaned up manually.
  4. Mature stage: This can be turned into a "gate." If new dead code is introduced, the CI build fails outright.

Redundant Dependencies

  • Identification Tools:
  • JavaScript/TypeScript: depcheck is an indispensable tool. It scans your code and tells you which dependencies in package.json are never imported or required anywhere in the code.
  • Cleanup Process:
  1. Periodically (for example, once a month), run npx depcheck in the project root.
  2. Review depcheck's report, and for any dependencies confirmed to be no longer needed, decisively remove them from package.json and re-run npm install or yarn install.
  3. This not only shrinks the size of node_modules, but also lowers the project's security risk (fewer dependencies means a smaller attack surface).

Second Type of Garbage: Logical Redundancy

This type of garbage cannot be fully discovered automatically by tools. It requires judgment that combines tools with human "domain knowledge."

Never-Reached Logic Branches

  • Phenomenon: There is an if (condition) block in the code, but because of how the rest of the system has evolved, this condition can logically never be true anymore.
  • Identification Method:
  1. Your code coverage report is your "X-ray." In the coverage report, carefully look for lines where branch coverage is not 100%.
  2. If a branch of an if statement still shows as "uncovered" after your comprehensive automated tests, that in itself is a strong "red flag."
  3. Human intervention: You need to review this "uncovered" branch together with AI. Ask AI: "Based on our current business logic, does any real scenario exist in which this if condition could be true? If not, please explain why, and help me safely remove this branch and the code inside it."
  • AI is very good at this kind of "logical reasoning." It may tell you: "This branch was designed to handle a user type called 'LEGACY_USER'. But three months ago we completed the data migration, and this user type no longer exists in the system. So this branch is safe dead code."

Invalid Degradation Logic

  • Phenomenon: As we discussed in Section 10.2, we may add some "degradation logic" for the sake of system robustness. But over time, the "root cause" that triggered the degradation may have been fixed.
  • Identification Method:
  1. Log monitoring is your "stethoscope." Periodically (for example, weekly), search your log monitoring system specifically for WARN log events related to "degradation" (such as event: "FALLBACK_TO_GENERIC_RECOMMENDATIONS").
  2. If a degradation log has not appeared even once in the past month, that too is a strong signal.
  3. Human intervention: Review this degradation logic together with AI. Ask AI: "We observed that this degradation logic appears never to have been triggered in the production environment. Please analyze its triggering condition [... a ...] and determine whether this condition can still occur under the current system architecture. If not, please help me remove this degradation code and simplify the original try-catch block into a direct call."

Third Type of Garbage: Cognitive Redundancy

This type of garbage does not affect the program's execution, but it greatly increases the "cognitive cost" for humans (and AI) to understand the code.

Outdated Comments

  • Phenomenon: When AI refactors code, it is likely to change a function's logic while "forgetting" to update the comments that describe the old logic.
  • Identification Method: This is the hardest to automate. It depends on strict code review habits.
  • Cleanup Process:
  1. In the team's code review checklist, explicitly add an item: "Check all comments surrounding the modified code blocks to confirm they are consistent with the new code's logic."
  2. Encourage a culture of "anti-commenting": the best code is self-explanatory. Rather than writing an elaborate comment to explain convoluted code, have AI help you refactor that convoluted code into something simple, clear, and readable without any comment at all.

Stale "Feature Flags"

  • Phenomenon: To release new features safely, we often use "feature flags." But once a feature has been rolled out to 100% and has been running stably for a while, the feature flag itself -- along with the if/else logic it wraps -- becomes technical debt.
  • Identification Method:
  • Maintain a centralized "feature flag registry" (in a document or a dedicated configuration center).
  • Give each feature flag a "lifecycle," for example, "must be cleaned up one month after going live."
  • Cleanup Process:
  1. Review this registry periodically.
  2. For flags that have "served their purpose," create a dedicated "technical debt cleanup" task.
  3. This task is ideally suited to AI: "The feature flag 'ENABLE_NEW_FEATURE_X' is now 100% enabled and permanent. Please scan the entire codebase, remove all if/else checks related to this flag, and keep only the logic inside the if branch."

By building such a regular cleanup mechanism that spans the three dimensions of "structure," "logic," and "cognition," you equip yourself with a powerful "code metabolism" system. This system will ensure that your project does not age and stiffen prematurely under AI's "catalysis."

12.3 Enabling the System to "Reverse-Grow" Through Iteration After Iteration

"Reverse growth" sounds like a poetic ideal that defies the laws of nature. But in the world of software, it is not impossible.

A conventional software project typically follows a lifecycle curve like this:

  • Early stage: small codebase, clear structure, very fast development.
  • Middle stage: code volume and complexity surge. To accommodate old logic and add new features, the code becomes full of patches and compromises. Development speed begins to decline noticeably; fixing a bug may take longer than shipping a new feature.
  • Late stage: the system has become a "big ball of mud." No one can fully understand all its details. Any tiny change can trigger an avalanche of knock-on effects. Eventually, the team is forced to make the painful decision to tear it down and start over.

This process is the software embodiment of the "law of entropy increase."

The ultimate purpose of the "regular garbage collection" mechanism we have built is to fight entropy. Together with our day-to-day "feature development" work, it forms the "Yin" and "Yang" of project evolution:

  • Feature development (Yang): adds new functionality and complexity to the system. This is the process of "growth."
  • Garbage collection (Yin): removes useless, redundant complexity from the system. This is the process of "pruning" and "purification."

When "growth" and "pruning" reach a dynamic equilibrium, something remarkable happens.

In each iteration, we:

  1. Add new, valuable business code.
  2. Remove an equivalent (or greater) amount of valueless old code, dead code, and redundant logic.

The result is that the project's total lines of code (LOC) may grow slowly, or even decline in some iterations! Yet the business value of the system continues to rise steadily and robustly.

The system's "complexity" is held at a relatively stable level rather than growing exponentially without bound. The codebase becomes like a carefully tended bonsai rather than a rainforest running wild. It continuously metabolizes, growing ever more "refined" and "pure."

This is "reverse growth."

AI's Role in This Process: AI is both the "catalyst" that can accelerate "entropy increase" and the most powerful "scalpel" we have for performing "entropy reduction."

  • On the "Yang" side, we use AI to implement new features quickly.
  • On the "Yin" side, we use AI to efficiently identify and refactor code, working through every item on the "cleanup list" we have set for it.

For a mature AI-collaborative team, the iteration rhythm should not be "develop, develop, develop," but "clean, develop, clean, develop." Institutionalizing "garbage collection" and placing it on the same strategic footing as "feature development" is the only path to ensuring that your project can survive the passage of time, achieving long-term value and sustainable growth.

[Cleanup Checklist] 10 Redundancy Points to Check Before Every Iteration

Use this checklist as the action guide for the "spring cleaning" ritual in each iteration cycle. You can turn it into a template and check off each item at every iteration planning meeting.

Category#CheckpointHow to Check (Tools/Methods)AI Collaboration Instruction
Structural1Unused Exports (Dead Exports)ts-prune"Run ts-prune and help me analyze its report. For each reported unused export, confirm if it's safe to remove."
2Unused Dependenciesdepcheck"Run depcheck and remove all identified unused dependencies from package.json."
3Empty Files/Directoriesfind . -type f -empty"Find and list all empty files or directories in the src folder for deletion."
Logical4Unreachable BranchesReview non-100% branches in the code coverage report"This if branch is never covered by our tests. Analyze the condition and confirm if it's unreachable in our current logic. If so, refactor the code to remove it."
5Never-Triggered FallbacksSearch production logs for degradation events that have long been absent"This fallback logic hasn't been triggered for a month. Is its triggering condition still possible? If not, please simplify the try-catch block."
6Duplicate/Similar LogicCode duplication detection tools such as jscpd or pmd (CPD)"Our CPD tool found these two functions are 90% similar. Please refactor them by extracting the common logic into a shared utility function."
Cognitive7Outdated CommentsManual review"The logic of this function has changed. Please review and update its docstring/comment to accurately reflect the new behavior."
8Stale Feature FlagsReview the feature flag registry"The feature flag '...' is now obsolete. Please scan the codebase and remove all related logic, keeping only the 'enabled' path."
9Vague/TODO CommentsSearch the codebase for // TODO:, // FIXME:, // HACK:"List all TODO comments in the codebase. Let's review them one by one. Can we resolve this one now? If so, implement the required change."
10Commented-Out CodeUse regular expressions to search for large commented-out blocks"This block of code has been commented out for a long time. It should have been managed by Git. Please remove it. If we need it, we can find it in the Git history."

Weave this checklist into your team culture. Make "keeping the code clean" just as honorable and satisfying as "delivering new features" -- an engineering practice to be proud of.

Once you reach this point, you have truly and completely mastered AI. You have harnessed not only its "light" -- that incomparable speed of creation -- but also tamed its "shadow" -- that equally astonishing capacity to create chaos. You have become a genuine, future-facing "master of software."