Re: Best Practices - common code

From: Rhino (rhino1_at_NOSPAM.sympatico.ca)
Date: 01/27/05


Date: Thu, 27 Jan 2005 15:20:21 -0500


"John C. Bollinger" <jobollin@indiana.edu> wrote in message
news:ctbenj$427$1@rainier.uits.indiana.edu...
> Rhino wrote:
>
> > Let's say that we have a bunch of independent projects, among them Foo
and
> > Bar. Each of the projects has little to do with one another but they do
> > share some common code, things like certain standard GUI panels and some
> > frequently executed utility code. For example, all of the projects
generate
> > an About panel via the same class and all of the projects use the same
class
> > to do various date manipulations. As a result, all of this common code
has
> > been organized into a Common project. Common is a rather large project
with
> > many classes.
>
> Java does not have "projects". Such a concept might be relevant to your
> programming environment, but not to the language. The closest analog in
> Java is probably "package", but the two may not be completely congruent.
>
Good point! Sorry, I am developing in Eclipse and I muddled up the question
by combinining Eclipse projects with Java packages.

> > When packaging project Foo, we know that it only needs a few of the
classes
> > in Common, not all of the many classes found there. When packaging
project
> > Bar, we know it only needs a few of the classes in Common, and that some
of
> > them will be same as the Common classes needed by Foo and some will be
> > different.
>
> In that case, "Common" isn't really very common -- it's more
> "miscellaneous".

I see your point. "Common" isn't necessarily the best word to use for this
code but I couldn't think of anything else that gave the flavour I wanted.
My "Common" classes aren't necessarily things that *EVERY* program is going
to use but they represent some "reusable parts" that can (and are) used in
several different programs.

> My recommendation would be to break it up into smaller
> pieces that you don't object to distributing as indivisible units. The
> natural way of doing this would be to assign classes to packages so that
> you can break up the bulk along package or package family* lines.
> Technically, a Java package is little more than a namespace and access
> control domain for classes, but it is common practice to use packages to
> group classes into functional and/or distribution units.
>
> *Package family: a non-Java term by which I mean a collection of
> packages all having a common name prefix.
>
I've already broken my Common project into a variety of different packages
with names like this:
mydomain.common.prefs
mydomain.common.edits
mydomain.common.error
mydomain.common.filters
mydomain.common.utilities

That's what you mean, right?

But in the case of project Foo, whose package names are mydomain.foo and
mydomain.foo.Resources, I only need some of the classes in
mydomain.common.utilities, not all of them. That's really the nub of my
question: should I be packaging all of mydomain.common.utilities when I only
need two of the dozen classes in it?

> > When it comes to packaging the Foo project for
distribution/installation,
> > which is the "best practice" in this case:
> > A. Distribute only the parts of Common that are needed by Foo?
>
> Depends on the structure of Common. If you subdivide it as I suggested
> then distributing only parts of Common would be natural. Note, however,
> that that doesn't necessarily mean distributing nothing but precisely
> those classes that Foo requires.
>
> > B. Distribute all of Common with Foo, even though most of it won't be
> > needed?
>
> If most of Common is not needed by Foo, then again, it's not very
> common. Break it up.
>
> > My strong inclination it to only do A for a variety of reasons:
> > a. less code to distribute: less space needed on CD -or- fewer files to
> > download and less bandwidth used
>
> Space on a CD is unlikely to be a real-world issue for the vast majority
> of cases. Downloading considerations, on the other hand, may be
> reasonable, depending on the actual sizes we're talking about.
>
> > b. slightly better performance of the application, assuming Jars are
being
> > used, since the classloaders won't need to inspect and ignore so many
files
> > that aren't being used
>
> If the size of the jars makes a noticeable difference then something is
> dreadfully wrong. This is in practice a non-issue.

Fair enough; I assumed that seek time for classes could be an issue in a
large jar but I have no idea how large a Jar would need to be in the real
world before you actually saw a performance degradation due to an
excessively large jar.
>
> > c. less code that can be reverse-engineered by competitors
>
> I guess you could argue that the hypothetical competitors keen on your
> technology would have to obtain multiple of your products to get their
> hands on all of "Common". If that makes a noticeable difference to your
> bottom line then you are small enough potatoes that your competitors
> either (a) for all intents and purposes don't exist or (b) are way out
> of your league.
>
I'll have to think about that one a bit more. I'm truly not sure how much
risk there is of competitors reverse-engineering code. I know that
obfuscators exist to make reverse-engineering more difficult but I don't
know how effective they actually are. Maybe the people who buy obfuscators
are just paranoid and the actual amount of reverse-engineering is
infinitesimal....

> > On the other hand, if I am selective about which parts of Common get
> > packaged, there is a fairly tedious process of figuring out precisely
which
> > classes in Common are needed by Foo. At least, it is fairly tedious to
*me*
> > since I only know how to do this mechanically: look at each 'import' and
> > 'implements' in each Foo class to determine which Common classes are
needed,
> > then look at each Common class to see what their dependencies are. If
anyone
> > knows a tool that will help me figure this out by simply clicking a
button
> > or filling out a dialog, I'd love to hear about it!
>
> You would have to do slightly more work than just click a button, but
> Ant can analyze class dependencies. Look at the ClassFileSet entity.
> Ant uses BCEL to perform that task, and it wouldn't be too hard to write
> your own tool for it if you didn't want to use Ant. I would expect that
> there are other possibilities, too; some may have a nice GUI.
>
I'm very fond of Ant but didn't realize it could analyze the dependencies. I
saw the acronymn BCEL in the docs but had no idea what it did or that it was
anything useful so thanks for telling me about it. I know that I could write
a tool that did that sort of analysis but I wasn't wild about re-inventing
the wheel when I was pretty sure there was some automated way of doing that
analysis.

> On the other hand, if you reduce the scope of your problem by dividing
> up "Common" as I suggest, then you don't really need to worry much about
> it. Just jar up whole packages or package families and distribute them
> as units.

Based on what I've described above, would I be correct in understanding that
you are recommending that I incorporate all of the
'mydomain.common.utilities' package, even the classes that Foo doesn't need?
I'd be reluctant to incorporate all of the 'mydomain.common' package family
since much of it isn't used within Foo. I don't have as much of a problem
with distributing a few unneeded classes in 'mydomain.common.utilities'.

> Document package dependencies instead of individual class
> dependencies. Use a build and / or packaging tool for which you can
> prepare a static configuration file (e.g. Ant, most IDEs).
>
I assume that those two sentences represent indepedendent thoughts. What is
the best way of documenting package dependencies, Javadoc? What do you mean
by a 'static configuration file'? I don't recognize that term from Ant or
Eclipse so I'm not quite sure what you mean, what it would contain, or what
it would look like.

> > What experiences do the rest of you have with the question of common
code?
> > Would you distribute all of Common or just the parts needed by Foo?
>
> Some of both. By subdividing the problem you can get some of the
> advantages of each approach while avoiding the worst problems of both.
>
That's what I expected. There are very few perfect solutions that don't
generate their own problems in turn ;-) I was just hoping to take advantage
of other people's experience to avoid the worst of the problems.

Rhino



Relevant Pages

  • Re: Best Practices - common code
    ... all of this common code has ... Java is probably "package", but the two may not be completely congruent. ... > A. Distribute only the parts of Common that are needed by Foo? ... > then look at each Common class to see what their dependencies are. ...
    (comp.lang.java.programmer)
  • Re: Package organization: where to put common modules?
    ... I have a module, say 'foo', that both package D and B require. ... the best practice in terms of creating a 'common' package that hosts ... I make a util package to hold commonly used code. ...
    (comp.lang.python)
  • Re: from __future__ import absolute_import ?
    ... foo not in bar ... A path below the package level is generally a good means to shoot ... to represent a python "package" structure. ...
    (comp.lang.python)
  • Re: A Question about DEFPACKAGE syntax
    ... Lisp and for not-really-Common-Lisp ... that it's easier to type:foo than to type "FOO". ... "FOO" does not create superficial symbols in the keyword package ...
    (comp.lang.lisp)
  • Re: Request for help constructing a simple macro
    ... Isn't an unbound symbol just a `symbol object'? ... Object in Lisp means generally all Lisp data. ... #:FOO ... No package for this symbol. ...
    (comp.lang.lisp)