Does anyone have any techniques for coping with version management in a JavaVirtualMachine
? In principal, you can have classes A and B that both depend on a class C -- but on different, incompatible versions of C. There's also an issue about managing serialization across different versions of a class.
There are various techniques for recording versions of code, such as adding a description class to packages. Java 2.0 has support for package versioning in the JAR (Hmmm, what about CAB files?) and they make a nice distinction between the version of the specification of a package (i.e. the public view) and the version of the code.
- do we believe that the package is the right unit of versioning?
Given a version description, what can we do with it when the code may be coming from different places:
- write a bunch of dependency checking utilities that complain when things don't match, and let the users sort it out?
- bundle up a consistent view of everything in a large JAR, like a Smalltalk image?
It is interesting... as often as people put Java and COM head to head,
they rarely mention the fact that COM deals with the versioning problem
explicitly and in a way that I have not seen done elsewhere. With some
discipline, the same scheme can be used in Java.
In COM, all interfaces are immutable. Once you make an interface and release it, it never changes. You associate a globally unique identifier (GUID) with the interface: a 128 bit number assumed to be unique across time and space. If you define IDispatch, there is only one IDispatch. It will be the same for everyone. This is DesignByContract
writ large. Components and systems are extended by adding new interfaces. There are a couple of repercussions. If you go this way you can do incremental deployment easily. Each version of your software is a true subtype of the previous version. In fact, one can see backwards compatible versioning as form of subtyping.
Of course, one has to decide whether this sort of discipline is worth the trouble. One can always BurnTheDiskpacks
I've seen this proposed elsewhere but it raises a couple of issue for me: the potential for code bloat if nothing is ever thrown away, especially for code intended to be downloaded, and that it's impossible to tell when something is no longer being used as the only real way to find out is to remove things and see who complains. -- SteveFreeman
If class A and B depend on different versions of class C, you can load
class C from two class-loaders, one for each version. The two class C's
will then be different classes as far as the JVM is concerned.
If you're interested in Nat's solution, there was a good article in the January edition of JavaWorld
) about class-loaders and their namespaces, "Design with dynamic extension" by BillVenners
I'm currently looking into "live updates", applications that dynamically update their class files when new ones become available within a class repository. Obviously version control is going to be an issue for us too.
This is an interesting technique. One implication for me is that, if you want to write long-lived code, you must create all your objects via a factory so you can manage this sort of thing. It looks to me like this technique is good for changes in implementation or combined with an element of the COM trick described above (which is good), but it won't get you through major changes in your public API. Those just have to be fixed to get through the static type checking. --SteveFreeman
You don't have to create all
your objects in a factory, only the object that you need to be a particular version. The class that is loaded will then load further classes from the same class loader, and only fall back on the system class loader if that fails. --NatPryce
What I meant was this could imply that, to protect yourself against potential future clashes (which, as a true XP'er, one should ignore), you localize and hide object creation behind some factory interface. That gives you one place to do stuff with class loaders when things get difficult, and allows you to do it without changing anything else. Of course, in the CommonLispObjectSystem you probably just tweak some method at the meta-level and everything just works. --sf
See the ArtOfChoosingTheNextCard for a discussion of how XP can get to a sophisticated design very quickly, if that's what the customer needs.
I see what you mean. An approach that doesn't go as far would be to encapsulate the use of whole packages behind factories to shield you from changes to the package API. I guess it would only be useful for packages developed by third parties.
Would this be a use of the BridgePattern
or the ShieldPattern
> "Potential for code bloat"
Not quite as bad as it might appear, since only the interfaces truly need to be replicated. The code behind them can often be shared, perhaps with some adapter code. In the case where the new interface is the old one plus some extra methods, you can use inheritance (of interface) directly in both COM and Java.
- If you're still interested in this topic, you should stop by the Thomson Connect team's area and chat with them about the way versioning is handled in Connect.
I hope it is appropriate for me to post this here. I suspect it fits into "utilities for dependency checking". If this is not welcomed, please delete:
When researching this topic I ran across the Jiazzi tool - http://www.cs.utah.edu/plt/jiazzi/
. It works by generating stubs for defined package/class/method groupings. You then code against those stubs instead of the implementations. This lets you swap one implementation for another without changing the client code. There was an article on IBM developerWorks about it : http://www-106.ibm.com/developerworks/java/library/j-diag1105.html
Note: Jiazzi hasn't been updated since March 2003, so user beware.
Jiazzi is a pretty simple idea that works fairly well, but it only solves syntactic problems, not semantic problems with versioning (note I'm the author).