Salta al contenuto principale

Refactor-cleaner skill: dead code cleanup con knip, depcheck, ts-prune

Cluster 6 della serie Claude Code Workflow (ultimo Superpowers). La skill refactor-cleaner orchestra strumenti di static analysis (knip, depcheck, ts-prune) per identificare e rimuovere dead code, dipendenze non usate, export inutilizzati. Pattern, esempi reali del portfolio.

Cosa ne pensi di questo articolo?

Refactor-cleaner skill: dead code cleanup con knip, depcheck, ts-prune
Claude Code WorkflowFoto:PixabayPexels

In Breve

Cluster 6 della serie Claude Code Workflow (ultimo Superpowers). La skill refactor-cleaner orchestra strumenti di static analysis (knip, depcheck, ts-prune) per identificare e rimuovere dead code, dipendenze non usate, export inutilizzati. Pattern, esempi reali del portfolio.

Risposta diretta

La skill orchestrandoli copre angoli sovrapposti del problema "dead code", validandosi a vicenda per ridurre false positive e aumentare la confidenza nelle segnalazioni. Utilizzando i tre tool insieme, si può identificare e rimuovere il codice morto con un tempo di 20 minuti e un effetto significativo sul progetto.

Il dead code si accumula in silenzio. Una funzione utility che nessuno importa più dopo un refactor; una dipendenza npm dichiarata anni fa per una feature dismessa; un export rimasto pubblico "in caso servisse". Singolarmente non fanno male; cumulati, gonfiano il bundle, rallentano i build, confondono i nuovi contributor. La skill refactor-cleaner orchestra tre strumenti di static analysis (knip, depcheck, ts-prune) per identificarli e proporli per rimozione.

Disclaimer di indipendenza: non sono affiliato a obra, ad Anthropic, né ai maintainer di knip/depcheck/ts-prune. Tutto quanto segue è esperienza sul mio portfolio Angular SSR + TypeScript negli ultimi mesi.

Cosa fanno i tre strumenti

I tre tool coprono angoli sovrapposti ma distinti del problema "dead code":

  • knip - analisi olistica del progetto, trova file interi non importati da nessuno, export non usati, dipendenze npm dichiarate ma non importate, binari/scripts non referenziati nel package.json. È il più completo, ma anche quello con più false positive su pattern dinamici.
  • depcheck - focus sulle dipendenze npm. Trova dipendenze dichiarate non importate e import di dipendenze non dichiarate. Più stretto di knip su questa dimensione.
  • ts-prune - focus su export TypeScript non importati. Funziona solo su file .ts con compiler TypeScript configurato. Più preciso di knip su questa dimensione.

Usati separatamente, ognuno copre il suo angolo. Usati insieme, si validano a vicenda: se knip e depcheck concordano su una dipendenza non usata, la confidenza è alta. Se solo uno lo segnala, è probabile un false positive.

Cosa fa la skill orchestrandoli

La skill refactor-cleaner non sostituisce i tre tool, li orchestra. Workflow tipico:

  1. Lancia knip sul progetto, raccoglie output.
  2. Lancia depcheck, raccoglie output.
  3. Lancia ts-prune, raccoglie output.
  4. Combina i tre output, identifica intersezioni (alta confidenza) e differenze (richiede verifica manuale).
  5. Produce report strutturato: candidate-removal per categoria + suggestion fix.
  6. Per ogni candidate, propone azione: remove (alta confidenza), investigate (media), keep (false positive identificato).
  7. Tu approvi/rifiuti caso per caso; la skill applica i remove approvati.
  8. Re-esegui suite test post-removal per verificare nessuna regression.

Esempio illustrativo: cleanup ciclico sul portfolio

Sintesi (non literal transcript) di una sessione mensile sul portfolio:

$ npx knip
  Unused files: 6
  Unused exports: 23
  Unused dependencies: 2
  Unlisted binaries: 0

$ npx depcheck
  Unused dependencies: 2 (concordano con knip)
  Missing dependencies: 0

$ npx ts-prune
  Unused exports: 18 (sottinsieme di knip)

Skill aggregation
  - Alta confidenza (rimuovi): 12 export + 2 dependencies
  - Media confidenza (verifica): 6 file (potential re-export pattern)
  - Bassa confidenza (skip): 5 export (Angular DI tokens, decoratori dinamici)

Proposed actions
  - rm src/utils/legacy-formatter.ts (file non importato)
  - rm src/utils/old-validator.ts (file non importato)
  - npm uninstall @deprecated/legacy-lib (dipendenza non usata)
  - npm uninstall some-old-polyfill (dipendenza non usata)
  - Rimuovi 12 export marker (vedi dettaglio)

User approves 10/12 export removals (2 keep: re-export per backward compat)
Skill applies, re-runs test suite: green

Tempo totale: 20 minuti. Effetto: 2 file rimossi, 2 dipendenze in meno (-3MB node_modules), 10 export inutilizzati eliminati, suite test ancora green.

I false positive principali

Tutti e tre i tool hanno false positive ricorrenti. La skill istruisce a riconoscerli prima di rimuovere:

  1. Re-export per backward compat. Un modulo index.ts che re-esporta funzioni di sub-moduli per consumatori esterni. knip vede gli export come "non usati internamente" ma sono pubblici per package consumer. Keep.
  2. Angular DI tokens e decoratori. Token InjectionToken sembrano "non importati" perché vengono risolti via DI runtime. Decoratori @Injectable(),@Component() sono usati dal framework, non importati esplicitamente in tutti i file. Keep.
  3. Dynamic require / dynamic import. Codice che usa require(\`./plugins/${name}\`) o import(\`./scopes/${scope}.json\`) non viene tracciato dai tool statici. Keep tutto il pattern dinamico.
  4. Polyfill conditional. Dipendenze caricate solo in certi browser o environment (es. fetch polyfill per Node). depcheck le vede come "non importate" ma sono usate runtime. Keep, configura .depcheckrc per escluderle.
  5. Script in package.json. Binari usati in scripts: di package.json ma non importati da codice applicativo. knip li segnala come "unlisted binaries"; sono usati, vanno keep. Configura .knip.json per esplicitarli.

Configurazione iniziale (illustrativa)

Esempio illustrativo di config che tipicamente serve per ridurre false positive (adattare al progetto):

// .knip.json
{
  "entry": ["src/main.ts", "src/main.server.ts", "scripts/**/*.{ts,mjs}"],
  "ignore": [
    "**/*.spec.ts",
    "**/*.stories.ts",
    "**/test-helpers/**"
  ],
  "ignoreDependencies": [
    "@angular/.*",
    "rxjs"
  ]
}

Configurare entry point (i file che il framework legge per primi: main, main.server per SSR, script di build) è il singolo settings che riduce di più i false positive iniziali. Senza, knip non sa da dove "iniziare" l'analisi e considera tutto non-entry come potenzialmente rimuovibile.

Pattern: chain code-reviewer → refactor-cleaner

Le due skill si combinano naturalmente. Quando code-reviewer segnala MEDIUM "duplicazione di logica fra X e Y", refactor-cleaner può proporre il refactor concreto (estrai helper, deduplica, rimuovi vecchia logica). Sul portfolio uso questo pattern dopo PR grosse:

  1. PR ha implementato feature.
  2. code-reviewer ha trovato 3 MEDIUM duplicazione.
  3. Invoca refactor-cleaner sui specifici file segnalati.
  4. Skill propone refactor concreto + auto-applica con tua approvazione.
  5. Re-esegui test: green.

Anti-pattern: cleanup-then-test, vs test-then-cleanup

La tentazione è "rimuovi tutto, poi vediamo se rompi qualcosa". Errore. Se rompi e non sai cosa hai rimosso, debug doloroso.

La skill istruisce a fare cleanup atomico per categoria:

  1. Rimuovi una categoria (es. dipendenze non usate).
  2. Esegui suite test.
  3. Verifica green.
  4. Commit atomico ("chore: remove unused npm dependencies").
  5. Passa alla categoria successiva (es. unused exports).

Se una rimozione spezza qualcosa, il rollback è atomic (revert del singolo commit). Niente big-bang cleanup che ti tiene ore di debugging.

Frequenza ciclica raccomandata

Sul portfolio uso questi intervalli:

  • Su PR grosse: dopo merge, lancia refactor-cleaner sui file toccati. Cattura detriti immediati prima che si stratifichino.
  • Mensile: cleanup ciclico generale su tutto il progetto. 15-30 minuti di sessione, rimuovi quel che c'è.
  • Trimestrale: full audit con riconfigurazione .knip.json + verifica nuovi false positive (framework update, nuovi pattern dinamici aggiunti).

Quando NON usare la skill

  1. Codebase molto dinamico: heavy uso di runtime require, plugin pattern con discovery dinamico, monorepo con tooling custom. False positive alti, rumore eccessivo.
  2. Prossimo deploy critico: non fare cleanup nelle 48h prima di un deploy critico. Anche con test green, c'è risk residuo di regression in path non testato.
  3. Solo un developer working su un'area: se sei l'unico a toccare un modulo e sai che certi export sono "tuoi futuri", potresti avere knowledge che la skill non ha. Skip cleanup su quei moduli.

Metriche di un cleanup tipico

  • Tempo sessione: 15-30 minuti mensile, 60-90 primo run progetto mai cleanato.
  • Token consumati: 20-50k per sessione mensile.
  • Codice rimosso: 5-30 file + 10-80 export mensile.
  • Dipendenze rimosse: 0-3 mensile, 5-15 primo run.
  • Bundle size impact: variabile, -50KB a -2MB sul JS bundle prod (dipende da cosa rimuovi).
  • Build time impact: -3% a -15% a parità di setup, principalmente da meno file da type-check.

Variante custom: cleanup per monorepo

Su monorepo con pnpm workspace o nx, una variante custom della skill aggiunge:

  1. Cross-package dependency check (workspace deps non usate).
  2. Detection di package "orfani" (nessuno li importa).
  3. Suggestion di consolidamento (due package fanno cose simili, mergeable?).

La skill upstream funziona su singolo package; la variante custom aggiunge livello monorepo. Sul mio portfolio (singolo repo, non monorepo) non la uso; la cito per chi gestisce monorepo.

Checklist invocazione skill refactor-cleaner

  1. knip, depcheck, ts-prune installati in devDependencies.
  2. Config .knip.json e .depcheckrc presente (anche se minima).
  3. Suite test green prima di iniziare (rollback safety net).
  4. 15-30 minuti di sessione disponibili.
  5. No deploy critico nelle prossime 48h.

Esempio concreto dal portfolio: cleanup sezione i18n

Storia recente sul portfolio. La pipeline i18n era cresciuta con script sperimentali nel tempo, e frontend/scripts/ conteneva 14 script di cui 5 obsoleti (sostituiti da scripts/i18n/xlf.py canonico). Il refactor-cleaner ha trovato in 5 minuti:

  • 5 script .mjs non più referenziati da package.json.
  • 2 dipendenze npm usate solo da quegli script.
  • 1 cartella scripts/i18n-old/ con backup pre-migration.

Rimozione totale: ~600 righe di codice, 2 dipendenze npm (-12MB node_modules), 1 cartella deprecata. Tempo: 12 minuti incluso re-test.

Cosa ho imparato scrivendo questo articolo

La sorpresa è stata quanto fosse poco il dead code sul portfolio dopo aver adottato il pattern ciclico. I primi due run (uno mensile + uno trimestrale) hanno raccolto quasi tutto il debito accumulato in anni; da lì in poi i run mensili trovano cinque-quindici cose, non più cinquanta-cento. La pratica ciclica è efficiente perché previene l'accumulo invece di doverlo recuperare a posteriori.

Secondo insight: la differenza fra "tool che ti dice il dead code" e "skill che orchestra i tool" è grande. Da solo, knip è facile da ignorare ("uff, 30 segnalazioni, leggo dopo"). Con la skill che classifica per confidence e propone azioni atomiche, il cleanup diventa un task da venti minuti invece che un sprint. La differenza è interfaccia, non sostanza, ma è quel che separa "tool installato" da "tool usato".

Anti-pattern evitati

  • Auto-remove cieco. Mai applicare in automatico tutte le segnalazioni dei tool. False positive su pattern dinamici esistono e fanno male.
  • Cleanup big-bang. Niente "rimuovi tutto stasera, vediamo domani se gira". Atomic per categoria + test green dopo ogni step = nessun sprint di debug post-cleanup.

Una storia ricevuta che vale la pena condividere

Sezione segnaposto. Se hai integrato refactor-cleaner in workflow di team (o ti sei pentito di un cleanup big-bang), scrivimi a federico@federicocalo.dev. Le storie di disastri pseudonimizzate sono particolarmente utili per i cluster successivi.


← Cluster precedente: Code-reviewer skill Prossimo cluster: ROADMAP-driven planning (track GSD) →

Domande frequenti

Cosa è il dead code e perché è un problema?

Il dead code si riferisce a codice non utilizzato o obsoleto che può accumularsi nel progetto, causando problemi di performance, complessità e difficoltà di mantenimento.

Come funzionano gli strumenti di static analysis menzionati (knip, depcheck, ts-prune)?

Ognuno degli strumenti copre un angolo diverso del problema "dead code", quindi utilizzati separatamente o insieme possono fornire una visione completa e ridurre i falsi positivi.

Qual è il pattern di lavoro raccomandato per eseguire il cleanup del dead code?

Il pattern consigliato è quello della "chain code-reviewer → refactor-cleaner", ovvero segnalare le problematiche con un tool e poi proporre azioni concrete per risolverle.

Quali sono i vantaggi di utilizzare la skill che orchestra gli strumenti di static analysis?

La skill riduce i falsi positivi, propone azioni atomiche e consente di eseguire il cleanup in modo efficiente e preventivo.

Fonti e approfondimenti

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti