Best Practices - common code

R

Rhino

I'd like to ask the experts on the newsgroup what the "best practices" view
is of a question regarding common code.

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.

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.

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?
B. Distribute all of Common with Foo, even though most of it won't be
needed?

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
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
c. less code that can be reverse-engineered by competitors
d. etc.

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!

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?

--
Rhino
---
rhino1 AT sympatico DOT ca
"There are two ways of constructing a software design. One way is to make it
so simple that there are obviously no deficiencies. And the other way is to
make it so complicated that there are no obvious deficiencies." - C.A.R.
Hoare
 
J

John C. Bollinger

Rhino said:
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.
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". 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.
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.
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.
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.

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


John Bollinger
(e-mail address removed)
 
R

Rhino

John C. Bollinger said:
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.
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?
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.


If most of Common is not needed by Foo, then again, it's not very
common. Break it up.


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.


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

Antti S. Brax

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?

Do not distribute classes. Create a separate "project" for your
common code, that includes all these packages, and make that
"project" produce JAR files as it's build result. Name those JAR
files common-prefs.jar, common-edits.jar and so on. In your other
projects, just distribute the JAR files you need.

You may want to use some other than common in the JAR file name,
since the Apache project alreay has a quite popular project named
"commons".
 
J

John C. Bollinger

Rhino said:
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?

Yes, just so.
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?

I wouldn't worry about a difference of ten classes in a medium-size project.

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

My point was that breaking up your "common" code and distributing fewer
unnecessary pieces simply means that a competitor who wanted to get all
of it would have to obtain more of your products to do so. If the
handful of additional sales is noticeable to you then (I assert) you are
a small enough operation that one of the two alternatives I offered applies.

Obfuscation is a different beast, and I will not otherwise comment on it
here.
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.

BCEL = ByteCode Engineering Library. It's an Apache Jakarta project
that offers rather good facilities for analyzing, modifying, and even
creating Java classes at the bytecode / class file format level.
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?

Yes. It's a management and maintenance issue. By making packages the
unit of distribution (instead of classes) you dramatically reduce the
complexity of the problem of including all required classes, while
taking a granular enough view to meaningfully cut in to the problem of
distributing unneeded classes.
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'.

I see no need to distribute all of 'mydomain.common' if only
'mydomain.common.utilities' is used.
I assume that those two sentences represent indepedendent thoughts.
Yes.

What is
the best way of documenting package dependencies, Javadoc?

You could do it in package-level Javadocs, but I was thinking more along
the lines independent developer documents. If you aren't maintaining
any and don't see a need to start then perhaps the dependency
documentation isn't so important for you.
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.

I was trying to be generic. For Ant, the term would refer to a project
build file (i.e. build.xml by default). For Eclipse it would be part of
the project configuration, and / or an Ant build file if you are using
Ant inside Eclipse.


John Bollinger
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top