• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

organizing classes into packages

 
boyet silverio
Ranch Hand
Posts: 173
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
how does one organize classes into packages? How would the following fare?
say in an mvc application, one way would be to do as follows (e.g. based on component function in a pattern):
package model;
package view;
package controller;
another way would be something based on business areas like
package savings;
package loans;
which one is better? is this a matter of style/taste? what are other considerations (other than class accessibility)? advantages? say for team work?
(In a different thread/topic I had been recommended, by Ilja, a book - Agile SW Development by Martin - which may have something on this topic based on its online table of contents, but I'm still in the process of scraping for the "hefty" USD 55 needed to buy the book... meanwhile...)
Thanks for your comments.
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I don't wish this to sound flippant, but I almost always start with everything in one package named for the project (e.g. com.efsol.friki ). I only split this into multiple packages if I really have to, typically if the list of classes in the package gets too unwieldy to browse.
Can you offer any tangible benefits of splitting into packages from the start?
 
boyet silverio
Ranch Hand
Posts: 173
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks there Frank, I actually don't split the packages from the start. I guess I was just in a hurry to get immediately to what i'd like to know. Ok the previous sample packages should be something like
say in an mvc application, one way would be to do as follows (e.g. based on component function in a pattern):
package myCompany.myApp.model;
package myCompany.myApp.view;
package myCompany.myApp.controller;
another way would be something based on business areas like
package myCompany.myApp.savings;
package myCompany.myApp.loans;
(the rest are up there in previous post)
[ June 26, 2003: Message edited by: boyet silverio ]
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by boyet silverio:
(In a different thread/topic I had been recommended, by Ilja, a book - Agile SW Development by Martin - which may have something on this topic based on its online table of contents, but I'm still in the process of scraping for the "hefty" USD 55 needed to buy the book... meanwhile...)


Yes, it handles that topic.
Another good starting point to read about the forces of package design is http://c2.com/cgi/wiki?PackageDesign
But Frank is right: Package design isn't something you can decide about up front - it needs to evolve over time, as needs become apparent. Doubly so as the principles discussed in the resources above are sometimes at odds and the balance point might even shift through the development of the project (for example early in the project the CCP might be more important, later on the CRP gains weight).
Did that help?
 
boyet silverio
Ranch Hand
Posts: 173
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
thanks Frank & Ilja. I could work up on your comments. I've a feeling though that I may be giving too much attention than necessary about this packaging thing. Anyway as i've said your comments are a good start for me.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Look into package dependency analysis tools for very large code bases. JDepends is a good freebie. Bob Martin is a prime mover in this area, and recommends running a tool like this maybe every major release. I think some of the theory in that wiki page can really pay off!
Recent experience. I'm on a very large vendor product now that the vendor packaged by architectural layers. All the panels are in one package, all the activity (command) classes in another, all the proxies to the server in another, and so on. This means that no vertical business function can be carved out for reuse. To reuse any function, say a customer tracker, you have to take the entire system. There are big parts of the purchased product that we don't use, but there is no way to *not* build and deploy them. Yuck.
Next time I'll package in horizontal slices by architctural layer, but also in vertical slices by business function. And use a dependency analysis tool.
[ June 26, 2003: Message edited by: Stan James ]
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To reuse any function, say a customer tracker, you have to take the entire system. There are big parts of the purchased product that we don't use, but there is no way to *not* build and deploy them. Yuck.
Really? I've found the use of packages to usually be more of a "code layout" than an "application structure" thing. Do you actually build individual packages?
I habitually use genjar (from http://sourceforge.net/projects/genjar ) to trim the fat from bloatware. It lets you build a jar which only includes classes which are actually used, regardless of which package they come from.
Is there something else preventing you from cutting out unused classes ?
 
Junilu Lacar
Sheriff
Posts: 17644
300
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You might find this JavaWorld article helpful.
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for that article.
I agreed with just about all of it until it recommended putting all your general class-independent methods into one huge static-utilities class.
I used to do this, but have discovered that it can unexpectedly bloat small applications. Such an approach implies that even using one small static method like:

will bring in the whole "utility" class. And such "mondo" utility classes can often be much larger than any other class in a well-factored system.
I now tend to split such static methods either each into its own class or at least into small related groups to reduce the overall size of the final application if it doesn't use all of the utilities.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
Is there something else preventing you from cutting out unused classes?


Well, it's often much more convenient to reuse whole jar files without having to repackage them. In fact the above mentioned principles are much more important when packaging into jar files than when putting classes into java packages. Personally, I prefer to not split java packages between different jar files, though.
http://xml.apache.org/batik/install.html#jarFiles is an interesting example of such a jar file packaging.
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hmm.
At heart, packages are simply namespaces. Jar files, on the other hand, are deliverables.
A jar file should have everything that someone downloading it might need, otherwise it's really hard to tell what should be downloaded. The fact that batik seems to need such a complex diagram of its own internal code astonishes me. I'd just put all the classes from all the batik jars into one big single download.
Does anyone still do this kind of "manual linking" where some jar files are included in the classpath, and some are not. Whether your program works or crashes depends on whether any of the unsatisfied methods are accidentally called or not. Scary!
The way I work is to put all my general-purpose classes into one big jar file (currently about 220K), then run genjar against my application specific code to build a new application-specific jar file using only the utility classes that are actually used. Even my most complex application jar files are usually less than about 60K, including the bits they need from the general utilities.
This way, there's no chance of "class not found" problems (if you don't use Class.forName(), but that can always fail), and you get a small, complete application.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I was thinking of packages as units of reuse:


The Reuse-release Equivalence Principle (REP)
The granule of reuse is the granule of release
This principle is based on the idea that packages rather than individual classes are the units of reuse. If a package is to be reused, all classes in that package should be designed for reuse.
The Common Reuse Principle (CRP)
The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.
This principle is also based on the idea that packages rather than individual classes are the units of reuse. Classes that are intended to be reused together, should be put in the same package.


Quote taken from http://javacentral.compuware.com/pasta/concepts/packageDesign.html which is a nice overview, even with the caveat that it is advertising for a tool that derives goodness numbers for these principles. Follow the link to layering, too.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Frank, I'd guess Batik's diagram is not astonishingly complex, but unusually clean. I saw only one cyclical dependency. See examples here for some frightening diagrams of java packages.
I'll keep an open mind and look more into GenJar, but at first glance it looks like a hack to get somebody out of trouble for not observing better practices. It lets you not know your dependencies and not care whether they are good or bad. Of course, that might mean they aren't good or bad. If I believe that, I have a good use for it.
[ June 26, 2003: Message edited by: Stan James ]
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'd guess Batik's diagram is not astonishingly complex, but unusually clean. I saw only one cyclical dependency
I'd agree if the batik diagram was a class diagram, or maybe if it was a package diagram. But it's not. Each "blob" is a jar file, and I see no sensible reason for that!
I'll keep an open mind and look more into GenJar, but at first glance it looks like a hack to get somebody out of trouble for not observing better practices. It lets you not know your dependencies and not care whether they are good or bad. Of course, that might mean they aren't good or bad. If I believe that, I have a good use for it.
As I far as I know, the "bad" things about dependencies are where they are cyclical, or where a class contains too many concepts or responsibilities, and thus depends on ("drags in")too many things, and so on. In my experience, I've always had to sort out these kind of problems at the class/interface level. How classes are grouped in packages or jar files has never seemed to have a significant effect.
I'm intrigued to see how "better practices" of using packages and jars might help solve these kind of dependency problems.
One thing genjar does do for me is answer the question "what is the complete set of classes that my "application" code (transitively) depends on?". And that's the dependency question I seem to want to ask most often.
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As for the piece you quote, I find that somewhat strange.
The Reuse-release Equivalence Principle (REP)
The granule of reuse is the granule of release

So far, so good.
This principle is based on the idea that packages rather than individual classes are the units of reuse.
I don't understand this at all. To me, the implication of REP would be that jars or other downloadable deliverables are the "units of reuse". I can't think of any publicly downloadable jar files which only contain classes from a single package. Why would that make sense?
If a package is to be reused, all classes in that package should be designed for reuse.
That sounds sensible. Although I'd argue that all classes should really be "designed for reuse" (leaving aside exactly what that might mean).
The Common Reuse Principle (CRP)
The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.

This is the one that completely baffles me. Whatever would be the advantage of "reusing" all the classes in a package if you only actually need to use one of them? Why would this "principle" ever be an advantage?
This principle is also based on the idea that packages rather than individual classes are the units of reuse.
Do they offer any justification for this? To me (as I said above) a package is just a namespace. Packages exist so you can use both java.util.List and java.awt.List in the same program. What has that got to do with reuse ?
Classes that are intended to be reused together, should be put in the same package.
I'd more likely agree if this was "deliverable" instead of package.
 
boyet silverio
Ranch Hand
Posts: 173
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
At first, I was just somewhat vaguely thinking whether packages could have something to do on how to facilitate distribution of work to team members. Something like, "hey Ric, can you do the savings package?" or "Manu, you're assigned the Loans package"... or to something like "... do the controller package... view package ...", etc. but wow there seems to be loadfuls to think about on this packaging thing, and good ones too.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's my thinking ... could be wrong ...
If I'm going to carve out some of my favorite goodies to give you for reuse, I think I'd like to just put the appropriate packages into a jar for you. I would not like to put some fraction of one package, and some other fraction of another.
That is, I buy the principle that if you're going to need something in a package, you should need (almost?) everything in the package. That principle rejects the notion that packages are "just" name spaces.
Such principles were written without the benefit of a tool like GenJar. GenJar might solve all the same problems, but for now I'm skeptical.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
A jar file should have everything that someone downloading it might need, otherwise it's really hard to tell what should be downloaded. The fact that batik seems to need such a complex diagram of its own internal code astonishes me. I'd just put all the classes from all the batik jars into one big single download.


It comes in one single zip file, containing all the jar files. The point is, if my batik-application doesn't use Swing, why should I need to deliver the batik-swing classes with it?


Does anyone still do this kind of "manual linking" where some jar files are included in the classpath, and some are not. Whether your program works or crashes depends on whether any of the unsatisfied methods are accidentally called or not. Scary!


Only if you don't trust your automated test suite...
Seriously, I would think that if I knew batik a little bit better, the diagram would make perfectly clear which jar files are needed for which application.

The way I work is to put all my general-purpose classes into one big jar file (currently about 220K), then run genjar against my application specific code to build a new application-specific jar file using only the utility classes that are actually used. Even my most complex application jar files are usually less than about 60K, including the bits they need from the general utilities.


For some applications, that might work; but it doesn't scale very well. We do have projects where the thirdparty jars alone amount to more than one megabyte. If, for example, there is a new version of FOP available which fixes some important bugs, it is good to be able to just replace its jar file with the newer one, instead of having to rebuild and redeploy the whole application. Especially with Webstart applications, you want to have the application in as many small jar files as makes sense, so that the automatic updates use as few bandwith as possible.


This way, there's no chance of "class not found" problems (if you don't use Class.forName(), but that can always fail), and you get a small, complete application.


Class.forName() doesn't typically fail if you use it wisely, for a small amount of classes (for example in the way JAXP uses it). I guess you could always include those dynamically loaded classes as additional "root classes" to your genjar process, but it seems to me that it would make the build process unnecessarily brittle...
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
As I far as I know, the "bad" things about dependencies are where they are cyclical


Not all cycles are equally bad - remember that the Visitor pattern invariably introduces a class-dependency-cycle.
I think that the most "evil" cycles are those spanning over different levels of abstractions. It might be that good packaging in combination with tools like JDepend can help identify those.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To put some of the arguments a little bit in context, some quotes from http://www.objectmentor.com/resources/articles/granularity.pdf (published 1996 in "C++ Report"):


This article is the first of several that will describe principles that govern the macro structure of large object-oriented applications. I emphasize the word large, because these principles are most appropriate for applications that exceed 50,000 lines of C++ and require a team of engineers to write.
...
As software applications grow in size and complexity they require some kind of high level organization. The class, while a very convenient unit for organizing small applications, is too finely grained to be used as an organizational unit for large applications. Something "larger" than a class is needed to help organize large applications.
Several major methodologists have identified the need for a larger granule of organization. Booch uses the term "class category" to describe such a granule, Bertrand Meyer refers to "clusters", Peter Coad talks about "subject areas", and Sally Shlaer and Steve Mellor talk about "Domains". In this article we will use the UML 0.9 terminology, and refer to these higher order granules as "packages".
The term "package" is common in Ada and Java circles. In those languages a package is used to represent a logical grouping of declarations that can be imported into other programs. In Java, for example, one can write several classes and incoporate them into the same package. Then other Java programs can "import" that package to gain access to those classes.


[ June 27, 2003: Message edited by: Ilja Preuss ]
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ooh, a lot to reply to ...
Stan:If I'm going to carve out some of my favorite goodies to give you for reuse, I think I'd like to just put the appropriate packages into a jar for you. I would not like to put some fraction of one package, and some other fraction of another.
Can you explain a little more why you wouldn't like to do this? Is it because you lack the tools to do it? is it because you'd be worried about missing some classes?
Jar files containing classes from more than one package are so common they it would surprise me if a jar only had classes from one package. Can you point to any popular downloads which have single-package jars?
Stan:That is, I buy the principle that if you're going to need something in a package, you should need (almost?) everything in the package. That principle rejects the notion that packages are "just" name spaces.
I still can't understand this. Why should I want to include a whole bunch of classes I never use? In what case would such unnecessary bloating of an application ever be a good idea? I'm not just arguing here, I'm honestly baffled by this one
Ilja:It comes in one single zip file, containing all the jar files. The point is, if my batik-application doesn't use Swing, why should I need to deliver the batik-swing classes with it?
So it actually comes in one big "deliverable" anyway. So you (the application developer) are expected to manually split open this zip file and perform a rough, manual process for your application.
Ilja:Seriously, I would think that if I knew batik a little bit better, the diagram would make perfectly clear which jar files are needed for which application.
But why should I need to know or care? Why should I have to study and learn the result of some other developers trying to guess what I might need, when I have a tool which will quickly, reliably, and automatically do it for me.
Ilja:For some applications, that might work; but it doesn't scale very well. We do have projects where the thirdparty jars alone amount to more than one megabyte. If, for example, there is a new version of FOP available which fixes some important bugs, it is good to be able to just replace its jar file with the newer one, instead of having to rebuild and redeploy the whole application.
This I mostly agree with. Note, though, that it is the external jar files that matter here. My complaint with the batik diagram was that it split up its own internal classes in such a complicated way.
I suggest that a reasonable model might be one deliverable (jar) for each separately managed project with a separate deliverable timeline.
Ilja:Especially with Webstart applications, you want to have the application in as many small jar files as makes sense, so that the automatic updates use as few bandwith as possible.
Fair enough. But I hope you are not advising that we partition every application or utility collection this way, just in case someone ever wants to deploy it by webstart! In practice, if I were building an application for deployment by webstart, I'd want to make sure it was as small as possible, with no unnecessary classes at all. So I'd be back to genjar, again.
Ilja:Class.forName() doesn't typically fail if you use it wisely, for a small amount of classes (for example in the way JAXP uses it). I guess you could always include those dynamically loaded classes as additional "root classes" to your genjar process, but it seems to me that it would make the build process unnecessarily brittle...
I guess there was a little confusion there. What I meant to say was that the "trimmed" jar files produced by genjar are as complete as hand-generated ones. If you start allowing classes to be created from externally-entered names, then any application might fail, not just one built using genjar.
Ilja: quoting objectmentorIn Java, for example, one can write several classes and incoporate them into the same package. Then other Java programs can "import" that package to gain access to those classes.
Do you honestly still use whole-package import statements? I haven't used one in months. My code always imports specific classes, using packages only as namespaces.
It really seems that many of these sources are confusing the roles of "namespace", "conceptual partitioning", and "deliverable unit", and often trying to assign all three to the poor overused "package" statement.
Note in particular, that the objectmentor article was written in the context of C++, a language with which it is customary to use a "linker" to build into the delivered executable only those classes, functions and variables actually used by the application . Often the "libraries" used in this linking phase will be much larger than the final application, containing many things which are not used, and so not included, in the deliverable. Does this sound like any tool I have mentioned?
Note also that the objectmentor article was written before jar files existed, and when there was no real way of bundling or partitioning deliverables. Back in 1996, a java application would be "delivered" as a soup of separate classes. If you were really lucky you might get them in a zip file, but you'd most likely expect to manually expand that before running the application.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
Ooh, a lot to reply to ...
Stan:If I'm going to carve out some of my favorite goodies to give you for reuse, I think I'd like to just put the appropriate packages into a jar for you. I would not like to put some fraction of one package, and some other fraction of another.
Can you explain a little more why you wouldn't like to do this? Is it because you lack the tools to do it? is it because you'd be worried about missing some classes?


I can't speak for Stan, but for me it would simply complicate the subject. For example, I'd like to know which jars I had to redistribute if I change a specific class. Having a direct mapping from packages to jars would make that much easier. Not having that mapping would just unsettle my mental model of the system. Perhaps it's just me...


Jar files containing classes from more than one package are so common they it would surprise me if a jar only had classes from one package. Can you point to any popular downloads which have single-package jars?


I didn't understand Stan to object to multiple packages per jar. I think he just objected to classes from one package distributed between several distributables.

Stan:That is, I buy the principle that if you're going to need something in a package, you should need (almost?) everything in the package. That principle rejects the notion that packages are "just" name spaces.
I still can't understand this. Why should I want to include a whole bunch of classes I never use?


You shouldn't - that's exactly the point: If you need a package, you should need the whole package, not just disconnected parts of it.

Ilja:It comes in one single zip file, containing all the jar files. The point is, if my batik-application doesn't use Swing, why should I need to deliver the batik-swing classes with it?
So it actually comes in one big "deliverable" anyway. So you (the application developer) are expected to manually split open this zip file and perform a rough, manual process for your application.


Yes.

Ilja:Seriously, I would think that if I knew batik a little bit better, the diagram would make perfectly clear which jar files are needed for which application.
But why should I need to know or care? Why should I have to study and learn the result of some other developers trying to guess what I might need, when I have a tool which will quickly, reliably, and automatically do it for me.


For GenJar to work, you need some knowledge of the internals, too. For example, some parts of batik use an XML parser. If batik uses JAXP to find it, you will need to know the Factory class of the parser, as it is loaded via reflection.
Additionally, GenJar only analysis static class dependencies. It might include classes which never get used by your system, just because they are referenced by a method you never call. Obviously, the class sets GenJar generates aren't as minimal as they could be.
BTW - how quick is "quick"?

Note, though, that it is the external jar files that matter here. My complaint with the batik diagram was that it split up its own internal classes in such a complicated way.


I am not sure about this - I don't know how the batik team works. What had to be true for the diagram to make sense?

I suggest that a reasonable model might be one deliverable (jar) for each separately managed project with a separate deliverable timeline.


I think this is the core of the REP, isn't it?

Ilja:Especially with Webstart applications, you want to have the application in as many small jar files as makes sense, so that the automatic updates use as few bandwith as possible.
Fair enough. But I hope you are not advising that we partition every application or utility collection this way, just in case someone ever wants to deploy it by webstart!


No. But I'd notice that for big enough projects similar forces could become apparent, even without using webstart.

Ilja:Class.forName() doesn't typically fail if you use it wisely, for a small amount of classes (for example in the way JAXP uses it). I guess you could always include those dynamically loaded classes as additional "root classes" to your genjar process, but it seems to me that it would make the build process unnecessarily brittle...
I guess there was a little confusion there. What I meant to say was that the "trimmed" jar files produced by genjar are as complete as hand-generated ones.


My jar files aren't "hand-generated". They automatically include all the jar files which need to be in the classpath for compiling and testing.

If you start allowing classes to be created from externally-entered names, then any application might fail, not just one built using genjar.


The class names I am speaking of typically come from configuration files which are part of our distribution. With genjar I simply would have to maintain those names at just another place (or find a way to state them at just one place by making the build process more complicated, so it seems to me).

Ilja: quoting objectmentorIn Java, for example, one can write several classes and incoporate them into the same package. Then other Java programs can "import" that package to gain access to those classes.
Do you honestly still use whole-package import statements?


No. I also don't think that's the point of the article.


It really seems that many of these sources are confusing the roles of "namespace", "conceptual partitioning", and "deliverable unit", and often trying to assign all three to the poor overused "package" statement.


It seems to me that the article propagates the use of "namespaces" (packages) as a tool for "conceptual partitioning" (CCP) and/or bundling a "deliverable unit" (CRP).

Note also that the objectmentor article was written before jar files existed, and when there was no real way of bundling or partitioning deliverables.


In "Agile Software Development", one of the chapters is an expanded version of the article linked to above, which isn't much different in essence.
In the first week of september we should remember to ask Robert Martin about this topic...
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

--------------------------------------------------------------------------------
Stan:That is, I buy the principle that if you're going to need something in a package, you should need (almost?) everything in the package. That principle rejects the notion that packages are "just" name spaces.
I still can't understand this. Why should I want to include a whole bunch of classes I never use?
--------------------------------------------------------------------------------
You shouldn't - that's exactly the point: If you need a package, you should need the whole package, not just disconnected parts of it.


This still baffles me, and all the repetition of the same bald statement "If you need a package, you should need the whole package" isn't making it any clearer.
Let's take a concrete example:
In my code I have a core abstraction class Tract, which lives in package org.stringtree.tract. In that package with it are five or six other classes for things like serializing a tract to an OutputStream, decorated versions with argument type conversion etc. These other classes are all very dependent on Tract, but Tract itself is unaware of their existence, and in general they are unaware of each other.
In some application code, I decide that a Tract is a fine representation for some application specific concept, so I import org.stringtree.tract.Tract
I don't need to serialize it or pass Date objects to any of its methods, so I don't import those other classes.
Yet, those of you who argue in favour of the "common reuse principle" seem to be saying that I should bring these other classes in and bloat my code just for the sake of the "principle", even though this application doesn't need them and never uses them.
This sounds mad. What am I missing?
[ June 30, 2003: Message edited by: Frank Carver ]
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The package design principles don't confuse namespace and distribution unit at all - they reject the namespace part explicitly. For my own opinion I'll repeat - All of these principles came about absent a tool like GenJar. If it's really all that reliable, I might buy into it as a completely different solution to the problem.
I'm working on a large Swing client for a number of different user groups. No group needs every function in the system. It might be nice to deploy only the classes each group needs to their desktop. (or would it? why?) That would involve leaving things out that are referenced in code, but because of user group authorizations will never be called - already identified as a dangerous practice.
GenJar wouldn't be able to do that just by looking at code. Right?
On the other hand, I could have a script per user group to build jars including some packages, excluding some others. As I mentioned miles ago in this thread, the app is currently not packaged that way. Now if I take the panels package, I get every panel in the system. I'd like to see the panels split up by line of business functionality so I could easily tell which packages to include for each user group. Then if I included the Group-X package, it would be because I really needed all of it.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
This still baffles me, and all the repetition of the same bald statement "If you need a package, you should need the whole package" isn't making it any clearer.


Sorry, I somewhat pushed the envelope here...
What I should have written is "One way to not let you distribute unneeded classes is to only put classes which get reused together into the same package and distribute whole packages."

In my code I have a core abstraction class Tract, which lives in package org.stringtree.tract. In that package with it are five or six other classes for things like serializing a tract to an OutputStream, decorated versions with argument type conversion etc. These other classes are all very dependent on Tract, but Tract itself is unaware of their existence, and in general they are unaware of each other.
In some application code, I decide that a Tract is a fine representation for some application specific concept, so I import org.stringtree.tract.Tract
I don't need to serialize it or pass Date objects to any of its methods, so I don't import those other classes.
Yet, those of you who argue in favour of the "common reuse principle" seem to be saying that I should bring these other classes in and bloat my code just for the sake of the "principle", even though this application doesn't need them and never uses them.
This sounds mad. What am I missing?


I think you are missing that they are just principles that you should be aware of and apply as fits - not rules which should be followed to the letter, come hell or high water.
Robert Martin explicitely states (at least in the book, not sure about the other resources) that there is a balance between the three principles - sometimes they work hand in hand, but sometimes they are also at odds, so that you need to decide about your needs.
In the above example, you decided that the CCP was more important to you than the CRP at the java-package level - partly because of the existence of GenJar.
That sounds like the right decision in this case. I still think that for some systems the CRP is more important, though.
By the way, it just occured to me that at work we are applying the CRP mostly at another level of grouping - CVS modules. More on that later - I need to go to bed. It's close to midnight in germany...
PS: Thanks for another great thread! The principles of package design were always a little bit unclear to me - I think, I start to grok it now...
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What I should have written is "One way to not let you distribute unneeded classes is to only put classes which get reused together into the same package and distribute whole packages."
Perhaps my problem with this is my understanding of "classes which get reused together". I can understand that in some cases classes have mutual or cyclic dependencies, so it would make sense for these classes to always be reused and distributed together. However, in the code I typically work with that situation is very rare.
In the common case (as in the example I gave above) the class dependency graph is directed and acyclic. Indeed I strive for that in my own designs, as I feel it give me maximum class reusability with minimum coupling and allows me to produce small, tightly-focussed deliverables.
If the dependency graph is acyclic, there simply
are no groups of classes which are always reused together. Each application uses its own unique set of classes from the common pool. In general, the same is true of most well-designed APIs. I don't have to include all of java.util just because I use an Iterator in my code, for example.
I think you are missing that they are just principles that you should be aware of and apply as fits - not rules which should be followed to the letter, come hell or high water.
But I still think that the "principle" seems fundamentally flawed, and runs contrary to good design (in particular, when expressed in terms of low/weak coupling). From the page referenced above: The dependencies between two packages A and B are defined as the set of all dependencies from types that are part of A to all the types that are part of B. Dependencies between packages are therefore implicitly defined in the type definitions via references to other types.
If we value low coupling, and subscribe to this approach to package design, there is obviously a force to minimise such "package dependencies". But in an acyclic class dependency graph this force is resolved only when we achieve one class per package. I suggest that this indicates a flaw in the princple.
PS: Thanks for another great thread! The principles of package design were always a little bit unclear to me - I think, I start to grok it now...
I'm enjoying it too. I love really getting to grips with a "soft" issue like this
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
But in an acyclic class dependency graph this force is resolved only when we achieve one class per package.


Yes - the CRP drives us to create small packages.
I just found the following rationale in the documents to a tutorial by Martin (which was quite entertaining, btw):


When a new release of that [reused] component [read: package/deliverable] is created, the reuser must reintroduce it into existing applications.
- There is a cost for this
- And a risk
Therefore, the user will want each component to be as focused as possible.
- If the component contains classes which the user does not take use of, then the user may be placed in the position of accepting the burden of a new release which does not affect any of the classes within the component that he is using.



I suggest that this indicates a flaw in the princple.


The flaw is not in the principle, but in applying it without taking the balancing forces of the other two principles into account.
The CRP applied alone will let us form to small packages.
The CCP will let us form bigger packages, so that changes aren't split over too many packages.
The REP will let us form bigger packages, so that version management is simplified.
You need to find the balance between those principles.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Mhh, my previous post sounds a lot more definitive than I intended - even a little bit harsh, I guess. I appologize...
Please interprete it as my current understanding of the issue - in fact I am still uncertain about it and would really like to read more about your thoughts...
 
Frank Carver
Sheriff
Posts: 7001
6
Eclipse IDE Python C++ Debian Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think this conversation drifted a bit. I also feel that there is still some confusion about terms.
My original strong sentiments in this thread stem from my frustration at people insisting that a "package" (as implemented in java using the "package" keyword) is somehow a reusable component or a deliverable unit. I can see nothing in the design or current idiomatic use of Java to suggest this. In both the official Java sources and all the successful third-party code I have seen, reuse and delivery is largely orthogonal to the package structure. The package structure is used only as a namespace mechanism.
I would agree much more with some of the "principles" as expressed in this thread if the word "package" is replaced with "component", "deliverable", "library", "jar", "module", or any other word for an arbitrary lump of code.
I might agree with "if you need to reuse one class from a jar, you should also need to reuse all the others". In practice, That seems a clumsy and over-specific way to say it, so I'd be more likely to "refactor" this to something like "a delivered component should contain no unused resources". I would achieve this by using tools such as ant and genjar to construct an application-specific jar file containing only classes and resource files actually used by the application.
Are we still disagreeing?
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Frank Carver:
The package structure is used only as a namespace mechanism.


With all due respect, I don't think that is the way you are using packages.
If it were that way, you rarely would need more than one package. Most often you could put all your classes directly into com.efsol - only if there were nameclashes between classes the need for subpackages became apparent.
Aren't you using subpackages to group classes for your convenience?

I would agree much more with some of the "principles" as expressed in this thread if the word "package" is replaced with "component", "deliverable", "library", "jar", "module", or any other word for an arbitrary lump of code.


Yes - in fact the principles aren't written with Java packages in mind. On the other hand I still think that they apply to *some* amount to java packages, too.

"a delivered component should contain no unused resources". I would achieve this by using tools such as ant and genjar to construct an application-specific jar file containing only classes and resource files actually used by the application.
Are we still disagreeing?


I am not sure. I understand that you would do so and suppose that for your projects it is the way to go.
I do know (work on) projects where I think that approach would be more inconvenient than using more explicite means of grouping the classes - like CVS modules or even Java packages.
So, are we still disagreeing? Were we disagreeing at all??? :roll:
 
Nalla Senthilnathan
Ranch Hand
Posts: 40
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The BluePrints Pet Store example suggests organizing the classes in the following pattern:
package com.xyz.j2eeproj1.app1;
package com.xyz.j2eeproj1.app2.web;
package com.xyz.j2eeproj1.comp1;
package com.xyz.j2eeproj1.comp2;
etc;
where app1 and app2 are sub-applications in a j2eeproj1. Note that app2 has a web interface. comp1, comp2 etc, are components used by the apps.
Nalla
[ July 16, 2003: Message edited by: Nalla Senthilnathan ]
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Good example, Nalla.
So, which principles do we see reflected in that structure?
 
Don Kiddick
Ranch Hand
Posts: 580
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


say in an mvc application, one way would be to do as follows (e.g. based on component function in a pattern):
package model;
package view;
package controller;
another way would be something based on business areas like
package savings;
package loans;


In my experience I find the latter strategy to create packages with less interdependencies.
In the example, if you have a loans package and in it you will have entity, model & controller classes all related to loans which will be relatively tightly coupled. There will be few interdepencies between the saving and loans packages.
If using the former strategy and have packages such as model, view, controller & entity. In each of these packages you place the relevent classes pertaining to both savings and loans. In this instance you will have relatively lots of interdepencies between packages. Also the packages will contain fairly unrelated classes.
As for whether reducing interdependcies between packages and having classes in a package closely interelated are more desirable features than using the package structure as a way of dividing namespace, I shall leave to Frank and Ilja.
I'm actually working on an application where we started with the former strategy, but then I changed the structure to the latter and I was much happier with it.
my 2 pence,
D.
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
One aspect of packaging we haven't covered here (hard to believe there could be any) is that you might want packages to reflect your organization. That is, if there are separate Loan and Savings teams, they would each want ownership of their vertical silos through all architectural layers. If there are separate Domain and Presentation teams, they would want ownership of all business functions across their particular layer.
Any harm in slicing both ways? loan.model, loan.view, loan.controller, savings.model, etc?
 
boyet silverio
Ranch Hand
Posts: 173
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


from Don:
In the example, if you have a loans package and in it you will have entity, model & controller classes all related to loans which will be relatively tightly coupled. There will be few interdepencies between the saving and loans packages.
If using the former strategy and have packages such as model, view, controller & entity. In each of these packages you place the relevent classes pertaining to both savings and loans. In this instance you will have relatively lots of interdepencies between packages. Also the packages will contain fairly unrelated classes.


been a while... thanks there Don and the others. We re-examined the functionalities in Loans vs. Savings, and we found out that the making of most of the functionailities of Loans won't rely on the construction of the functionalities of the Savings (and vice versa) i.e. programmers of one group won't have to wait for the accomplishments of the other. This led us to re-package mid-stream mainly along the second option which seemed also to have made the "contending" groups peaceful for now .


from Stan:
...you might want packages to reflect your organization...


on the mark, for our case!. This seemed to be what had turned out.


from Stan:
Any harm in slicing both ways? loan.model, loan.view, loan.controller, savings.model, etc?


this is similar to what we've done which reflects more on the second case, and which I understand is Don's drift.
[ July 18, 2003: Message edited by: boyet silverio ]
 
HS Thomas
Ranch Hand
Posts: 3404
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Any harm in slicing both ways? loan.model, loan.view, loan.controller, savings.model, etc?
--------------------------------------------------------------------------------

this is similar to what we've done which reflects more on the second case, and which I understand is Don's drift.



The above approach does not promote re-usability.
How about say you are coding for Company XYZ Ltd.
package com.XYZ.ModelViewController
which is a class that encapsulates publish-subscribe behaviour for all the systems applications.
Each application then inherits from and plugs-in it's model,view(s),controller(s).
The question is how would you write a generic plug-in interface for Model,View,and Controller ?
The approach given above seems to lean towards cut-and-paste.
regards
[ July 20, 2003: Message edited by: HS Thomas ]
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm not sure I entirely follow your example, so I may be off track ...
If you have some base framework classes like a publisher that is used across architectural layers and business silos, they will be in a package of shared classes. If I wanted to pull out the loan.model, loan.view and loan.controller packages to reuse them, I'd have to take the framework package, too.
You always read that inheritance is a very strong form of coupling but it's never really bothered me much. Look at the dependency every other package has on the shared stuff package when they extend base framework classes. Any concerns?
 
HS Thomas
Ranch Hand
Posts: 3404
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


quote from Stan James:
Look at the dependency every other package has on the shared stuff package when they extend base framework classes. Any concerns?


Do you mean that it won't be easy to decouple and replace with another MVC solution?
My example was not based on a framework package.
Just another class like Servlet.
So my fictitious company could customise servlets by having XYZServlet extends Servlet.
Why not a generic MVC class called XYZModelViewController which all XYZ applications ( or all XYZ Account applications )inherit from .
Is this too far fetched or impractical ?
 
Stan James
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Now you have a base servlet class, presumably in another package of core stuff for reuse in other applications. Now somebody on another project not using your base servlet would like to borrow your application servlet. He has to get the base one, too. Is that an issue? Does he want the whole core stuff package? Will it conflict with his existing stuff? Or do we use GenJar to give him a jar of exactly the compiled classes he needs, no more, no less and the world is all good, never mind our internal dependencies and package structures?
BTW: Idunno the answers. It's easier to ask em than answer em!
 
Rufus BugleWeed
Ranch Hand
Posts: 1551
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Facinating thread, I do not comprehend the whole thing yet.
Frank Carver talks above about creating an application specific jar files with genjar.
Now if some machine hosts three applications: App1.jar, App2.jar and App3.jar might all contain com.javaranch.MyClass.
Or it might be that App1, App2, and App3 all have their own versions of FCarverUtil.jar and each one contains com.javaranch.Myclass?
So a purist might say com.javaranch.Myclass.class is cut and pasted into three applications?
Am I understanding this paradigm correctly? This is something Bob Martin is trying to avoid with his principals, no?
TIA
 
Don't get me started about those stupid light bulbs.
reply
    Bookmark Topic Watch Topic
  • New Topic