Comprendere le Dipendenze…Visivamente!

Alza la mano chi di noi capisce veramente come il tuo strumento di automazione della compilazione costruisce il suo albero delle dipendenze? Ora, abbassate la mano se lo capite perché lavorate su strumenti di automazione della compilazione. Pensavo fosse così!

Una responsabilità frustrante degli ingegneri del software è comprendere le dipendenze del progetto: quali dipendenze transitive sono state introdotte e da chi; perché viene utilizzato v1.3.1 quando è stato dichiarato v1.2.10; cosa è risultato quando le dipendenze transitive sono cambiate; come è avvenuta la presenza di più versioni dello stesso artefatto?

Ogni ingegnere del software ha inviato un albero delle dipendenze in un file di testo, ha cercato specifici artefatti e poi ha risalito per identificare la sua origine. Per qualsiasi cosa diversa da progetti banali, creare una mappa mentale delle dipendenze è estremamente difficile, se non impossibile.

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: questo non è un tutorial su database grafici, né questo tutorial richiede una conoscenza dei database grafici. Se interessati, Neo4J ha tutorial e white papers per aiutarvi a iniziare.

Configura l’ambiente

Installa Java

È richiesto Java 11 o versioni successive. Se non è già disponibile, installa la tua versione preferita di OpenJDK.

Installare Neo4J

Il tutorial richiede un database Neo4J nel quale caricare le informazioni sulle dipendenze, preferibilmente non condiviso, poiché il caricatore svuota il database prima di ogni esecuzione. Sei stato avvisato!

Neo4J offre sandbox personali, ideali per progetti a breve termine come questo tutorial.

In alternativa, installa Neo4J localmente sul tuo desktop o notebook. Homebrew semplifica le installazioni su MacOS: 

Shell

 

brew install neo4j && brew services start neo4j

Prima di procedere, conferma l’accesso al tuo database Neo4J utilizzando il browser, utilizzando o il link e le credenziali per la sandbox Neo4J o localmente all’http://localhost:7474. Le credenziali predefinite per un’installazione locale sono neo4j/neo4j; dopo un login riuscito, ti viene chiesto di cambiare la password.

Clona i Repositori

Il repository neo4j-gradle-dependencies contiene le istruzioni per caricare le dipendenze in Neo4J. Questo tutorial genererà un grafo delle dipendenze per spring-boot. Devi clonare questi due repository.

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

Nota: Gradle locale non è necessario poiché entrambi i repository utilizzano il Gradle Wrapper, che scarica tutti i componenti necessari la prima volta che viene utilizzato il wrapper. 

Genera Dipendenze

Il DependencyLoader accetta come input l’albero delle dipendenze generato da Gradle. Sebbene sia possibile caricare insieme più configurazioni — ad esempio, compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath — partire con una singola configurazione è più semplice da navigare, specialmente per un tutorial.

Per generare le dipendenze per tutte le configurazioni: 

  • gradle dependencies
  • ./gradlew dependencies

Per generare le dipendenze per una singola configurazione

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

Genera Dipendenze Spring Boot

Questo tutorial crea un grafo delle dipendenze in Neo4J utilizzando le dipendenze compileClasspath di Spring Boot. Dal directory dove sono stati clonati i repository, eseguire i seguenti comandi:

Shell

 

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

Il file dependencies.out contiene le dipendenze di classpath a compile-time per Spring Boot.

Caricamento delle Dipendenze

In primo luogo, confermare l’URL di connessione e le credenziali di autenticazione in DependencyLoader.java e modificarli se necessario.

Eseguire i seguenti comandi per caricare le dipendenze di Spring Boot in 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"

Al successo, le linee di output da gradle sono:

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

Visualizzare le Dipendenze

Sono disponibili diversi strumenti per visualizzare i grafi Neo4J, ma lo strumento browser integrato è adeguato per questo tutorial.

Mostra l’Albero Completo

La query MATCH(a) RETURN a è l’equivalente relazionale di SELECT * FROM <table>

Visualizzare i Dettagli di un Artefatto

Ogni artefatto trovato crea un nodo le cui proprietà identificano l’artefatto (groupId/artifactId) e il suo tipo, mostrato nel pannello a destra.

Visualizza Dettagli di una Dipendenza

Ogni dipendenza viene creata come una relazione le cui proprietà identificano i dettagli della dipendenza: configurazione, versione specificata e configurazione. La dipendenza selezionata di seguito mostra spring-security:spring-web dipende da io.micrometer:micrometer-observation, ma la versione specificata 1.10.7 di spring-web è stata risolta come versione 1.11.0.

Naviga Dipendenze

Neo4J ti consente di esplorare il grafo nodo per nodo, permettendoti di espandere manualmente il grafo nodo per nodo, fornendo un modo per esplorare specifiche aree dell’albero delle dipendenze.

Supponiamo che tu voglia comprendere le dipendenze per l’artifact io.projectreactor.netty:reactor-netty-http. Innanzitutto, interroghiamo Neo4J per quel nodo specifico.

Cypher

 

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

Doppio cliccando sul nodo si visualizzano i nodi adiacenti — gli artifact(s) a cui è dipendente e gli artifact(s) da cui dipende.

Questo grafo espanso mostra un artifact che dipende da esso — la radice del progetto con un tipo di artifact PROJECT e altre sei dipendenze da cui dipende.

Successivamente, fai doppio clic su io.netty:netty-code https://github.com/netty/netty/tree/4.1/codec-httpc-http per mostrare il livello successivo di dipendenze. Si noti che oltre alle relazioni (dipendenze) del nodo selezionato, possono essere mostrate relazioni aggiuntive per i nodi già presenti nel grafico.

Identificare Disallineamento di Versione

L’output delle dipendenze di Gradle indica dove la versione specificata non era la versione risolta da Gradle. Le proprietà sulla dipendenza (relazione) possono essere utilizzate in una query Neo4J, limitando le relazioni mostrate e gli artefatti collegati (nodi).

Cypher

 

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

Neo4J può restituire risultati in formato tabulare per una verifica più agevole, se necessario.

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

Informazioni Aggiuntive

mappings.out

Il file mappings.out ti consente di personalizzare il tipo di artefatto assegnato a un nodo in base al groupId degli artefatti, comunemente per identificare in modo specifico gli artefatti creati dalla tua organizzazione.

Directory di Input

L’argomento della riga di comando per DependencyLoader può essere una directory contenente più alberi di dipendenze Gradle caricati nella stessa base di dati Neo4J. Ciò aiuta a comprendere le dipendenze di progetti correlati con file build.gradle separati.

Limitate e Omesse

Gradle identifica alcune dipendenze come Limitate e Omesse. Attualmente, quelle non vengono caricate ma sarebbe facile includerle, probabilmente creando proprietà aggiuntive per le relazioni.

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