DevOps Zone is brought to you in partnership with:

I'm a programmer. Or at least, I intend to be a programmer but it's taking an awfully long time. I'm starting to wonder whether being a programmer is more about the journey towards being a programmer than being a programmer. Edmund is a DZone MVB and is not an employee of DZone and has posted 34 posts at DZone. You can read more from them at their website. View Full User Profile

A Simple Suggestion to Radically Improve Your Package Structure

02.26.2013
| 6436 views |
  • submit to reddit

Up Helly Aa 2011

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.

Tangled Rope

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.

Published at DZone with permission of Edmund Kirwan, author and DZone MVB.

(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.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.