David W. Van Couvering wrote:
Hi, Kathy, thanks for your email. The timing is actually pretty good,
I was just talking with Francois trying to understand his concerns
better.
After quickly describing the two approaches, I'd like to summarize the
experience/impact of these approaches from the perspectives of the end
user, the developer/maintainer, and the test developer/runner.
Goal:
- Reduce code duplication while continuing to support different
versions of client and embedded driver in the same VM
Approach 1:
- Create a common package and put all common code there
(org.apache.derby.common)
- Use compatibility guidelines to ensure backward compatibility and
some degree of forward compatibility
- Common classes are embedded in derby.jar and derby-client.jar
(based on lots of negative feedback for having a separate jar)
Approach 2:
- Create a common package and put all common code there
(org.apache.derby.common)
- During build process, "clone" all common classes into at least two
generated packages, one for the engine and one for the network client
(org.apache.derby.engine.common and org.apache.derby.client.common).
- This approach avoids having to implement compatiblity
guidelines/constraints and guarantees, as the engine and client
continue to be fully isolated
USER EXPERIENCE
Approach 1
- No new jar files, everything looks the same
- For the vast percentage of users who don't mix versions in the same
VM, everything works great
- For the small percentage of users who mix versions, the order in
which jar files are loaded. For example, if they want to use
derby-10.2.jar and derby-client-11.0.jar, then if derby-10.2.jar is
first in the classpath, they will get an exception saying that the
client code is incompatible with the common code and that they need to
re-order their jar files, whereas it will work fine if the order is
reversed.
Approach 2
- No new jar files, everything looks the same
- Ordering of jar files does not matter, everything works fine
DEVELOPER EXPERIENCE
Approach 1
- Pretty much as it is today, nothing surprising
Approach 2
- When navigating code either during source browsing or debugging,
they will see the *generated* common code, not the master common code.
- If a developer is not aware of how things work, or just forgets,
he/she will try to edit this generated code, and will be confused and
surprised when his/her changes disappear after a build
- Stack traces will point to generated code, and the developer will
have to remember to translate that back to the master version.
- The generation process must be very careful not to adjust line
numbers or all stack traces will be off and misleading. This means
for instance we can't add comments saying "THIS IS GENERATED CODE, DO
NOT EDIT"
- We may need to generate more copies if different types of version
mixing are required (e.g. if the tools.jar and derby.jar need to be at
different versions)
TESTER EXPERIENCE
Approach 1
- We would have to build and run compatibility tests to make sure
that compatible versions run correctly and incompatible ones correcty
raise the exception
Approach 2
- No real change, although debugging of tests may be confusing due to
issues I already listed under developer experience
I also am uncomfortable with the "twistiness" of approach 2. There is
something to be said for a clean architecture and build environment.
I have seen time and again that a good architecture allows you to
scale and grow, whereas "twisty" architectures tend to wrap you up and
tie you down at some point. I think this has to be taken into
consideration.
My main question is: is it OK to sometimes throw an exception for the
small set of users who mix versions, and for them to then have to
rearrange their jar ordering. If the answer is that this is not
acceptable and would be considered a showstopper regression for some
part of our user base, then I think we have no choice but to go with
Approach 2, even if we do risk painting ourselves into an
architectural corner. Otherwise, it is my strong recommendation to go
with Approach 1.
Thanks!
David
Hi David,
Thank you very much for the clear explanation. From a usability
perspective, I would vote for approach 2. Requiring a classpath to be
in a particular order is always an issue. However, the saving grace is
that it sounds like the ordering issue only comes up if you mix versions
of the derby.jar and the derbyclient.jar in the same classpath. I don't
believe most users put the client and engine in the same classpath
(unless there's a new requirement I don't know about), so that
definitely helps. Requiring classpath in a specific order can easily
lead to complications though, so I'm not in favor of it in general.