[Rubygems-developers] Library versioning

Mauricio Fernández batsman.geo at yahoo.com
Tue Mar 30 13:12:03 EST 2004


[As some of you might know, I am participating in a project so far
completely orthogonal to rubygems (RPA == Ruby Production Archive,
http://www.wobblini.net/svn/rpa/rpa-base/manifesto.txt). I believe
that it is time that this orthogonality be broken at least on a IMHO
fundamental policy issue, library versioning.]

Problem
=======

There are two mechanisms related to versioning, one used at install time
when 'remote-installing' a gem (add_dependency), the other at load time
(require_gem); both use the same underlying version specification mechanism.

I see 2 problems: a major one related to policy (or the lack thereof)
and a technical one, regarding the current implementation of
Gem::Version::Requirement.

A Requirement is currently defined as a pair <relational operator,
version number>. The following shows why this is not enough.
At some point, gems will be used to manage libraries across API changes. 
Given the following scenario:
 library A depends on B, with the API used in 1.0
 library B 1.0 available, 2.0 available with incompatible API
if this is to work at all, A must declare a dependency on that particular API,
with something like
 s.add_dependency "B", ">= 1.0"
 s.add_dependency "B", "< 2.0"  # otherwise the latest one will always be used

This illustrates the (minor) technical problem in the current implementation,
">= 1.0" and "< 2.0" are not considered simultaneously. This is esp. important
in the require_gem case. Gem::Version::Requirement *has to* be fixed to
support several relational operators per requirement specification. That is, a
Requirement must become a set of <operator, version number>
"sub-dependencies".

So far so good, problem solved... or not? Note that the above assumed the
following:
 * the person making the 'A' gem knows which API he needs, which was the first
   version of B that provided it (1.0) (this is not a must however), and
   *predicts* which will be the first one to break it (2.0). Note also
   that *all* dependencies should have a corresponding "< x.y"
   'sub-dependency'; the API would have to be backwards compatible
   forever otherwise.
 * the developer of B follows a consistent versioning policy, such that A's
   prediction will be correct

Since the persons making A and B do not normally know each other (in fact, B
might not even be aware of A's existence), relying on an implicit agreement
between the lib. developer and the user is but calling for troubles. It is not
realistic to assume that the developer of A will be tracking B to see when the
API changes and add a "< x.y" to the requirement a posteriori; this
would also require all the users to upgrade A in time (and not after
upgrading B!).

Solution
========

Policy
------

It is essential that some conventions (a minimalistic policy) be established
to make sure the API-breakage scenario will not break rubygems' scheme.

A working system needs at least the following:

* major version number: guaranteed to be increased on backwards-incompatible
  changes in the API. Note that another way to proceed is changing the name of
  the gem ("B1" -> "B2") but most people won't want to do this.
* minor version number: increased when new functionality is added.

Given this convention, ">= 1.0" would imply "< 2.0".

This scheme can be refined further as shown in 
http://www.codeforpeople.com//lib/ruby/library/library-0.0.0/doc/ to support
arbitrary "backwards-compatibility levels".


Education
---------

It seems that a chapter on packaging w/ rubygems will be included in
Programming Ruby 2. IMHO it is far more important that the versioning policy
be explained there than the technicalities of how to package a gem: if a
developer doesn't know about rubygems, the "rubygems world" loses one
package; if the developer makes a gem without following some minimalistic
versioning policy, he can potentially break *a large number of (to him)
unrelated gems*, and ruin the user experience.

I think it is imperative that:
* at least equal importance be attached to the versioning policy as to other
  technicalities in rubygems' documentation (I'd put it *before* 
  'Creating the Gem Specification' in the 'RubyGems Developer Documentation
  Area').
* the rubygems team make sure that the versioning policy is explained in the
  2nd edition of the Pickaxe (this makes sense since rubygems will
  change for sure, but the versioning policy ought to remain stable).
* in general, that the versioning policy be considered a fundamental part of
  rubygems and that all needed measures be adopted to ensure that no 'rogue
  gem packager' will break the system (unintentionally).


-- 
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

martin at bdsi.com (no longer valid - where are you now, Martin?)
	-- from /usr/src/linux/drivers/cdrom/mcd.c


More information about the Rubygems-developers mailing list