From 246b15d8d25eb8e4a073370661ae3037b9c0dd69 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Thu, 29 Oct 2020 11:42:12 -0400 Subject: [PATCH 1/3] Declare all dependencies --- docs/JLBP-0022.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/JLBP-0022.md diff --git a/docs/JLBP-0022.md b/docs/JLBP-0022.md new file mode 100644 index 0000000000..0a369f36d5 --- /dev/null +++ b/docs/JLBP-0022.md @@ -0,0 +1,56 @@ +--- +jlbp: + id: JLBP-22 +permalink: /JLBP-22 +--- + +# Declare all dependencies + +If your code references a class—for example, by invoking a method in that class—declare a dependency that includes that class in your pom.xml, build.gradle, +or equivalent. In Bazel this practice is called "strict deps". + +Code should not call methods, reference fields, or instantiate classes from _indirect_ dependencies. These are dependencies of the declared dependencies. Projects that rely on indirect dependencies have an annoying habit of breaking in unexpected ways when direct dependencies are upgraded. + +For example, your project might declare a dependency on the +Google HTTP Java Client which +itself depends on the Apache HTTP Components. If so, it is possible to use the `org.apache.http.client.utils.URLEncodedUtils` method in your own project without +explicitly declaring a dependency on Apache HTTP Components. However, you should +add the dependency anyway. This way if a future version of the +Google HTTP Java Client no longer depends on Apache HTTP Components, your code will +still compile and work. Strict dependencies also help static analysis tools better understand a project. + +This doesn't only happen when a project itself is upgraded. It can also +happen when dependency mediation selects a different version of a library's dependency +that does not include the necessary indirect dependency. Relying on indirect dependencies can cause problems for your customers that you don't see. + +IDE autocomplete suggestions are a common way projects come to depend on +indirect dependencies. When importing a new class, most IDEs only look to see if it's present in the classpath, not whether it comes from a direct or indirect dependency. + +The `mvn dependency:analyze` command lists dependencies a Maven project uses +but hasn't declared: + +``` +[WARNING] Used undeclared dependencies found: +[WARNING] org.apache.maven.resolver:maven-resolver-impl:jar:1.4.1:compile +[WARNING] org.apache.maven.resolver:maven-resolver-api:jar:1.6.1:compile +[WARNING] org.apache.maven:maven-core:jar:3.6.3:compile +[WARNING] org.apache.maven:maven-model-builder:jar:3.6.3:compile +``` + +These should be added to your pom.xml file. + +The tool also lists dependencies the project declares but doesn't use: + +``` +[WARNING] Unused declared dependencies found: +[WARNING] com.google.cloud.tools:dependencies:jar:1.5.5-SNAPSHOT:compile +[WARNING] com.google.truth:truth:jar:1.0.1:test +[WARNING] junit:junit:jar:4.13.1:test +[WARNING] org.mockito:mockito-core:jar:3.5.15:test +``` + +However its analysis of which dependencies aren't used is not as accurate +as its analysis of which dependencies are used. In particular, +it reports dependencies used through reflection as unused, so be cautious when +removing any allegedly unused dependencies. + \ No newline at end of file From af8178fdd871d74b6e4b3dd7b21e6753f917fc2c Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Thu, 29 Oct 2020 13:41:20 -0400 Subject: [PATCH 2/3] code review --- docs/JLBP-0022.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/JLBP-0022.md b/docs/JLBP-0022.md index 0a369f36d5..364d566425 100644 --- a/docs/JLBP-0022.md +++ b/docs/JLBP-0022.md @@ -4,20 +4,20 @@ jlbp: permalink: /JLBP-22 --- -# Declare all dependencies +# Declare all direct dependencies If your code references a class—for example, by invoking a method in that class—declare a dependency that includes that class in your pom.xml, build.gradle, or equivalent. In Bazel this practice is called "strict deps". -Code should not call methods, reference fields, or instantiate classes from _indirect_ dependencies. These are dependencies of the declared dependencies. Projects that rely on indirect dependencies have an annoying habit of breaking in unexpected ways when direct dependencies are upgraded. +Code should not call methods, reference fields, or instantiate classes from _indirect_ dependencies. These are dependencies of the declared dependencies. Projects that rely on indirect dependencies tend to break in unexpected ways when direct dependencies are upgraded. For example, your project might declare a dependency on the Google HTTP Java Client which -itself depends on the Apache HTTP Components. If so, it is possible to use the `org.apache.http.client.utils.URLEncodedUtils` method in your own project without +itself depends on the Apache HTTP Components. If so, it is possible to use the `org.apache.http.client.utils.URLEncodedUtils` class in your own project without explicitly declaring a dependency on Apache HTTP Components. However, you should add the dependency anyway. This way if a future version of the -Google HTTP Java Client no longer depends on Apache HTTP Components, your code will -still compile and work. Strict dependencies also help static analysis tools better understand a project. +Google HTTP Java Client no longer depends on Apache HTTP Components, your code +still compiles. Strict dependencies also help static analysis tools better understand a project. This doesn't only happen when a project itself is upgraded. It can also happen when dependency mediation selects a different version of a library's dependency From 6d9e34ec250a92ad484c56ce416ce572b54ebb2e Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Fri, 30 Oct 2020 10:31:01 -0400 Subject: [PATCH 3/3] code review --- docs/JLBP-0022.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/JLBP-0022.md b/docs/JLBP-0022.md index 364d566425..0a174162bd 100644 --- a/docs/JLBP-0022.md +++ b/docs/JLBP-0022.md @@ -15,13 +15,15 @@ For example, your project might declare a dependency on the Google HTTP Java Client which itself depends on the Apache HTTP Components. If so, it is possible to use the `org.apache.http.client.utils.URLEncodedUtils` class in your own project without explicitly declaring a dependency on Apache HTTP Components. However, you should -add the dependency anyway. This way if a future version of the +add the dependency anyway so that if a future version of the Google HTTP Java Client no longer depends on Apache HTTP Components, your code still compiles. Strict dependencies also help static analysis tools better understand a project. -This doesn't only happen when a project itself is upgraded. It can also -happen when dependency mediation selects a different version of a library's dependency -that does not include the necessary indirect dependency. Relying on indirect dependencies can cause problems for your customers that you don't see. +Code breakages due to indirect dependencies don't just +happen when a library is upgraded. They can also +occur when dependency mediation selects a different version of a library's dependency +that does not include the necessary indirect dependency. Relying on indirect dependencies cause problems for clients with different dependency trees +that don't appear in your own code. IDE autocomplete suggestions are a common way projects come to depend on indirect dependencies. When importing a new class, most IDEs only look to see if it's present in the classpath, not whether it comes from a direct or indirect dependency.