Código lixo (junk code) refere-se a código e dependências que não trazem benefício a um projeto, mas aumentam seu tamanho, tempo de compilação e carga cognitiva na equipe. Ao contrário de código morto, que nunca é executado, o lixo pode funcionar, mas o faz de forma ineficiente ou redundante: bibliotecas duplicadas, importações não utilizadas, blocos comentados, polyfills obsoletos e abstrações decorativas. De acordo com o CodeScene Code Health Report (2025), em média 15 por cento das dependências em projetos móveis não são usadas diretamente e apenas puxam pacotes transitivos. Código lixo é o “peso extra” de um projeto: torna a base de código mais espessa, mas não mais forte. Auditorias regulares de dependências e remoção de abstrações redundantes melhoram diretamente a velocidade de compilação e a qualidade do código.
Principais pontos
Junk (código lixo) é um termo coletivo para código, configurações e dependências que existem em um projeto, mas não fornecem valor funcional. O lixo não está necessariamente quebrado ou não utilizado — o problema é que sua presença piora as métricas do projeto sem justificativa adequada.
O lixo se divide em quatro categorias. Primeira — dependências redundantes: bibliotecas adicionadas para um único recurso que poderia ser implementado com ferramentas padrão. Segunda — peso morto: blocos comentados, TODO sem tickets, métodos vazios e classes stub. Terceira — soluções duplicadas: duas bibliotecas fazendo a mesma coisa (por exemplo, Gson e Kotlin Serialization em um mesmo projeto). Quarta — superengenharia: camadas arquiteturais que não são usadas, mas mantidas “por precaução.”
De acordo com a pesquisa Stripe Engineering Productivity (2025), remover 10 por cento de lixo de um projeto típico reduz o tempo de compilação completa em média 22 por cento. A razão: cada dependência extra aumenta o grafo de compilação, cada abstração vazia requer tempo para entender, cada bloco comentado distrai a atenção.
A principal dificuldade na luta contra o lixo é a ausência de consequências imediatas. Um projeto com código lixo compila e funciona. Os problemas se acumulam gradualmente: a compilação fica mais lenta, o número de dependências transitivas cresce, e depois de um ano adicionar um novo recurso leva o dobro do tempo que deveria.
Dependências lixo são bibliotecas e pacotes adicionados a um projeto que não são usados diretamente no código, ou são usados apenas para um único recurso que seria mais simples implementar com APIs padrão.
Exemplos típicos: uma biblioteca para processamento JSON quando o projeto já usa Kotlin Serialization (dois parsers é lixo); a biblioteca Apache Commons Lang para uma única chamada StringUtils.isEmpty que poderia ser substituída pela extensão isNullOrBlank do Kotlin; uma biblioteca de DI usada em um módulo de dez, enquanto os outros recebem dependências manualmente pelo construtor.
Cada dependência extra não é apenas código adicional no binário. Ela aumenta a superfície de ataque para vulnerabilidades: de acordo com o GitHub Advisory Database (2025), 40 por cento dos CVEs críticos em projetos móveis vêm de dependências transitivas que os desenvolvedores não controlam. Quanto menos dependências, menor a superfície de ataque.
// 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
Para iOS, use o comando swift package show-dependencies, que exibe a árvore completa de dependências. A ferramenta Xcode Build Timeline mostra quanto tempo de compilação cada biblioteca adiciona. Se uma biblioteca ocupa 30 por cento do tempo de compilação, mas é usada em uma única tela, é candidata à remoção ou substituição.
Para Node.js (React Native), use depcheck — um utilitário que encontra dependências não utilizadas em package.json, e npm-check, que adicionalmente mostra versões desatualizadas. Implemente uma regra: cada nova dependência deve passar por revisão de código com uma justificativa de “por que ferramentas padrão não podem ser usadas.”
Importações mortas são o tipo mais comum de lixo. Elas não afetam o tempo de execução, mas aumentam o tempo de compilação: o compilador processa cada importação, mesmo as não utilizadas. Em projetos grandes, remover importações não utilizadas reduz o tempo de compilação em 5–10 por cento.
IDEs modernos destacam automaticamente importações não utilizadas em cinza. Configure a limpeza automática ao salvar: no IntelliJ IDEA — Optimize Imports on the fly, no Xcode — Editor > Remove Unused Imports. Adicione uma verificação no CI: o linter deve bloquear commits com importações não utilizadas.
Código comentado é outro tipo de lixo. Desenvolvedores comentam blocos para “não perder” funcionalidade durante a refatoração. No entanto, o git armazena o histórico completo de alterações: qualquer código removido pode ser restaurado com um único comando git revert ou git log -S
A regra: não há código comentado no repositório. Se o código não for necessário, exclua-o permanentemente. Se o código for necessário, mas estiver temporariamente desativado, use um feature toggle com um ticket e uma data de expiração. Comentários como // TODO: remove after migration — não os deixe sem prazo. Defina uma data e lembre-se com um calendário.
Superengenharia é a criação de camadas arquiteturais que não resolvem problemas atuais, mas exigem manutenção. Este é um dos tipos de lixo mais difíceis porque formalmente o código é “correto”: segue SOLID, é coberto por testes e está em conformidade com a arquitetura. O problema é que não é necessário.
Um exemplo clássico é uma classe abstrata UseCase com um único método invoke que simplesmente chama um repositório. Se o UseCase não adiciona lógica (cache, repetição, transformação) e apenas passa a chamada adiante, é uma entidade extra. Ela aumenta a navegação no projeto: um desenvolvedor abre o UseCase, vê invoke → repositório e o fecha. Tempo perdido, benefício zero.
Outro exemplo é a parametrização excessiva. Uma interface genérica com seis parâmetros de tipo usada em um único lugar. Cada parâmetro de tipo adiciona carga cognitiva: ao ler o código, é preciso manter seis tipos em mente enquanto apenas dois são realmente usados. Se uma abstração não é reutilizada, ela é redundante.
O critério de corte: se uma abstração não é reutilizada em três contextos diferentes, remova-a. Uma abstração é justificada quando realmente resolve um problema de duplicação, não quando prevê cenários hipotéticos futuros. YAGNI (You Ain’t Gonna Need It) é o melhor princípio para prevenir a superengenharia.
A auditoria de lixo requer uma combinação de análise estática, análise de dependências e revisão manual. É impossível automatizar completamente a detecção de abstrações redundantes, mas o lixo técnico (importações mortas, bibliotecas não utilizadas, código comentado) pode ser encontrado com ferramentas.
| Categoria | Ferramenta | O que verifica |
|---|---|---|
| Dependências não utilizadas | dependency-analysis (Gradle) | Bibliotecas não usadas no código |
| Dependências não utilizadas | depcheck (Node.js) | Pacotes de package.json sem importações |
| Dependências não utilizadas | swift package --show-dependencies | Árvore de dependências SwiftPM |
| Importações mortas | IDE (Optimize Imports) | Declarações import não utilizadas |
| Código comentado | grep -r “//” / rg “^\s*//” | Blocos de comentários com código |
| Métodos/classes vazios | SonarQube / CodeClimate | Métodos sem corpo ou com corpo vazio |
| Bibliotecas duplicadas | Gradle lint (duplicate classes) | Conflitos de classes de bibliotecas diferentes |
Para uma auditoria completa, execute buildHealth (Android) ou depcheck (Node.js) uma vez por sprint. Crie um painel no CI que mostre a tendência da quantidade de dependências ao longo dos sprints. Se a quantidade cresce, mas a funcionalidade não cresce proporcionalmente, a equipe está acumulando lixo.
Preste atenção às classes duplicadas — um erro que ocorre quando duas bibliotecas contêm a mesma classe. Isso não é apenas lixo, mas também uma fonte direta de conflitos de compilação. No Gradle, esses conflitos são resolvidos via force ou exclude, mas cada resolução é um sinal de que uma das bibliotecas é desnecessária.
A limpeza de lixo não é uma ação única, mas um processo regular. Sem um procedimento, o lixo retorna em dois ou três sprints. A melhor prática é alocar 10–15 por cento da capacidade de cada sprint para limpeza técnica, incluindo auditoria de lixo.
O processo consiste em quatro etapas. Primeira — diagnóstico: executar ferramentas, obter um relatório, priorizar. Alta prioridade: dependências com CVEs conhecidos e bibliotecas duplicadas. Média prioridade: importações mortas e código comentado. Baixa prioridade: abstrações redundantes (exigem análise manual).
Segunda — limpeza: remover dependências mortas, substituir bibliotecas duplicadas por uma, excluir código comentado. Cada alteração deve ser um commit separado com uma mensagem clara: “remove unused dependency: gson (replaced by kotlinx.serialization)”, “delete commented code in LoginViewModel.”
Terceira — verificação: compilar o projeto, executar testes, verificar a interface. Se os testes passarem após remover uma dependência, a dependência era realmente desnecessária. Se os testes falharem, há uma referência oculta que o analisador estático não detectou.
Quarta — prevenção: atualizar a lista de verificação de code review, adicionar uma regra “sem nova dependência sem justificativa” ao Definition of Done, configurar verificações automáticas no CI. A prevenção é a única maneira de evitar que o lixo se acumule novamente.
Perguntas frequentes
A dívida técnica é uma solução de compromisso consciente (rápida, mas de baixa qualidade) que se planeja corrigir. O lixo não é uma decisão consciente, mas lixo acumulado: dependências extras, código comentado, abstrações vazias que ninguém planejou nem quer manter.
O ritmo ideal é alocar 10 por cento de cada sprint para limpeza técnica. Isso mantém o lixo sob controle sem acumular massa crítica. Se um projeto tem muito lixo, comece com um grande sprint de limpeza e depois mude para um ritmo regular.
Meça e mostre os números: meça o tempo de compilação antes e depois de remover 3–5 dependências extras. Uma redução de 15–30 segundos por compilação multiplicada pelo número de compilações por dia dá horas de tempo economizado para a equipe. Os números convencem melhor do que chamados abstratos à limpeza.
Sim, especialmente se a dependência tiver um CVE. Mesmo que o projeto esteja estável, uma vulnerabilidade em uma dependência transitiva é um risco de segurança. Além disso, ao atualizar um SDK ou linguagem, uma dependência antiga pode se tornar incompatível, e removê-la antes da atualização economizará horas de migração.
Cada TODO sem ticket é lixo. Estabeleça uma regra: TODO é escrito apenas no formato // TODO(PROJECT-1234): fix vinculado a uma tarefa no tracker. Revise os TODOs regularmente e feche aqueles que perderam relevância. Remova TODOs expirados — se o problema não surgiu em seis meses, não é crítico.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também