Sunday, March 6, 2011

Best practices, building trunk against trunk?

We have many projects that use a common base of shared components (dlls). Currently the development build for each project links against dlls built from the trunk of the components. (ie trunk builds use the dlls from other trunk builds)

When we do a release build, we have a script that goes through the project files and replaces the trunk references to specific numbered versions of the components (that are built from a tagged branch)

I think this weakens the testing that we do during development because the project that I am actually working on is using diferent dlls to what the release build will be using. I would like to always develop against the numbered versions of the components and only ever update them when there is a specific need.

However others in the team argue that unless we develop against trunk (and update to the newer versions of the components with each release) we will have the problem that (a) our products will hardly ever update to the newer version of the components then (b) when we do need to update it will be a huge task because the component source/interfaces will have changed so much.

What practices do you follow, and why?

Edit: Sorry all, I have just realised I have confused things by mentioning that there are several main products sharing components - although they share the components they don't run on the same PCs. My concern relates to the fact the because the components are likely to change with each release of a product (even though there was no specific requirement to update the component) that testing would miss some subtle change that was done in a component and not related to the specific work being done on the product.

From stackoverflow
  • You should have strong interfaces that rarely change, so changing versions shouldn't be that hard.

    Separating the versions and working against specific versions will increase overhead when you need to change, but it should also encourage less interface changes overall, which will help in the long term.

    hamishmcn : True, the interfaces may not change that much. I am more worried about subtle changes in the behaviour of the components not being picked up because testing is focused on the change being made to the main product
    chills42 : You could add some basic unit tests?
  • We develop against multiple branches and trunk simultaneously and we have chosen to build and test each branch with the code we'll be pushing out to production. I don't think it is safe any other way.

    Basically, if a developer is working on trunk, all they have to do is worry about building from trunk and committing code to trunk.

    Any developer working on a branch needs to build and test off that branch (there are multiple projects all branched/tagged the same build/release). When they commit changes to that branch, they must also merge those individual changes into trunk.

    We expect all developers to be familiar with SCM (SVN) and to be capable of maintaining multiple branches of code. As a team we handle major framework shifts or huge code changes to minimize troublesome merging.

    Simon Lehmann : Doesn't the practice of immediately merging any commit to a branch into trunk defeat the whole purpose of a branch?
    Instantsoup : Not for us. Trunk is for research/development spikes into large new features or technologies. Trunk is volatile, the branches are stable. The libraries used in branches are static once we cut them, but we can radically change how we do things in trunk.
  • Two things here. First, I think you're right; you want to build against the most current development versions, not against the old versions. If you haven't already, you will see a situation in which the build-for-release blows up and you have to do an all-nighter cleaning up the diffs.

    I'm personally a fan of the "commit to trunk, release from branch" model anyway. All commits go to the trunk, overnight builds or CI builds are against the trunk, and people create branches freely. When you have a trunk that meets acceptance criteria, tag a release candidate, BUT KEEP MAKING UPDATES TO THE TRUNK. If you hae a long release cycle, then you might have changes for release n+1 being added to the trunk, but ideally you should just shorten your release cycle instead. If there are changes to the trunk that shouldn't be in the released version, AND you have a problem that requires changes, create a branch against the tagged version --- and make sure you merge any changes back to the trunk once you have an actual release.

    hamishmcn : Good points thanks
  • We are using the scons building system, and have our own file in the root directory which specifies what version of each library we're going to use when building the application.

    That reduces the need to change version names in several locations like you mentioned.

  • Whether (b) is a valid argument depends on how often your shared components change and by how much. If they change often in your workplace, it might be a valid that you are "forced" to develop off the newest version. Whether that in itself is a problem is a valid question.

    However, from your side of things, I don't see how you can push code into production without it being tested against the shared components being used in production. Do you do a second test cycle against the release build? Do you just pray that nothing breaks? Frankly, (b) can be reversed in these cases to support your point of view: If the trunk is different enough from the most recent tagged branch, then that effort has to be made to ensure your app works properly with it.

    If your shared components are tagged often enough, then your colleagues are probably right, and it's easier to manage the incremental changes from the most recent tag to the trunk than it is to manage the change from arbitrary version X (determined at the last build) to arbitrary version Y (determined when you choose to upgrade).

  • Hmm, I may be in a minority here, but this comes down to release management.

    Developing against the trunk of a set of shared components means, by definition, that the components are a "moving target" -- a developer using those shared components won't necessarily know if a newly found defect or failure is due to the project code or the shared components, which leads to a loss of productivity, IMNSHO.

    The "shared components" have a release cycle all their own. Give your other developers a break and fix the version of the shared components that the projects are going to use and use tags, labels or branches to identify the shared component release. On the next iteration for the projects, bump up to the latest "stable" or "production" build of the shared components.

    There's another "smell" here, if you'll pardon the expression. Having "shared components" whose "source/interfaces will have changed so much" between project releases sounds like the components aren't so solid or shouldn't necessarily be shared.

    See also the answer to this question Shared components throughout all projects, is there a better alternative than svn:externals?

    Instantsoup : This is exactly what I attempted to say, but done with far more clarity and eloquence, bravo!
    Stefano Borini : As a complement to your answer. Consider the situation where an important functionality that your trunk needs is only "in development" in the shared component. In that case, you can refer to daily, well defined snapshots of the shared component.

0 comments:

Post a Comment