Subversion Best Practices for Web Applications

A few months back I had some dialogue with Nick Parker from uship.com.  He was wrestling with getting version control setup in a way that would meet the needs of his team and wanted to brainstorm a bit.  Here is a portion of our discussion that speaks directly to a couple of the problems Nick was trying to solve:

“I’m trying to figure out the best way to set up our subversion repository to do a couple things:

  1. Facilitate peer code review.
  2. Always have an "uploadable" version of our website (i.e. - be able to decide exactly which parts of the code go up when). “

These questions and the context of Nick’s situation really interested me.  I think that most if not all software development teams have to answer hard questions about version control at one point or another.  And if not at the start of a project then after learning a hard lesson from not using version control appropriately.

In addition, you will notice from these questions that Nick isn’t letting the tool (subversion in this case) shape the goals for his team or the desired process.  Instead, he has a clear direction in mind, he has some specific pieces of the development process that are proven and valuable, and he wants to use the tool in a way that would enable his chosen approach.

Like I told Nick, although I don’t have the perfect solution to these issues, I can share an approach I like to use on projects that has worked well and should provide a good foundation.

(Note that this approach was born out of a need to simplify and increase consistency of deployments to the asp.net suite of sites.  Our team was switching from Vault to Subversion at the time and really needed a better approach for managing environments independently and deploying more automatically.)

Directory Structure

This is probably one of the most overlooked pieces of setting up a Subversion repository for new users.  It’s easy to just start a project and begin checking in files as needed.  And with some version control systems this isn’t a big deal but with Subversion I think it’s really important to start with a structure that sets the flow of your development process.

Here's a snapshot of they way I typically setup the directory structure for a Subversion (SVN) repository and is loosely based on the ‘Branch-When-Needed’ system described in SVN Best Practices:

svn-example 

‘Trunk’ is where all the day-to-day development happens. It includes everything you want to version control on a project. And it should at least include a single directory for the web application. The web directory should contain the application as it is to be deployed compiled binaries and all.

As the name implies, ‘Branches’ is used to keep track of the branches for your web application.  In order to have independent version control of your web application per environment you should have a branch of the ‘trunk/web’ folder per environment.  And they should be branched in the order of deployment. For example, the alpha branch should be branched from trunk, while the beta branch should be branched from the alpha branch.

‘Tags’ is used to keep track of specific versions of a branch or deployment milestone.  Because each environment specific branch has its own change log, you probably don't need to tag each time you do a deployment to each, but it is a good idea to tag major versions and deployments to production.

Day-to-day Development

So, how does this apply specifically to Nick’s questions and the day-to-day development process?

1. Facilitate peer code review.

You can use ‘Trunk’ to do peer code review. It is where developers always check in their code.  If you are using continuous integration (Nick mentioned that his team is using CruiseControl) your build tool can pick up the check-in to auto-build and keep everyone honest.  Every check-in can be compared to previous versions to see what changes were made and revert if necessary.  This is a natural aid in the code review process.

Deployment

2. Always have an "uploadable" version of our website (i.e. - be able to decide exactly which parts of the code go up when).

The branches provide exactly this. You only merge into alpha what you want deployed to alpha (or staging) and you only merge into beta from alpha what you want deployed to beta.  This kills two birds with one stone.  First, you have complete control over what changes are deployed to which environment.  Second, you always know the code that is running in each environment.

To simplify deployment and remove human error, you can set up command line SVN and create a simple batch file to do an ‘svn update’ on the server.  Then deployment becomes as easy as merge changes, update server.  Or, if you use CruseControl you can automate the build and deployment on checkin for a specific environment.

Feedback

Now, there are obviously a lot of sophisticated ways to change this approach and make it work better for different development processes.  Understand, that the above is meant to be a simple example of an approach that solves many of the basic problems that teams encounter with using version control to fit their process and workflow.

I am quite interested in how you use version control to solve these problems on your development team.  Whether you use Subversion or another tool please share your approach and any feedback you have on the approach described above.

And Nick, if you’ve had a chance to experiment more please share what approach you ended up using.

Filed under: ,

Leave a Comment

Comments

  • Nick Parker said:

    Kyle,

     Thanks for the great post ideas that have lef to our current build process.  Below is what we're now using:

    We have our trunk, and two branches - test and staging.

    Developers regularly check into trunk, which fires off an automatic build of our development site using CruiseControl.net (confluence.public.thoughtworks.org/.../Welcome+to+CruiseControl.NET).  From there I can automatically merge all changes from trunk into the test branch, which fires off an automated build of our test site, or I can manually merge changes into the test branch and force a build of the test site (this is used for patches).  When that's been tested and is ready for primetime, CruiseControl automatically controls the merge into the staging branch, which builds our staging site in the production environment.  From there, we use vice-versa to only update / add / delete new or changed files to production.

    So the most common steps to push a new release are:

    1.) Force cc to merge trunk into test branch

    2.) Test everything on test

    3.) Force cc to merge test into staging branch, tag revision

    4.) Final testing on staging (in production environment)

    5.) Vice versa between staging and production

    The nice thing there is that we have a few loadbalanced servers, and vice-versa can update whichever servers we want all at the same time, and also will remove files that are no longer in use.

    Nick

    28 Aug, 2008 @ 09:47 AM
  • Kyle said:

    Nice!  I really like how you are using CruiseControl to automate everything.

    One question: How do you handle binaries?  Do you check them in, rely on CruiseControl to build them, have CruiseControl check them in, other?

    28 Aug, 2008 @ 12:27 PM
  • Nick Parker said:

    CruiseControl builds the binaries using msbuild - binaries that aren't built from the project are checked in.

    28 Aug, 2008 @ 01:32 PM