Quem trabalha há bastante tempo com Delphi provavelmente já encontrou units com cláusulas uses enormes, formadas por dezenas de dependências que ninguém sabe ao certo se ainda são necessárias. Algumas foram adicionadas automaticamente pela IDE, outras eram utilizadas por trechos de código que já não existem e muitas permanecem na seção interface mesmo sendo necessárias apenas na implementação. Embora pareça um problema meramente estético, esse acúmulo pode aumentar o acoplamento entre as units, dificultar a manutenção e ampliar desnecessariamente o impacto de cada alteração realizada no projeto.
Remover essas dependências manualmente nem sempre é simples. Excluir uma unit da cláusula uses, compilar o projeto e repetir o processo até encontrar todas as dependências desnecessárias pode consumir muito tempo, principalmente em sistemas antigos ou de grande porte. Além disso, algumas units possuem efeitos colaterais durante a inicialização da aplicação e não podem ser removidas apenas porque seus símbolos não aparecem diretamente no código. É nesse cenário que o Atropos se apresenta como uma ferramenta interessante para a comunidade Delphi.
O Atropos é um projeto open source (github.com/ViniAbreu/Atropos) criado para analisar e otimizar automaticamente as cláusulas uses de projetos Delphi. A ferramenta identifica units aparentemente não utilizadas, verifica quais dependências podem ser transferidas da seção interface para a seção implementation e modifica os arquivos de código. Depois disso, ela tenta compilar o projeto para confirmar que as alterações continuam válidas. Se a compilação falhar, os arquivos modificados são restaurados automaticamente.
Por que uma cláusula uses limpa é importante?
Durante a evolução de um sistema, é natural que suas dependências mudem. Classes são substituídas, telas são refatoradas, bibliotecas deixam de ser utilizadas e funcionalidades inteiras são removidas. Entretanto, as referências adicionadas à cláusula uses frequentemente permanecem no código, pois o compilador normalmente não exige que o desenvolvedor elimine todas as units sem uso.
Com o passar do tempo, uma unit pode acabar com uma estrutura semelhante a esta:
unit MinhaUnit;
interface
uses
System.SysUtils,
System.Classes,
System.Generics.Collections,
Vcl.Forms,
Vcl.Dialogs,
MinhaUnitAntiga,
OutraUnitNaoUtilizada;
Nesse exemplo, algumas dependências podem ser essenciais, outras talvez sejam necessárias apenas na implementação e algumas podem não ser utilizadas em nenhum ponto do arquivo. Quando esse padrão se repete por centenas ou milhares de units, o projeto acumula uma rede de dependências maior e mais confusa do que deveria.
Uma cláusula uses mais enxuta facilita a leitura porque comunica melhor as responsabilidades da unit. Ao abrir o arquivo, o desenvolvedor consegue reconhecer com mais facilidade quais bibliotecas e componentes fazem parte daquele código. A limpeza também reduz ruídos durante refatorações e ajuda a revelar relações arquiteturais que poderiam passar despercebidas em meio a uma longa lista de referências.
A diferença entre interface e implementation
No Delphi, não basta saber que uma unit está sendo utilizada. Também é importante entender em qual seção ela deve ser declarada. Quando uma dependência aparece na seção interface, ela passa a participar do contrato público da unit e pode influenciar outras partes do projeto que dependem desse contrato. Isso é necessário quando um tipo externo aparece na declaração de uma classe, em um parâmetro, no retorno de um método, em uma propriedade ou em outra definição pública.
Por outro lado, se a dependência é utilizada exclusivamente dentro da implementação de um método, geralmente não existe motivo para expô-la na interface. Nesse caso, ela pode ser movida para a seção implementation, deixando explícito que se trata de um detalhe interno:
unit MinhaUnit;
interface
uses
System.SysUtils;
type
TMeuServico = class
public
procedure Executar;
end;
implementation
uses
MinhaDependenciaInterna;
Essa mudança aparentemente pequena melhora o encapsulamento e reduz o acoplamento. A interface pública passa a declarar apenas aquilo que seus consumidores realmente precisam conhecer, enquanto os detalhes internos permanecem escondidos. Em projetos grandes, essa separação também pode diminuir recompilações em cascata, pois uma mudança em uma dependência interna tende a afetar menos units do que uma alteração em uma dependência exposta publicamente.
Identificar manualmente todas as referências que podem ser movidas exige atenção, especialmente quando o projeto possui código legado, diretivas condicionais e diferentes configurações de compilação. O Atropos procura automatizar justamente essa análise.
Como o Atropos realiza a análise
O processo começa pela leitura do arquivo .dproj, utilizado para conhecer a estrutura do projeto e as units que fazem parte dele. Esse contexto é importante porque uma análise isolada de cada arquivo Pascal não seria suficiente para compreender corretamente os caminhos de busca, as dependências existentes e a forma como o projeto é compilado.
Em seguida, o Atropos utiliza a biblioteca DelphiAST para transformar o código Pascal em uma Abstract Syntax Tree, ou árvore sintática abstrata. Em vez de tratar o arquivo como um simples conjunto de palavras, a ferramenta passa a enxergar seus elementos estruturais, como declarações de tipos, métodos, identificadores e seções da unit. Essa abordagem oferece muito mais precisão do que uma busca textual, que poderia confundir comentários, nomes semelhantes e ocorrências sem significado semântico.
Com a árvore sintática disponível, a ferramenta cruza os identificadores utilizados no código com os símbolos exportados pelas units importadas. O objetivo é descobrir quais dependências são efetivamente necessárias e em qual parte do arquivo elas aparecem. Uma unit completamente sem uso pode ser indicada para remoção, enquanto uma dependência utilizada apenas no corpo dos métodos pode ser transferida da interface para a implementation.
Depois de modificar os arquivos, o Atropos executa uma compilação do projeto. Essa etapa funciona como uma rede de segurança: se as alterações produzirem algum erro, a ferramenta realiza o rollback e restaura os arquivos anteriores. A validação por compilação não substitui uma suíte de testes, mas reduz consideravelmente o risco de permanecer com um projeto que nem sequer pode ser construído.
Uma abordagem conservadora para evitar efeitos colaterais
Um dos desafios desse tipo de ferramenta é que uma unit pode ser importante mesmo quando nenhum de seus símbolos aparece explicitamente no código. O exemplo mais conhecido é uma unit que possui uma seção initialization. Apenas incluí-la na cláusula uses pode ser suficiente para registrar classes, configurar bibliotecas, instalar handlers ou executar outras operações necessárias para o funcionamento do sistema.
Remover automaticamente uma dependência desse tipo poderia manter o projeto compilável e, ainda assim, modificar seu comportamento durante a execução. Por esse motivo, o Atropos adota uma estratégia conservadora e preserva units que possuem blocos de inicialização.
A ferramenta também evita alterar referências protegidas por diretivas condicionais, como {$IFDEF}, pois uma dependência aparentemente desnecessária na configuração atual pode ser obrigatória em outra plataforma ou combinação de símbolos de compilação. Units que não podem ser encontradas nos caminhos de pesquisa também são ignoradas, já que a ausência de informações suficientes impede uma análise segura.
Essas limitações não devem ser vistas como falhas, mas como decisões de segurança. Em uma ferramenta de refatoração automática, reconhecer os casos em que não há informação suficiente para agir é tão importante quanto identificar as oportunidades de alteração.
Benefícios para projetos Delphi
O benefício mais evidente é a redução do trabalho manual. Em vez de remover cada referência individualmente e recompilar o sistema várias vezes, o desenvolvedor pode utilizar o Atropos para analisar o projeto de forma automatizada, gerar um relatório e revisar as alterações propostas.
A reorganização das dependências também pode melhorar a arquitetura do software. Quando uma unit permanece na seção interface, ela se torna parte da rede pública de dependências. Movê-la para a implementation ajuda a esconder detalhes internos, diminui o conhecimento entre componentes e aproxima o código de princípios como encapsulamento e baixo acoplamento.
Outro possível ganho está no tempo de compilação. Dependências declaradas na interface podem provocar recompilações em cadeia quando são alteradas. Ao manter apenas as referências realmente públicas nessa seção, reduz-se a quantidade de arquivos potencialmente afetados. O impacto concreto depende do tamanho e da organização do sistema, mas tende a ser mais perceptível em bases de código extensas.
A limpeza também pode beneficiar ferramentas da IDE, como Code Insight e servidores de linguagem. Uma árvore de dependências menos carregada significa menos elementos para indexar e analisar. Além disso, a remoção de units verdadeiramente desnecessárias pode permitir que o linker descarte código que não precisa fazer parte do executável, embora o efeito sobre o tamanho final varie de acordo com cada projeto.
Como utilizar o Atropos
O projeto oferece uma aplicação gráfica desenvolvida com VCL e uma versão para linha de comando. A interface gráfica é conveniente para o uso manual, enquanto a CLI pode ser incorporada a scripts e rotinas de manutenção.
Um exemplo de execução pela linha de comando é:
AtroposCLI.exe -dproj "C:\Caminho\MeuProjeto.dproj" --remove --move -html
Nesse comando, -dproj informa o caminho do projeto, --remove solicita a remoção das units consideradas desnecessárias, --move habilita a transferência de dependências da interface para a implementation e -html gera um relatório no formato HTML.
Os parâmetros disponíveis incluem:
| Parâmetro | Finalidade |
|---|---|
-dproj <caminho> | Informa o arquivo .dproj que será analisado |
--remove | Remove units consideradas não utilizadas |
--move | Move dependências da interface para a implementation |
-html | Gera um relatório em HTML |
-txt | Gera um relatório em texto |
--debug | Ativa registros detalhados para diagnóstico |
Para executar somente a remoção de dependências, pode-se utilizar:
AtroposCLI.exe -dproj "C:\Projetos\Sistema\Sistema.dproj" --remove
Para reorganizar as dependências e gerar um relatório textual:
AtroposCLI.exe -dproj "C:\Projetos\Sistema\Sistema.dproj" --move -txt
Recomendações antes de executar
Apesar do mecanismo automático de rollback, o Atropos deve ser utilizado como qualquer outra ferramenta de refatoração: com controle de versão, revisão das alterações e testes. O ideal é começar com o projeto compilando e com a árvore de trabalho limpa. Dessa forma, o desenvolvedor consegue comparar exatamente o que foi modificado e reverter manualmente qualquer alteração, caso necessário.
Também é recomendável executar a ferramenta inicialmente em uma branch separada. Depois da análise, revise o diff, examine o relatório gerado, compile o sistema em todas as configurações relevantes e execute a suíte de testes. Projetos que utilizam diferentes plataformas, símbolos condicionais ou configurações de build merecem atenção especial, pois uma compilação bem-sucedida em um ambiente não garante que todas as combinações possíveis continuem funcionando.
A compilação automática confirma que o código permanece válido para o compilador, mas não consegue assegurar sozinha que todas as regras de negócio foram preservadas. Testes automatizados e verificações manuais continuam sendo necessários, especialmente em aplicações que dependem de registros realizados durante a inicialização das units.
A arquitetura do próprio Atropos
Além da proposta da ferramenta, a organização de seu código também merece atenção. O repositório separa o domínio, os serviços de aplicação, as portas do núcleo, os adaptadores de infraestrutura, a interface de linha de comando, a aplicação gráfica VCL e os testes automatizados.
Os detalhes externos, como acesso ao sistema de arquivos, compilação, geração de relatórios, interpretação do .dproj, descoberta do ambiente Delphi e integração com o DelphiAST, ficam organizados em adaptadores. O núcleo da aplicação trabalha por meio de abstrações, evitando depender diretamente da interface gráfica ou de mecanismos específicos de infraestrutura.
Essa estrutura segue os princípios da arquitetura hexagonal, também conhecida como Ports and Adapters. Na prática, isso permite que a versão gráfica e a versão de linha de comando compartilhem as mesmas regras de análise e modificação. Também facilita a substituição de componentes, a criação de testes e a evolução do projeto sem misturar regras de negócio com detalhes da interface.
Projeto open source
O código-fonte do Atropos está disponível publicamente no GitHub sob a licença GPL 3.0. No repositório é possível consultar a implementação, acompanhar a evolução do projeto, relatar problemas e enviar contribuições:
As versões publicadas podem ser consultadas na página de releases. Desenvolvedores interessados também podem abrir issues com sugestões, enviar pull requests ou simplesmente marcar o repositório com uma estrela para demonstrar apoio ao projeto.
Conclusão
A cláusula uses pode parecer apenas um detalhe da linguagem, mas ela representa parte importante da rede de dependências de uma aplicação Delphi. Quando essa rede cresce sem controle, o código se torna mais acoplado, mais difícil de compreender e potencialmente mais demorado para compilar. Manter essas referências organizadas é uma tarefa importante, mas que costuma ser deixada de lado por exigir tempo e envolver certo risco.
O Atropos procura tornar essa manutenção mais prática ao combinar análise sintática, remoção de dependências, reorganização entre interface e implementation, geração de relatórios, compilação de validação e rollback automático. Sua abordagem conservadora também demonstra preocupação com situações nas quais uma remoção aparentemente correta poderia causar efeitos colaterais.
Para quem mantém projetos Delphi antigos ou de grande porte, o Atropos pode ser uma ferramenta útil na redução gradual da dívida técnica. Com controle de versão, revisão cuidadosa e uma boa suíte de testes, ele ajuda a transformar uma atividade repetitiva e arriscada em um processo mais rápido, previsível e seguro.
Se você desenvolve em Delphi, vale a pena conhecer o Atropos no GitHub, executá-lo em uma branch separada e descobrir quais dependências desnecessárias podem estar escondidas no seu projeto.
Descubra mais sobre Régys Borges da Silveira
Assine para receber nossas notícias mais recentes por e-mail.
Dê-nos sua opinião, seu comentário ajuda o site a crescer e melhorar a qualidade dos artigos.