views:

306

answers:

3

I'm working on a project that will (soon) be branched into multiple different versions (Trial, Professional, Enterprise, etc).

I've been using Subversion since it was first released (and CVS before that), so I'm comfortable with the abstract notion of branches and tags. But in all my development experience, I've only ever really worked on trunk code. In a few rare cases, some other developer (who owned the repository) asked me to commit changes to a certain branch and I just did whatever he asked me to do. I consider "merging" a bizarre black art, and I've only ever attempted it under careful supervision.

But in this case, I'm responsible for the repository, and this kind of thing is totally new to me.

The vast majority of the code will be shared between all products, so I assume that code will always reside in trunk. I also assume I'll have a branch for each version, with tags for release builds of each product.

But beyond that, I don't know much, and I'm sure there are a thousand and one different ways to screw it up. If possible, I'd like to avoid screwing it up.

For example, let's say I want to develop a new feature, for the pro and enterprise versions, but I want to exclude that feature from the demo version. How would I accomplish that?

In my day-to-day development, I also assume I need to switch my development snapshot from branch to branch (or back to trunk) as I work. What's the best way to do that, in a way that minimizes confusion?

What other strategies, guidelines, and tips do you guys suggest?


UPDATE:

Well, all right then.

Looks like branching is not the right strategy at all. So I've changed the title of the question to remove the "branching" focus, and I'm broadening the question.

I suppose some of my other options are:

1) I could always distribute the full version of the software, with all features, and use the license to selectively enable and disable features based on authorization in the license. If I took this route, I can imagine a rat's nest of if/else blocks calling into a singleton "license manager" object of some sort. What's the best way of avoiding code-spaghettiism in a case like this?

2) I could use dependency injection. But generally, I hate it (since it moves logic from the source code into configuration files, which make the project more difficult to grok). And even then, I'm still distributing the full app and selecting features at runtime. If possible, I'd rather not distribute the enterprise version binaries to demo users.

3) If my platform supported conditional compilation, I could use #IFDEF blocks and build flags to selectively include features. That'd work well for big, chunky features like whole GUI panels. But what about for smaller, cross-cutting concerts...like logging or statistical tracking, for example?

4) I'm using ANT to build. Is there something like build-time dependency injection for ANT?

+2  A: 

Do you want to do this via Subversion ? I would use Subversion to maintain different releases (a branch per release e.g. v1.0, v2.0 etc.) but I would look at building different editions (trial/pro etc.) from the same codebase.

That way you're simply enabling or disabling various features via a build and you're not having to worry about synchronising different branches. If you use Subversion to manage different releases and different versions, I can see an explosion of branches/tags in the near future.

For switching, you can simply maintain a checked-out codebase, and use svn switch to checkout differing versions. It's a lot less time-consuming than performing new checkouts for each switch.

Brian Agnew
I wouldn't recommend using 'switch' because it can fail halfway (e.g. when unversioned files are obstructing the versioned ones) leaving you with partially switched working copies. Having one checkout for each branch will reduce confusion.
Wim Coenen
+1  A: 

You are right not to jump on the branching and merging cart so fast. It's a PITA.

The only reason I would want to branch a subversion repository is if I want to share my code with another developer. For example, if you work on a feature together and it is not done yet, you should use a branch to communicate. Otherwise, I would stay on trunk as much as possible.

I second the recommendation of Brian to differentiate the releases on build and not on the code base.

yhager
+1  A: 

A most interesting question. I like the idea of distributing everything and then using a license key to enable and disable certain features. You have a valid concern about it being a lot of work to go through the code and continue to check if the user is licensed for a certain feature. It sounds a lot like you're working in java so what I would suggest is that you look into using an aspect weaver to insert the code for license checking at build time. There is still a going to be one object into which all calls for license checking goes but it isn't as bad of a practice if you're using an aspect, I would say that it is good practice.

For the most part you only need to read if something is licensed and you'll have a smallish number of components so the table could be kept in memory at all times and because it is just reads you shouldn't have too much trouble with threading.

As an alternative you could distribute a number of jars, one for each component which is licensed and only allow loading the classes which are licensed. You would have to tie into the class loader to achieve this.

stimms