의존성 이해…시각적으로!

손들어보세요, 우리 중 몇 명이나 정말로 빌드 자동화 도구가 의존성 트리를 어떻게 구축하는지 이해하고 있나요? 이제 빌드 자동화 도구를 개발하는 일을 하고 있기 때문에 이해하는 사람은 손을 내려놓으세요. 그랬죠!

소프트웨어 엔지니어들에게 가장 답답한 책임 중 하나는 프로젝트의 의존성을 이해하는 것입니다: 누가 어떤 전이적 의존성을 가져왔는지; 왜 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 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에 의존성을 로드하기 위한 것들이 포함되어 있습니다. 이 튜토리얼에서는 스프링 부트의 의존성 그래프를 생성합니다. 이 두 저장소를 복제해야 합니다.

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를 사용하므로, 래퍼가 처음 사용될 때 필요한 모든 구성 요소를 다운로드합니다.

의존성 생성

DependencyLoaderGradle에 의해 생성된 의존성 트리를 입력으로 사용합니다. 여러 구성을 동시에 로드할 수 있으나 — 즉, compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath — 튜토리얼의 경우 단일 구성으로 시작하는 것이 훨씬 더 쉽게 탐색할 수 있습니다.

모든 구성에 대한 의존성을 생성하려면:

  • gradle dependencies
  • ./gradlew dependencies

단일 구성에 대한 의존성을 생성하려면

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

스프링 부트 의존성 생성

이 튜토리얼은 스프링 부트의 compileClasspath 의존성을 사용하여 Neo4J에서 의존성 그래프를 생성합니다. 저장소가 복제된 디렉토리에서 다음 명령을 실행하십시오:

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는 스프링 부트의 컴파일 타임 클래스패스 의존성을 포함합니다.

의존성 로드

먼저 DependencyLoader.java에서 연결 URL과 인증 자격 증명을 확인하고 필요한 경우 수정하십시오.

다음 명령을 실행하여 스프링 부트 의존성을 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"

성공하면 그레이들의 출력 라인은 다음과 같습니다:

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 aSELECT * FROM <table>의 관계 동등물입니다.

아티팩트 세부 정보 보기

각 아티팩트가 발견되면 그 속성(groupId/artifactId)과 유형을 식별하는 노드가 생성되며, 오른쪽 패널에 표시됩니다.

의존성 세부 정보 보기

각 의존성은 구성, 지정된/버전 및 구성과 같은 특성을 식별하는 속성을 가진 관계로 생성됩니다. 아래에서 선택한 의존성은 spring-security:spring-webio.micrometer: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이고 그 아티팩트가 의존하는 다른 6개의 의존성을 보여줍니다.

다음으로, 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를 기반으로 노드에 할당된 아티팩트 유형을 사용자 지정할 수 있으며, 대개 조직에 의해 생성된 아티팩트를 구체적으로 식별하는 데 사용됩니다.

입력 디렉토리

디렉토리에 여러 Gradle 의존성 트리가 동일한 Neo4J 데이터베이스에 로드되는 것을 지정하는 DependencyLoader의 명령줄 인수는 build.gradle 파일을 가진 관련 프로젝트의 의존성을 이해하는 데 도움이 됩니다.

Gradle은 특정 의존성을 Constrained Omitted로 식별합니다. 현재 이러한 의존성은 로드되지 않으나, 관련 관계에 대한 추가 속성을 생성함으로써 쉽게 포함시킬 수 있습니다.

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