Levantem as mãos, quantos de nós realmente compreendem como a sua ferramenta de automação de construção cria sua árvore de dependências? Agora, abaixem a mão se você entende porque trabalha com ferramentas de automação de construção. Pensei assim!
Uma responsabilidade frustrante dos engenheiros de software é entender as dependências do seu projeto: quais dependências transitivas foram introduzidas e por quem; por que v1.3.1 é usado quando v1.2.10 foi declarado; o que resultou quando as dependências transitivas mudaram; como ocorreu a existência de múltiplas versões do mesmo artefato?
Cada engenheiro de software já canalizou uma árvore de dependências em um arquivo de texto, procurou por artefatos específicos e então trabalhou de volta para identificar sua origem. Para qualquer coisa além de projetos triviais, criar um mapa mental das dependências é extremamente difícil, senão impossível.
I faced this problem when starting a new job with a mature code base, presenting a challenge to assemble the puzzle pieces. I’ve previously worked with graph databases and thought a graphical view of the dependency artifacts could be created using Neo4J, which resulted in DependencyLoader.
Nota: este não é um tutorial sobre bancos de dados de grafos, nem este tutorial requer um background em bancos de dados de grafos. Se estiver interessado, o Neo4J possui tutoriais e white papers para ajudá-lo a começar.
Configurar Ambiente
Instalar Java
É necessário Java 11 ou posterior. Se ainda não estiver disponível, instale sua versão favorita de OpenJDK.
Instale o Neo4J
O tutorial requer um banco de dados Neo4J no qual a informação de dependência é carregada, preferencialmente não compartilhada, pois o carregador limpa o banco de dados antes de cada execução.Lembre-se disso!
Neo4J fornece caixas de areia pessoais, ideais para projetos de curto prazo como este tutorial.
Como alternativa, instale o Neo4J localmente no seu desktop ou laptop. Homebrew simplifica as instalações no MacOS:
brew install neo4j && brew services start neo4j
Antes de continuar, confirme o acesso ao seu banco de dados Neo4J usando o navegador, usando o link e credenciais para a caixa de areia Neo4J ou localmente em http://localhost:7474. As credenciais padrão para uma instalação local são neo4j/neo4j; após o login bem-sucedido, você é obrigado a alterar a senha.
Clone Repositórios
O repositório neo4j-gradle-dependencies contém as informações para carregar as dependências no Neo4J. Este tutorial irá gerar um grafo de dependência para spring-boot. Você deve clonar esses dois repositórios.
Scott.Sosna@mymachine src% git clone [email protected]:scsosna99/neo4j-gradle-dependencies.git
Scott.Sosna@mymachine src% git clone [email protected]:spring-projects/spring-boot.git
Nota: Gradle local não é necessário, pois ambos os repositórios utilizam o Gradle Wrapper, que baixa todos os componentes necessários na primeira utilização do wrapper.
Gerar Dependências
DependencyLoader
recebe a árvore de dependência gerada pelo Gradle como entrada. Embora várias configurações possam ser carregadas simultaneamente — por exemplo, compileClasspath
, runtimeClasspath
, testCompileClasspath
, testRuntimeClasspath
— começar com uma única configuração é mais simples de navegar, especialmente para um tutorial.
Para gerar dependências para todas as configurações:
gradle dependencies
./gradlew dependencies
Para gerar dependências para uma única configuração
gradle dependencies --configuration <configuration>
./gradlew dependencies --configuration <configuration>
Gerar Dependências do Spring Boot
Este tutorial cria um gráfico de dependência no Neo4J usando as dependências de classpath de compilação
do Spring Boot. A partir do diretório onde os repositórios foram clonados, execute os seguintes comandos:
Scott.Sosna@mymachine src% cd spring-boot/spring-boot-project/spring-boot
Scott.Sosna@mymachine spring-boot% ./gradlew dependencies --configuration compileClasspath > dependencies.out
O arquivo dependencies.out
contém as dependências de classpath de compilação para o Spring Boot.
Carregar Dependências
Primeiro, confirme a URL de conexão e as credenciais de autenticação em DependencyLoader.java e modifique-as se necessário.
Execute os seguintes comandos para carregar as dependências do Spring Boot no Neo4j:
Scott.Sosna@mymachine spring-boot% cd ../../../neo4j-gradle-dependencies
Scott.Sosna@mymachine neo4j-gradle-dependencies% ./gradlew clean run --args="../spring-boot/spring-boot-project/spring-boot/dependencies.out"
Quando bem-sucedido, as linhas de saída do gradle são:
Scott.Sosna@PVHY32M6KG neo4j-gradle-dependencies % ./gradlew clean run --args="../spring-boot/spring-boot-project/spring-boot/dependencies.out"
> Task :compileJava
Note: /Users/Scott.Sosna/data/src/github/neo4j-gradle-dependencies/src/main/java/dev/scottsosna/neo4j/gradle/relationship/DependsOn.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
> Task :run
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Jun 02, 2023 6:19:22 AM org.neo4j.driver.internal.logging.JULogger info
INFO: Direct driver instance 1606286799 created for server address localhost:7687
dependencies.out completed.
Jun 02, 2023 6:19:23 AM org.neo4j.driver.internal.logging.JULogger info
INFO: Closing driver instance 1606286799
Jun 02, 2023 6:19:23 AM org.neo4j.driver.internal.logging.JULogger info
INFO: Closing connection pool towards localhost:7687
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.5.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 3s
Visualizar Dependências
Várias ferramentas estão disponíveis para exibir gráficos Neo4J, mas a ferramenta de navegador interna é adequada para este tutorial.
Mostrar a Árvore Completa
A consulta MATCH(a) RETURN a
é o equivalente relacional de SELECT * FROM <tabela>
Ver Detalhes de um Artefato
Cada artefato encontrado cria um nó cujas propriedades identificam o artefato (groupId/artifactId) e seu tipo, mostrado na janela lateral direita.
Visualizar Detalhes de uma Dependência
Cada dependência é criada como uma relação cujas propriedades identificam os detalhes específicos da dependência: configuração, versão especificada e configuração. A dependência selecionada abaixo mostra spring-security:spring-web depende de io.micrometer:micrometer-observation, mas a versão especificada do spring-web 1.10.7 foi resolvida como versão 1.11.0.
Percorrer Dependências
O Neo4J permite explorar o grafo nó a nó, permitindo expandir manualmente o nó do grafo nó a nó, fornecendo uma maneira de explorar áreas específicas da árvore de dependências.
Suponha que você queira entender as dependências para o artefato io.projectreactor.netty:reactor-netty-http. Primeiro, faremos uma consulta ao Neo4J para aquele nó específico.
MATCH(a:Artifact {groupId: 'io.projectreactor.netty', artifactId: 'reactor-netty-http'}) RETURN a
Duplo clique no nó mostra seus nós vizinhos — os artefatos(s) que dependem dele e os artefatos(s) de que ele depende.
Esta árvore expandida mostra um artefato que depende dele — a raiz do projeto com um tipo de artefato PROJETO e outras seis dependências de que depende.
Em seguida, duplo clique em io.netty:netty-codehttps://github.com/netty/netty/tree/4.1/codec-httpc-http para mostrar o próximo nível de dependências. Observe que, além das relações (dependências) do nó selecionado, podem ser mostradas relações adicionais para nós já no gráfico.
Identificar Desalinhamento de Versão
A saída de dependência do Gradle indica onde a versão especificada não foi a versão resolvida pelo Gradle. As propriedades na dependência (relação) podem ser usadas em uma consulta Neo4J, restringindo as relações mostradas e os artefatos anexados (nós).
MATCH (a:Artifact)-[d:DEPENDS_ON]->(b:Artifact) WHERE d.specifiedVersion<>d.resolvedVersion RETURN a,b,d
O Neo4J pode retornar resultados em formato tabular para facilitar a revisão, se necessário.
MATCH (a:Artifact)-[d:DEPENDS_ON]->(b:Artifact) WHERE d.specifiedVersion<>d.resolvedVersion RETURNa.name AS source, b.name AS dependency, d.specifiedVersion AS specified, d.resolvedVersion AS resolved
Informações Adicionais
mappings.out
O arquivo mappings.out permite personalizar o tipo de artefato atribuído a um nó com base no groupId do artefato, geralmente para identificar especificamente os artefatos criados pela sua organização.
Diretório de Entrada
O argumento de linha de comando para DependencyLoader
pode ser um diretório contendo múltiplas árvores de dependências Gradle carregadas no mesmo banco de dados Neo4J. Isso ajuda a entender as dependências de projetos relacionados com arquivos build.gradle separados.
Restritas e Omitidas
Gradle identifica certas dependências como Restritas e Omitidas. Atualmente, essas não são carregadas, mas seria fácil incluí-las, provavelmente criando propriedades adicionais para as relações.
Source:
https://dzone.com/articles/understanding-dependenciesvisually