Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re: Versioning modules in a package

by BrowserUk (Patriarch)
on Oct 04, 2004 at 19:13 UTC ( [id://396348]=note: print w/replies, xml ) Need Help??


in reply to Versioning modules in a package

Long, long ago, in days of yore, I was brought up using 3-level version numbers: XX.YY.ZZ

  1. Major: XX - this incremented only when the external interface to the code was changed or extended.
  2. Midor (middle order): YY - Zeroed when the Major version increments.

    - This was incremented only when an internal interface changed.

    Eg. The number or types of paramaters to an Internal Use Only function changed.

    Or a piece of common code was factored into a new subroutine ( Of course, we didn't call it factoring back then).

    Or, new IUO functionality was added that was not (yet) exposed externally through the documented API.

  3. Minor: ZZ - Zeroed when midor increments.

    - Incremented every time a modification was made that made no changes to internal or external APIs. Eg. Bug fixes, corrections, simplifications.

Increments at any level are only made once unit/system and regressions test suite have been run and passed.

Occasionally, if large numbers of bug fixes or enhancements meant that midor or minor were approaching 3 digits, then a "maintainance increment" of the next higher level was made to avoid that.

So far, I not seen a better system.

The upshot is, the version of your subpackages should live their own lives and be pretty much unrelated to the versioning of the parent.

However, a change in the major (XX) version number of a subpackage should result in an increment in the the midor (YY) of the parent.

If both subpackages modify their external interfaces, then both their major version increment, and the midor of the parent is incremented twice.

(Though if you want to avoid major woes, you modify one subpackage at a time, and then the dual increment of the parent becomes obvious.)

Update: The reason why I consider this a good system is because any code that uses (only) the published interface, will be compatible whilst the Major version number remains the same.

This is especially useful with dynamically link libraries as newer, but major version compatible .dll/.so files can be substituted for earlier ones without rebuilding the calling code.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

Replies are listed 'Best First'.
Re^2: Versioning modules in a package
by FoxtrotUniform (Prior) on Oct 04, 2004 at 19:35 UTC
    1. Major: XX - this incremented only when the external interface to the code was changed or extended.
    2. Midor (middle order): YY - Zeroed when the Major version increments.
    3. Minor: ZZ - Incremented every time a modification was made that made no changes to internal or external APIs.

    This looks like a great numbering system; I think I'll give it a try.

    It's interesting to compare your XX.YY.ZZ system with Perl's major.minor.patchlevel system. Obviously, "midor" releases of Perl tend to change the external interface, although most old code seems to run fine. Major releases are few and far between, with no guarantees of backwards compatibility. Bugfix releases are fairly rare, which is kinda nice -- the interesting thing about fixing bugs in a language is that it does change the external interface, though not the way it's specified.

    There's also the hidden semantics of the "midor" number's parity, where an even number indicates a "production" release and an odd number a "development" release. Until now, I'd never really thought about it, but on further reflection I don't like it. The "hidden" field annoys me. There's no reason not to cat on a "-devel" or "-release" tag on the version number -- or at least, none that I can think of.

    It seems like your numbering scheme works best when there are a moderate number of releases and a lot of refactorings going on, and especially with internal-release code that isn't going to be used by the world at large. Putting the midor number (internal changes) ahead of the minor number (bug fixes) strikes me as a developer's way of doing things; customers wouldn't notice the internal API changes, but damn straight they'd notice the bug fixes. Perl's versioning system seems better for a slower-paced project, with lots of undocumented (at least in the version number) internal-development releases and a few major public milestones.

    Here's another question: how does this sort of thing apply to a file format? After a very little reflection, it seems to me that every change in a format's syntax or semantics deserves a "warning - old files are probably incompatible" numbering change. Adding new stuff to the format -- provided that most parsers will be clever enough to warn-but-ignore stuff they don't understand -- won't break compatibility in the same way, so new features deserve only a minor increment. But that's bass-ackwards from the way I tend to think about version changes! What gives?

    --
    F o x t r o t U n i f o r m
    Found a typo in this node? /msg me
    % man 3 strfry

      The odd/even number midor builds denoting development and maintainance tracks isn't that unusual. It serves to solve the parenial problem of separating the two which is essential for a developing product. You can only really avoid it once a product moves in to "Maintainance only" status.

      In a nutshell, this is to solve the problem, that having just released a version; say 5.8(.0), you have four sets of changes to track:

      1. Bug fixes arising from customer discovery.
      2. Bug fixes from internal discovery.
      3. New and/or modified internal apis.
      4. New and/or modified external apis.

      You need to be able to apply the first two to the last released build so that it can be sent out to customers with forcing them to wait for a new midor release to be tested, packaged and released. This allows small fixes that only affect a single file to be sent as just that file without compromising compatibility. If changes to internal or external apis are involved, it requires shipping a complete set, which effectively means a full release.

      To accomodate the two tracks, it is necessary to fork the codebase. Whilst 5.8-maint and 5.8-devel are possible, it makes life hard in all sorts of small ways to have alpha designations. The consistancy (my favorite watchword) that comes from sticking with the same numbering scheme by going the odds/evens route can simplify many things.

      Personally, I think I favour .50 nomeclature. At the release of 5.8, the codebase is split into 5.8.1 and 5.8.50--maintainance and development respectively. In a very large project, a 3 digit minor might be required, but usually not.

      On the file format thing.

      1. If the file format changes in a way that is not backwards compatible. The interface has changed. That is a major version change.
      2. If within the existing file format semantics, new syntax can be added such that it will be parsed by older parsers, but not be functional, this is an internal api change. A midor increment is called for.
      3. Changes that correct mis-interpretations of the existing syntax or semantics to bring them in line with the published api's are minor changes.

      The fly in that ointment is the case of a discrepancy between the published api and the way the parser parses the file, where the erroneous behaviour is found to be useful, or even preferable to the documented behaviour.

      In this case, the answer depends on who discovers it, how big a customer they are, and how many others will complain if the documentation is brought in line with the code rather than the other way around. Pragmatism rules here.

      The classic example of this was when DEC tried to drop support for a little known (and used) hybrid real-time/time-sharing OS they had called IAS (if memory serves?). Three customers complained when the announcement went out. DEC very pragmatically negotiated an agreement with the 3 customers that they would pay somewhat more for their service agreements in order to keep maintanance team going for a further 10 years.

      A very pragmatic decision when the three customers were General Electric, General Motors and the US DOD!

      I may have misremembered the details, but the basis of the story is true


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re^2: Versioning modules in a package
by legLess (Hermit) on Oct 04, 2004 at 19:33 UTC
    The upshot is, the version of your subpackages should live their own lives and be pretty much unrelated to the versioning of the parent.

    This is the kernel of what I thought, although not with the detail you suggest. Yours seems like a good system: specific and fine-grained.

    So the only question I have left is: should the Main module's $VERSION equal the package's version? This seems true of every package I've seen, but appears to be a special case of the other guidelines.

      should the Main module's $VERSION equal the package's version?

      The scheme was mostly used for C and/or assembler based libraries, so we didn't really have the same concept of separate package and module versions. The nearest thing to a package version would have been the release number. In essence this was just the major.midor numbers with the minor (always 00) dropped. New releases were made each time the midor number was incremented.

      Individual clients may be given an an .zz build of a particular file (possible because no external nor internal interfaces had changed; so interfile compatibility was ensured) to solve a specific problem as required, but there was no new release made until a new midor increment.

      In effect, the latest release would be 3.2(.0) with some customers having one or more files that might be 3.2.xx (99 >= xx > 00) to solve immediate problems between releases. Pre-release betas usually went out to a limited set of customers and got numbered 3.2.90/91/92 which then became 3.3.00 at release.

      Applying this to Perl packages, I would use the same scheme. CPAN releases being XX.YY(.00) with "internal" developments incrementing zz until it becomes time for a new CPAN release. When a specific users reports a bug that need immediate fixing, only increment the zz number and send them the interim. You then note the fix on the bugtracking system (along with the full xx.yy.zz number) but only send it out as people ask for it.

      If the frequency of requests for upgrades to a specific level rise above a trickle, then it worth doing a new CPAN release--once you've had feedback (or a lack of negative feedback) from the users who are already using it.

      Note: That's just how I would do it. I don't have any CPAN/OSS packages to maintain, so the reality of that environment may be completely different to my experience of in-house and paying customer work.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re^2: Versioning modules in a package
by stvn (Monsignor) on Oct 04, 2004 at 21:45 UTC

    Very nice ++ This is one of the best descriptions I have seen of the rationale behind the 3-number versioning system. It is a shame that CPAN doesn't seem to be able to deal with this system though.

    -stvn
Re^2: Versioning modules in a package
by Aristotle (Chancellor) on May 02, 2012 at 14:26 UTC

    This is what has now become popularly known as Semantic Versioning, yes?

    Makeshifts last the longest.

      It certainly wasn't called that back then, but it has probably been re-discovered, (and variously), re-invented many times under many names by many people down the years. As those that ignore the past have a habit of doing :)

      It, and minor variations of it, where pretty much universal across the industry when I started out. It was only once the marketeers started trying to steal a march on their competitors, but upping the major version in the (mostly) vain hope that purchasing depts would believe that version PQRv12 (previously v2.3.1) must be significantly better than XYZv10 (previously v2.4), that things started getting screwed up.

      That codification of the rules certainly fits with my understanding of 3-level versioning. And I agree with the writer that unless the rules are clearly defined and rigorously applied, it does devalue the purpose.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

      The start of some sanity?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://396348]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (2)
As of 2024-03-19 05:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found