13 Oct 2009 @ 20:57 

Having read my last post regarding version, you have no doubt jumped in your time machine, gone back a few years or months and implemented a sound versioning policy on all the projects you work on;  your colleagues think you are even more amazing than you were before, and life is generally coming up roses.

However, back in the present day a problem has presented itself.   While the code in the trunk has improved in leaps and bounds in terms of both high- and low-level architecture, features, modularisation, and to a lesser degree for this example, testing and documentation a parallel path of development has formed in one of the branches.

As previously discussed, branches are best used for fixing bugs in specific versions.  More than occasionally, a branch becomes the site of new development in order to cut out the overhead of migrating customers to newer versions – I’ve seen various reasons for this, but they’re of no importance as it’s the outcome that counts.

Depending on the timescale involved, and the amount of active development in both the trunk and the branch, the result may be two versions of the same project that are in essence both the latest version but are partially or totally incompatible with each other.

The problem can be alleviated to a greater or lesser degree by porting new features from the branch into the trunk.  If this is done diligently, this ceases to be a problem.  It’s still not a good situation to be in, but it is one less problem on your plate…for now, at least.

If porting doesn’t happen – due to perceived time contraints, difficulty in doing a quick port because of architectural changes, laziness, whatever – you’re heading into territory where the merge from hell lives.  Let’s take the example where a project which in the branch is a monolithic project built with Ant now exists in the trunk as a modular Mavenized project which has been refactored to the nth degree to improve many aspects; we now have two incompatible codebases that require reconciling.

There are a few approachs that can be taken here.  The brute force approach is to examine the branch compared to the trunk to build up a profile of files that have been added or removed.  You can finesse this process a little by comparing the branch to the trunk at the time of branching to get some addition information – but any major strucural changes to the trunk (like that described above) will negate this.  Once you’ve compiled your exhaustive list of files that have been added, removed or updated you can go through and copy each file from the trunk to the branch – ensuring in the process that you’re not introducing any bugs, incorrect assumptions, duplicate functionality, etc.  Also, make sure that you’re matching the new architecture and coding guidelines if you don’t want a rap on the knuckles from the other developers.

Another approach is to merge at the functional level, in other words port the features but not necessarily the code.  This may feel like a counter-intuitive approach given the features already exist in perfectly good code just over there, but digging those features out of the branch could well be as intensive – and probably a hell of a lot more frustrating – than implementing them afresh in the the trunk.

If all this seems like a lot of hard work – it is.  It’s far better to never get into this situation in the first place, but we live and work in a world where things have not always been as pragmatically optimised as we would like.  As we move towards cleaner, better tested and architecturally sound projects there are occasionally a few pit stops along the way.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • DZone
  • Facebook
Posted By: steve
Last Edit: 15 Oct 2009 @ 20:24

EmailPermalinkComments (0)
Tags
Tags:
Categories: fundamentals, versioning
 07 Oct 2009 @ 0:29 

Why use version control?

Versioning is a crucial key of the development process for several reasons best described through the lack of versioning:

  1. Want to see a great piece of code that was refactored out, deleted or otherwise lost six months ago? Hmm…
  2. If you have multiple versions of a product used in live environments (by customers or yourself), how are you able to provide any form of bug-fixing without upgrading to the most recent version?
  3. Want to experiment with a new architecture, build system, unit test library or general-purpose doomahickey without risking your current setup? Tough.
  4. Is your code full of commented-out chunks that are kept around just in case? That’s poor man’s versioning!
  5. And a whole bunch of other reasons that I’ll probably remember as soon as I hit the publish button.

The most basic – and naive – form of versioning if simply to take a copy of the codebase every so often and place it somewhere safe.  This is better than nothing, but it would require logic to be convoluted at Olympic level to persuade anyone it’s a reasonable approach; it smacks of the wrong kind of laziness – zero effort up front, and sustained effort for minimal gain on the back end.

Skipping over the part where a company decides the best solution is to develop an in-house versioning system, we can move directly to tried-and-tested version control systems (VCSs).  Many exist, both free and commercial, and whichever you decide will generally make your life easier.

In this particular example, I will use Subversion (http://subversion.tigris.org) , a.k.a. svn- a popular, well-established VCS system that enjoys support from the command line, and various continuous integration servers and IDEs.

Versioning with Subversion

At the core of the user interaction possible, Subversion works on a system of checkouts, commits and updates.  A quick definition:

  • repository – a collection of versioned files within the svn server
  • checkout – the process by which the versioned files, plus some svn-specific information, are copied from the svn server to a working copy (e.g. on your local computer, or on a continuous integration server)
  • commit – an atomic operation where all the files added, removed or updated in the working copy are propagated back to the svn server.
  • update – synchronizes the files of the working copy with those of the svn server.  This is used to pull the results of commits other than your own into your working copy.  Your own commits, by definition, are already in your working copy because that’s where you made the changes.

A typical project lifecycle in an imaginary world would be

1. Create project in subversion

2. Create or import the initial files

3..n-1. Commit and update files as you and other committers make changes to the repository

n. End of project

Anyone who has ever got to n, break out the champagne and take a five-minute break – you’ve either shipped the definitive (not to mention bug-free) version of the project, or you’ve just been downsized.  Nonetheless, this illustrates versioning with a single branch with no tags.  Each commit can be traced to a specific committer, and the development history of the project is kept for both posterity and code audits.

Branches?  Tags?

As mentioned above, versioning can be done in a linear fashion – one single line, with commits falling exclusively on that line.  In svn terminology, this line is called the trunk.

Versioning using the trunk only

Versioning using the trunk only

A project that has multiple versions, however, needs to consider branching.  Branching, just as the name suggests, represents a major offshoot of the trunk.  In fact, it’s an exact copy of the trunk at the point the branching took place.  We now have, in effect, two parallel lines of development which are completely independent but have a common root.

The branch may represent, for example, the point at which version 1.1 was released.  The trunk would be branched into, say, MyApp-1.1, built, tested and shipped.  At roughly the same time as this, the person sitting opposite you just committed a major change that won’t be available until version 1.2 – this commit does not affect the 1.1 code, and so ongoing developments in the trunk do not corrupt bug-fixing endeavours in the 1.1 branch.

A more realistic development cycle would be

trunk.1 -  Create project in subversion

trunk.n..trunk.n-1 -  Commit and update files as you and other committers make changes to the repository

trunk.n – Branch code as new customer comes on board and makes various requests

trunk.n+1 – Continue working on new features, requirements, etc, no effect is felt by the branch.  Any bug discovered which also exists in the branch may have its fix ported into the branch.

branch.n.1 – Bug fixes, no effect is felt by the trunk.  Any bug discovered which also exists in the trunk may have its fix ported into the trunk.

A repository with branches and tags

A repository with branches and tags

When certain points are reached, for example when all the requirements are have been met, tags come into play.  A tag is a snapshot of the branch at a given point, and is useful for recalling the state of the project at a given point.  Tags should be used, at the very least, for each release;  they may also be used, for example, for internal tracking.

So you can only have one branch?

So far, the examples have centered around the trunk and a single branch.  This is fine for illustrative purposes, but remember that not only are multiple branches possible, it’s also possible to branch from branches.  In fact, you can think of the trunk as a branch with the only difference being it doesn’t have a parent.

Why version when the binaries tell the whole truth and nothing but the truth?

Pragmatism and laziness are, at the end of the day, two of the greatest attributes any developer can have.  They lead to automation, efficient processes and a tendency to get things right in the minimum amount of time.  Taking this into account, surely adding version control to your project is an unnecessary overhead?  After all, the binaries held by the customer not only fit their reqiurements but also contain exactly the bug that requires fixing!  The binaries can be requested from the customer, decompiled, patched, recompiled and redistributed.  Easy as pie, sweet as a pea, etc, etc.

If you’re going to take this route, you have to ask the customer for their binaries each and every time you have to fix a bug for them.  There is, of course, the possibility that you’ll keep a copy of each binary you send to them to avoid this unprofessional and embarrasing request…but if you’re going to do that, why not just version the source code in the first place?

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • DZone
  • Facebook
Posted By: steve
Last Edit: 13 Oct 2009 @ 08:11

EmailPermalinkComments (0)
Tags

 Last 50 Posts
Change Theme...
  • Users » 1
  • Posts/Pages » 10
  • Comments » 0
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

About



    No Child Pages.