Понимание зависимостей… Визуально!

Поднимите руки, сколько из нас действительно понимает, как инструмент автоматизации сборки создает свой дерево зависимостей? Теперь опустите руку, если вы понимаете это, потому что работаете над инструментами автоматизации сборки. Думаю, так!

Одна из раздражающих обязанностей инженеров-программистов — понимание зависимостей вашего проекта: какие транзитивные зависимости были добавлены и кем; почему используется v1.3.1, когда была объявлена v1.2.10; что произошло, когда изменились транзитивные зависимости; как возникло несколько версий одного артефакта?

Каждый инженер-программист уже записывал дерево зависимостей в текстовый файл, искал конкретные артефакты и затем пробирался обратно, чтобы определить их происхождение. Для всего, кроме тривиальных проектов, создание ментальной карты зависимостей чрезвычайно сложно, если не невозможно.

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.

Примечание: это не учебник по графовым базам данных, и этот учебник не требует знаний в области графовых баз данных. Если интересует, Neo4J предлагает учебники и технические статьи для начала.

Настройка окружения

Установка Java

Требуется Java 11 или более поздняя версия. Если она еще не установлена, установите вашу любимую OpenJDK версию.

Установите Neo4J

В этом руководстве требуется база данных Neo4J, в которую загружается информация о зависимостях, предпочтительно не используемая совместно, так как загрузчик очищает базу данных перед каждым запуском. Вы предупреждены!

Neo4J предоставляет личные песочницы, идеальные для краткосрочных проектов, таких как этот учебник.

В качестве альтернативы, установите Neo4J локально на вашем настольном компьютере или ноутбуке. Homebrew упрощает установки на MacOS: 

Shell

 

brew install neo4j && brew services start neo4j

Перед продолжением убедитесь в доступе к вашей базе данных Neo4J через браузер, используя либо ссылку и учетные данные для песочницы Neo4J, либо локально по адресу http://localhost:7474. Учетные данные по умолчанию для локальной установки — neo4j/neo4j; после успешной авторизации вам придется сменить пароль.

Клонируйте Репозитории

Репозиторий neo4j-gradle-dependencies содержит инструкции для загрузки зависимостей в Neo4J. В этом учебнике будет сгенерирован граф зависимостей для spring-boot. Вам необходимо клонировать эти два репозитория.

Shell

 

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

Примечание: локальная установка Gradle не требуется, так как оба репозитория используют Gradle Wrapper, который при первом использовании загружает все необходимые компоненты.

Генерация зависимостей

Класс DependencyLoader принимает дерево зависимостей, сгенерированное Gradle в качестве входных данных. Хотя можно загружать несколько конфигураций одновременно — например, compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath — начать с одной конфигурации проще для понимания, особенно в учебнике.

Для генерации зависимостей для всех конфигураций:

  • gradle dependencies
  • ./gradlew dependencies

Для генерации зависимостей для одной конфигурации

  • gradle dependencies --configuration <configuration>
  • ./gradlew dependencies --configuration <configuration>

Генерация зависимостей Spring Boot

В этом руководстве создается граф зависимостей в Neo4J с использованием зависимостей compileClasspath Spring Boot. Из директории, где были клонированы репозитории, выполните следующие команды:

Shell

 

Scott.Sosna@mymachine src% cd spring-boot/spring-boot-project/spring-boot
Scott.Sosna@mymachine spring-boot% ./gradlew dependencies --configuration compileClasspath > dependencies.out

Файл dependencies.out содержит зависимости classpath во время компиляции для Spring Boot.

Загрузка Зависимостей

Сначала убедитесь, что URL подключения и учетные данные аутентификации в DependencyLoader.java верны и измените их при необходимости.

Выполните следующие команды для загрузки зависимостей Spring Boot в Neo4j:

Shell

 

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"

При успешном выполнении, вывод строк от gradle будет:

Shell

 

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

Просмотр Зависимостей

Существует несколько инструментов для отображения графов Neo4J, но встроенный браузерный инструмент достаточен для этого руководства.

Показать Полный Дерево

Запрос MATCH(a) RETURN a является эквивалентом реляционной записи SELECT * FROM <table>

Просмотр Деталей Артефакта

Каждый найденный артефакт создает узел, свойства которого идентифицируют артефакт (groupId/artifactId) и его тип, отображаемый в правом боковом панели.

Просмотр подробностей зависимости

Каждая зависимость создается как отношение, свойства которого определяют специфику зависимости: конфигурацию, указанную/версию и конфигурацию. Выбранная ниже зависимость показывает, что spring-security:spring-web зависит от io.micormeter:micrometer-observation, но указанная версия spring-web 1.10.7 была разрешена как версия 1.11.0.

Обход зависимостей

Neo4J позволяет исследовать граф узел за узлом, позволяя расширять граф узел за узлом вручную, предоставляя возможность исследовать конкретные области дерева зависимостей.

Предположим, вы хотите понять зависимости для артефакта io.projectreactor.netty:reactor-netty-http. Во-первых, мы запросим Neo4J для этого конкретного узла.

Cypher

 

MATCH(a:Artifact {groupId: 'io.projectreactor.netty', artifactId: 'reactor-netty-http'}) RETURN a

Двойной щелчок по узлу показывает его соседние узлы — артефакты, от которых он зависит, и артефакты, на которые он зависит.

Этот расширенный граф показывает один артефакт, который зависит от него — корень проекта с типом артефакта PROJECT и шесть других зависимостей, от которых он зависит.

Далее, дважды кликните по io.netty:netty-code https://github.com/netty/netty/tree/4.1/codec-httpc-http, чтобы показать следующий уровень зависимостей. Обратите внимание, что помимо отношений (зависимостей) выбранного узла, могут отображаться дополнительные отношения для уже существующих на графике узлов.

Определение Несоответствия Версий

Вывод зависимостей Gradle указывает, где указанная версия не соответствует версии, решенной Gradle. Свойства зависимости (отношения) могут быть использованы в запросе Neo4J, ограничивая отображаемые отношения и присоединенные артефакты (узлы).

Cypher

 

MATCH (a:Artifact)-[d:DEPENDS_ON]->(b:Artifact) WHERE d.specifiedVersion<>d.resolvedVersion RETURN a,b,d

Neo4J может возвращать результаты в табличном формате для удобного просмотра, если это необходимо.

Cypher

 

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

Дополнительная Информация

mappings.out

Файл mappings.out позволяет настроить тип артефакта, назначенный узлу, на основе groupId артефактов, чаще всего для конкретного определения артефактов, созданных вашей организацией.

Входная Папка

Аргумент командной строки для DependencyLoader может быть директорией, содержащей несколько Gradle деревьев зависимостей, загруженных в одну базу данных Neo4J. Это помогает понять зависимости связанных проектов с отдельными build.gradle файлами.

Ограниченные и Исключенные

Gradle идентифицирует некоторые зависимости как Ограниченные и Исключенные. В настоящее время они не загружаются, но их легко можно включить, вероятно, создав дополнительные свойства для отношений.

Source:
https://dzone.com/articles/understanding-dependenciesvisually