One key to a stable application is a well-structured codebase. We know that we should build as many black boxes as possible, because as soon as one black box is finished, we no longer have to think about its interior. You just use the code you or another team member has written through a well-defined interface. This gives you the possibility to concentrate on the next feature you want to add.
When we think about black boxes we often have classes or whole jar packages in mind. Classes should of course be black boxes, no discussion about that. The same is true for jar packages. But in-between classes and jar packages there is another level of structure, which is often not seen this directly as a black box: packages.
Packages are often second class citizens and their interrelationship is not analyzed this thoroughly. But there is a great tool for such analysis: Structure101. It in general helps you to monitor and verify the dependency structures and complexity of your project by the means of well-organized diagrams.
So let’s start with a sample project. I have taken one of my own projects for this: japicmp is a tool to compute the differences between the API of two jar archives in means of what methods and classes have changed. structure101 has a great composition view, which shows you the dependencies between the packages of a project. This is how it looks for the current version of japicmp:
Cleary we can see for example that the cli package, which is responsible for the command-line parsing, uses the exception as well as the config package and is used itself by the main package, where the main() method resides. With the cli package everything seems to be OK. But what about the three packages cmp, util and model. The difference computation between the classes and methods, i.e. the business logic, resides in the package cmp. Hence it should use the model as well as the util package. But these two packages should not have any backward dependencies. This problem is also shown in the matrix view:
When we take a closer look at the tangle between these three packages, we see that the class AccessModifier, which is located in the cmp package, is used from the util package:
Beyond that, this class is also used in the model. This clearly indicates that the class should rather stay in the model package as in the cmp package. This seems to make sense, as the access modifiers of a class or method are part of the model of a jar archive and do not belong into the business logic. If we move this class to the model package, we get the following result:
This looks much better. We do not have any tangles within the package structure. The nice layout also shows clearly that the whole application depends on the model, as the package is located at the bottom of the diagram. The business logic, which resides within cmp, is called from the main package and uses util, config and the model, as it should be. The same is true for the output package, where the implementations for the cli and xml output reside. This package uses the config as well as the model, once it is computed.
Conclusion: Packages should not be second class citizens but help you to structure your application such that it is easy to overview the code and separate functionality. Tools like structure101 help you to analyze the dependencies between packages and therefore let packages be an important level between the jar on the one side and the class on the other side.