Brian Smith made some good points on my last post about software component versioning. They're too detailed to reply to in a comment so I'm posting a reply as a full entry.
You'll probably need to read that last post for this one to make sense. Also, I kind of have a strategy now. More on than at the end of this post.
I would just change the version number to 2.0, and then tell your customers that they can have a free upgrade even though this isn't the normal policy.
There's not enough new stuff to go to 2.0. It's not really fair to customers either. I think it has to be 1.2. I'd like 2.0 to be a bigger bang.
Unless you are taking away functionality I have a hard time understanding why you cannot maintain backward-compatibility. Compatability is something that everybody expects, and doubly so if they are paying for the product. It seems like the problem could be solved by adding a new interface instead of replacing an existing one.
When adding methods, this is the case. In fact I will be adding methods and maintaining the old ones. But if you want to change method access permissions it's basically impossible. I want to move a public method to protected.
Also, adding a new interface is not an option as I need to keep the name of the interface consistent across product lines. Bit of a catch-22 really. It's a bit of a pain when you have to manage more than one product. I'm starting to have some sympathy for Sun and the mess that is
The nice thing about backward-compatibility is that there is helps encourage people to upgrade to the latest version. If people refuse to upgrade then you end up supporting old versions longer. If a customer finds a bug in version 1.1 then they will ask you for a 1.1.1 to fix it, instead of upgrading to 2.x where it was already fixed.
Ah. Yes. But I do this in any case. All major versions will be supported for as long as possible. This is important. Part of the reason developers hate external components is because they can't be trusted and a lot of vendors just don't care if there are bugs. Well I care, and I won't let bugs stand if I can help it.
I don't really like the idea that the first component of the version number only changes when there is an incompatible change. If you maintain compatibility for five years then the version number would be something like 1.9. But, 1.9 probably would have much, much more functionality than 1.0. Yet, the numbers 1.9 and 1.0 don't seem that much different from each other (it is easy to misread it as 1 & 23/100). The result is that this scheme is counterproductive to marketing the product: the main version number increases when something bad happens.
The worst case would be when you publish an interface in, say, version 1.6.1 that for some reason has to change immediately (e.g. the way the interface was structured facilitates some kind of security problem). To fix this problem you want to release a fixed version of the API. But, now you have to call this version 2.x even though it might be a very, very small change. Maybe the jump from 1.0.1 to 1.6.1 was a huge improvement in functionality. Yet, the increase from 1.6.1 to 2.0.0 was a single bugfix, perhaps just a few characters changed in the source code. It is counter-intuitive.
This is a very strict interpretation. I would say that one can bump to 2.0 at anytime, for marketing reasons say. It would only be forced by a compatibility issue.
In any case, I think I am going to drop the minor version restriction and say that minor numbers can accept compatibility changes. This means that you can only be 100% sure of compatibility on the same
major.minor revision. But that's pretty much OK.
It works okay for open source products because marketing for them is totally different (often ignored).
Very true. And there is something to learn from Open Source. Version numbers are an important way to give a quick overview of the state of the project. I like that and it's very useful, even necessary, for software components. It's much less important for applications, where the version number is just a marketing gimmick. But for my stuff the version number is, in a way, part of the customer service. It's very important that it has a crystal clear meaning.
So this all seems like a very difficult problem to solve. However I was forgetting one thing about Java: Just-In-Time compilation!
How does that help? Well, it means that reflection is not as bad as you think it is. The “common knowledge” is that reflection is slow. Well sure, the lookup is slow, but once you have the method reference the JIT compiler will optimize the calls for you. In the case of data processing where you perform the same operation many times, this effect comes into play very quickly.
So reflection is OK! I can use it! I'm going to look at trying to rewrite the support classes to handle this situation. They will introspect themselves to see if the old methods are declared. They can thus recognize the old interface and work with it. Old code should just keep working.
Yes this will make my support classes messy and more complex. Tough for me. That's the price to be paid. If you want to maintain compatibility for paying customers, as Brian noted above, you must do this. Anything else is just lazy.
Of course, this may not work completely. We'll see. But even if I can reduce the changes required, that's a good thing.
Thank You Blogosphere, and Thank You Brian!