I hope we all agree that methods an classes should be small and have only few dependencies. This point of view is widely accepted, while the interpretation of “small” varies. There is lots of literature out there about this. But what about packages?
Some people consider packages just as namespaces. So packages are just things that allow you to reuse names for classes!?
I thought so about methods a couple of years ago: Just containers for reusable code.
Today I disagree with both statements. Methods are a very important tool to name a thing, to separate it from the rest, even when it is called only once.
Likewise packages have an important role even when we ignore the issue of names. Packages bundle together some functionality. They name that functionality and they should encapsulate it so we might reuse it. And just as with methods a package should have single purpose. It is probably a ‘bigger’ purpose than that of a method but still it should do only stuff directly related to that purpose.
Unfortunately in many projects this doesn’t work out well.
Here is a challenge. Pick a random package out of your current project. For this package answer the following questions
- What is the purpose of that package? Please use a single simple sentence. Does this sentence match the name of the package?
- Go through the classes of that package do they all work together to achieve the purpose of the class? Or are there classes in there that just ended up there by accident?
- Go through all the other classes of your system. Is none of them concerned with the single purpose of your package? Or are there classes that float around somewhere else that really should be in the package you are looking at?
- If your coworker in the next project needs basically the same package, how difficult would it be to extract the package from your code base and build it as a standalone jar?
In my experience it is very likely that the answers to the questions above are rather depressing. They certainly are in most projects I worked with.
Even when the classes and methods in that project are reasonable clean.
Why is that?
I think the reason is that problems with packages are not as obvious as with methods or classes. If a methods spans across the complete monitor you see that every time all the time you are working with the method. And since the method is long there is probably much work to be done in it. Same for classes. But with packages is different. I spend whole days coding without looking what is inside a package . I open my classes with shortcuts and name based search, no need to look inside packages.
So you won’t notice that classes concerned with completely different issues are together in one package. You won’t notice that the number of classes in a package exceeds any reasonable threshold.
And if it comes to the last question, the question about dependencies it becomes really ugly. What other packages does a package depend on? Which class contains that dependency? There is very limited tool support for this kind of question. And the question only gets asked late in a project, maybe when a sister project gets spawned that should reuse some of the code base so it should move in a common base project.
Since I have been there a couple of times I recommend to implement a couple of tests right in the beginning of a project using either JDepend or Dependency Finder:
- No cyclic dependencies between packages
- A maximum number of classes per package
- A fixed naming schema like <domain>.<project>.<module>.<layer>.<rest-of-package-name>
- A fixed direction of dependencies between modules (modules are vertical slices, often based on some domain concept)
- A fixed direction of dependencies between layers ( gui, presentation, domain, persistence are typical examples)
But be warned: these tests tend to be hard to keep satisfied. But if you put in the extra effort to keep your packages clean it has a significant positive impact on your application structure.