Search code examples
javamavengradlebuild-toolsdead-code

Dead code elimination from binaries on published artifacts, is it possible? Will it interfere with downstream dependency resolution?


I am using an artifact (of my own), and I'll be using maybe 25% of its functionality.

The other unused 75% is a lot of code and pre-allocated memory

This library contains things such as static final instances that serve as default states (for memory optimization), things that will be employed at length by other projects.

Some of the class structures are design as indexed/categorized components, like:

class Utils {
   static class OfArrays {}
   static class OfCollections {}
}

Other structures are inherited:

class Parent {
   static class ClassToBeUsedInArtifact extends Parent {}
   static class IgnoredClass extends Parent {}
}

Since the components I'll be using from this library are very important I wonder If I can crop everything that will not be used, out of the binary that will be published.

In the case that this is indeed possible (either because of some javac config, or because of the help of other build tools) I now have some concerns.

My main concern is that if these dependencies are cropped from the published binary (artifact), will downstream dependencies resolutions even be possible when other downstream branches find the dependency (that was cropped) once again?

example:

//Gradle keyword = `implementation` on all artifacts built.
SomeProject
   ├──(implementation) ArtifactC  (built with pruned ArtifactA and B)
   │            ├ (implementation)─ ArtifactB:1.0.0 
   │            └ (implementation)─ ArtifactA:1.0.0 
   ├──(implementation) ArtifactB:1.0.0 (built with pruned ArtifactA)
   │            └ (implementation)─ ArtifactA:1.0.1
   └──(implementation) ArtifactA:1.0.2 (full artifact)

If specialized build tools for dead (binary) code pruning are used:

Will the compiler (standard or not) be able to:

  1. perform dependency resolution on every instance of ArtifactA so that all 3 use the same version? (I assume the compiler will choose the latest ArtifactA:1.0.2)

  2. Will SomeProject's compiler be able to infer that ArtifactC should use ArtifactB instead of using the pruned version within it?

  3. I assume ArtifactC can be used without the need to implement both ArtifactB and B. Is this correct?

Now code pruning is one thing. I am assuming if other more specialized build tools are used, tools that force inlining and reordering to greater extents, then, will any of this hamper SomeProject's compiler's ability to perform the dependencies resolutions across these artifacts?


Solution

  • Unless you are very experienced and have really good reason to then don’t write nested classes.

    Proper usage of interfaces and package names and not using pre-initializedfields will go a long way of getting the isolation you want while not getting the coupling you don’t want. Also thorough unit tests are really good at discovering things you don’t want to happen.

    Don’t be smart. Write as clear code as you can. You will appreciate it later.