A Simple Suggestion to Radically Improve Your Package Structure
A burning issue.
Here's the thing.
In Java, all classes can see all the public classes in all other packages.
This blushing promiscuity generates astronomical quantities of potential coupling, the measure of the maximum number of dependencies that can be formed in a system. The more dependencies that can potentially form between packages, the greater the tendency that those dependencies will actually form, solidifying your package structure into a rigid creaking nightmare with ripple-effects up the wazoo.
Really, if your mattress is bulging with unwanted cash then paying programmers to maintain a pile of fabulously inter-dependent packages is a great way to get rid of it.
The solution's simple: restrict package access.
One way to achieve this is to allow packages to depend only on antecedents, that is, only on those packages that "come before" it in the package's fully-qualified name. This is radial encapsulation.
If you have package com.cheesepaint then it can depend only on the single package com.
If you have package com.cheesepaint.model then it can depend only on the two packages com.cheesepaint and com.
Any class in package com that depends on any class in either com.cheesepaint.model or com.cheesepaint is condemned to face the refactoring squad.
Objection, your honour!
You're thinking: hang on, how does this help?
This helps because it radically reduces the amount of dependencies that you can create in your system. At a stroke most of your packages will fall off one another's radars. With potential coupling slashed the tendency to form horribly-connected systems evaporates along with the ensuing costs.
Your honour, I really must object!
You're thinking: hang on, Java ain't got no such restriction.
No, it hasn't. This is an extra-linguistic rule. The compiler won't catch it. Enforce it by style guideline. Enforce it by code reviews. Write a script. Do it any way you like. The compiler won't help.
Your honour, this is an outrage!
You're thinking: hang on, what if I have com.cheesepaint.controller and it darn-tutin' has to depend on com.cheesepaint.model?
Two packages can only communicate via their (usually highest) common antecedent, which in this case is com.cheesepaint. So com.cheesepaint.model model must export a facade (family of classes or interfaces) into com.cheesepaint and com.cheesepaint.controller has to depend on that facade rather than on com.cheesepaint.model directly.
But, your ... !
You're thinking: hang on, Java only has one main() method: it can't be in both com.cheesepaint.controller and com.cheesepaint.model. So something must depend on both?
Yes of course this restriction is impossible to satisfy in Java but we won't let that stop us. Just make sure that whatever depends on both com.cheesepaint.controller and com.cheesepaint.model is utterly trivial: maybe only a Starter class that does nothing but tell the packages to store their facades in "lower" packages, ready for later use. The rule is relaxed only for such initialization maneuvers.
Summary
Slash package-access and thus slash potential coupling, frustration, development-time, hair-loss, weight-gain and costs.
Photo credit attribution.
CC Image Up Helly Aa 2011 courtesy of brockvicky on Flickr.
CC Image Tangled Rope courtesy of DaveOnFlickr on Flickr.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)








Comments
Andreas Schilling replied on Tue, 2013/02/26 - 1:48am
OSGi helps you alot better IMHO to stick to package borders.
Your bundle forms a closed space where classes can see the other public classes, to the outside only those packages that are exported can be seen from other bundles that depend on these bundles or packages.
I find this more appealing, because it actually IS enforced at compile time.
Kevin Chabot replied on Tue, 2013/02/26 - 6:43am
What about component-based composition? Imagine you have a page in package com.web.pages that would like to use a re-usable component from com.web.components? Same problem would apply when exposing components?
Steve Mcduff replied on Tue, 2013/02/26 - 11:34am
As applications grow, this solution would force either a lot of facade in common low level packages to exist or it would force package names that get longer and longer.
My personal solution was to use JDepend to scan each of my project for cycles in the package dependencies. My build script then triggers a build failure when a cycle is detected using a regular expression match on the JDepend output.
This way, it's perfectly fine for com.cheesepaint.controller to depend on com.cheesepaint.model. If anyone ever makes the mistake of introducing a relationship in the other direction, a build failure will promptly force the developer to redesign his change.
Edmund Kirwan replied on Wed, 2013/02/27 - 2:54pm
in response to:
Andreas Schilling
Few of those who keep untidy apartments automatically mend their messy ways on moving to large houses; the extra floors just take longer to clutter.
Edmund Kirwan replied on Wed, 2013/02/27 - 2:55pm
in response to:
Kevin Chabot
com.web.components would export an interface to the desired component into com.web
Edmund Kirwan replied on Wed, 2013/02/27 - 2:56pm
in response to:
Steve Mcduff
Having a lot of system-public facades in a few packages is a problem. Having a lot of system-public facades scattered all over a system is two problems.
Though your use of JDepend is an excellent way to avoid cyclic dependencies among packages. I wish more did that.