views:

383

answers:

5

My company is having trouble figuring out the best way to manage our builds, releases, and branches... Our basic setup is we have 4 applications we maintain 2 WPF applications and 2 ASP.NET applications, all 4 of these applications share common libraries, so currently they are all in one folder /trunk/{app1, app2, app3, app4}.

This makes it very hard to branch/tag a single application because you are branching all 4 at the same time, so we would like to separate it out into something like {app1,app2,app3,app4}/{trunk,tags,branches} but then we run into the issue of where to put the shared libraries?

We can't put the shared libraries as SVN externals because then when you branch/tag the branch is still referencing the trunk shared libs instead of having them branched as well.

Any tips? Ideas?

We are currently using svn and cruisecontrol.net.

EDIT: The shared libraries are changing often as of right now, which is why we can't use them as svn externals to trunk, because we might be changing them in the branch. So we can't use them as binary references.

Its also very hard to test and debug when the libraries are statically built instead of including the source.

+6  A: 

I guess it all depends on how stable the shared libraries are. My preference would be for the shared libraries to be treated as their own project, built in CruiseControl like the others. Then the four main applications would have binary references to the shared libraries.

The primary advantage with this approach is the stability of the applications now that the shared libraries are static. A change to the libraries wouldn't affect the applications until they explicitly updated the binaries to the newer version. Branching brings the binary references with it. You won't have the situation where a seemingly innocuous change breaks the other three applications.

Brian Frantz
The shared libraries are changing often as of right now, which is why we can't use them as svn externals to trunk, because we might be changing them in the branch. So we can't use them as binary references.
sontek
If you are adding to the shared libraries I would put that new code in the application in the branch, then move it to the shared libraries only when needed by one of the other apps. Do the dev in the application until fully tested, then expose it to the other apps only when needed. Probably shouldn't _change_ the shared libraries other than bug fixes - the functionality/interface of existing classes/methods should generally stay the same. Open/closed principle - add functionality, don't change existing.
Brian Frantz
These shared libraries are the core of our applications, if a bug is found, or a new feature comes up, it needs to change.For example, one of these shared libraries are some asp.net user controls that are used in both applications, so recently I was re-working the credit card/payment controls to add payment plan functionality (payment plans is a new business need). I obviously didn't want to change Payment controls in trunk because that would interfere with everyone elses work. So I needed to branch until I got it working and then merge it back into trunk.
sontek
If all the applications are so tightly coupled, then maybe they should just be one giant solution? Or maybe two solutions - web and desktop? Then you could branch the entire group.Either way, I'd recommend reevaluating your entire approach to see if there is a better fit to what you are trying to do.
Brian Frantz
A giant solution is often easier. Or if the "giant" solution gets too big then have many solutions that reference just enough projects for their part to compile. However remember you should still build all the projects as a single giant solution even if you work with a lot of small ones. At my work we've made a small utility that reads the small solutions and generates a giant one as a step in our automated build process. That way we don't have to maintain the giant solution whenever we add or delete a project.
JohannesH
+1  A: 

I agree with @Brian Frantz. There's no reason to not treat the shared libraries as their own project that is built daily and your projects take binary dependency on the daily builds.

But even if you want to keep them as a source dependency and build them with the app, why wouldn't the SVN externals approach work for you? When you branch particular app, there's no need to branch the shared library as well, unless you need a separate copy of it for that branch. But that means, it not a shared library anymore, right?

Franci Penov
The shared libraries are changing often as of right now, which is why we can't use them as svn externals to trunk, because we might be changing them in the branch. So we can't use them as binary references.The reason we would branch it is because we might be making important changes that would effect the shared libraries but we don't want to break the other projects until the change is fixed and tested in the branch, and then when we merge it back into trunk we'd fix the calls to it in the other apps.
sontek
That is a disaster recipe. What happens when you branch two of your apps and you branch the shared libraries for both of them? Merging the shared libraries changes back can (and probably will) be a logistics nightmare. (Been there, done that :-))
Franci Penov
Well, obviously that is a concern but we have to rely on good communication between our developers, there should be very few times they have to work on the same exact lines and if they do touch the same lines and they conflict, we have the diff tools to figure out what went wrong, its just part of developing with a team :)I think its much better to have the code branched so *everything* that they change is in that branch and not affecting other developers, the only time we branch is when we are going to be making breaking changes :)
sontek
A breaking change in the shared libraries should not be made in a branch of one of the client apps. it should be made into a shared library branch, that has stabilized versions of all the client apps, so that you have full control over what's changing in the shared libraries.
Franci Penov
+1  A: 

I've tried solving this problem several ways over the years, and I can honestly say there is no best solution.

My team is currently in a huge development phase and everyone basically needs to be working off of the latest and greatest of the shared libs at any given time. This being the case we have a folder on everyone's C: drive called SharedLibs\Latest that is automatically synced up with the latest development release of each of our shared libraries. Every project that should be drinking from the firehose has absolute file references to this folder. As people push out new versions of the shared libs, the individual projects end up picking them up transparently.

In addition to the latest folder, we have a SharedLibs\Releases folder which has a hierarchy of folders named for each version of each shared lib. As projects mature and get towards release candidate phase, the shared lib references are pointed to these stable folders.

The biggest downside to this is that this structure needs to be in place for any project to build. If someone wants to build an app 10 years from now, they will need this structure. It is important to note that these folders need to exist on the build/CI server as well.

Previous to doing this, each solution had a lib folder that was under source control containing the binaries. Each project owner was tasked with propagating new shared dlls. Since most people owned several projects, things often fell through the cracks for the projects that were still in the non-stable phase. Additionally TFS didn't seem to track changes to binary files that well. If TFS was better at tracking dlls we probably would have used a shared libs solution / project instead of the file system approach we are taking now.

Daniel Auger
+3  A: 

Can you clarify why you don't like branching all four applications at the same time?

This makes it very hard to branch/tag a single application because you are branching all 4 at the same time

I usually put all my projects directly under trunk as you are currently doing. Then when I create a release branch or a feature branch, I just ignore the other projects that get carried along. Remember, the copies are cheap, so they're not taking up space on your server.

To be specific, here's how I would lay out the source tree you've described:

  • trunk
    • WPF1
    • WPF2
    • ASP.NET 1
    • ASP.NET 2
    • lib1
    • lib2
  • branches
    • WPF1 v 1.0
      • WPF1
      • WPF2
      • ASP.NET 1
      • ASP.NET 2
      • lib1
      • lib2
    • WPF1 v 1.1
      • WPF1
      • WPF2
      • ASP.NET 1
      • ASP.NET 2
      • lib1
      • lib2
    • lib1 payment plan
      • WPF1
      • WPF2
      • ASP.NET 1
      • ASP.NET 2
      • lib1
      • lib2
Don Kirkby
The copy on the server is cheap but the checkout and copy on the developers computer is not cheap, most of the devs like to keep the whole repo checked out in case they have to work on a branch with someone, they'll already have it pulled down, but this starts taking forever when you have a few branches and tags going on.But so far, this seems to be the best solution :)
sontek
In your situation, I would check out trunk or a single branch, whatever I'm working on. Then use switch to work on another branch. I might check out two working copies so I can leave one on my main work branch and use the other to switch around when doing small jobs on other branches.Something else to consider is shallow checkouts: check out the whole repository from the root, but don't recurse that checkout down to the branches until you need them. I find this more annoying because getting rid of a branch from your checkout is a hassle.
Don Kirkby
I'd agree this is the correct approach. The devs keeping the whole repo checked out is a behaviour that can change - there is no reason to have a sub-standard solution just to satisfy what is effectively laziness, IMHO. In addition to that, while someone is working on experimental WPF 1.1 branch, I don't want to wait to get all those updates while I am just trying to work on one specific branch.
gregmac
I've tried working on projects that used both Brians and Dons methods of separating and I think doing what Don suggests is far easier in practice and also more correct in some respect. The method Brian suggests can quickly lead to version problems if you are not on top of it ALL the time.
JohannesH
+2  A: 

We are kicking off an open source project to try and deal with this issue. If anyone is interested in commenting on it or contributing to it, it's at:

http://refix.codeplex.com

David M