Charles Gardiner said:
Hi,
from a work-flow view point, I see at least one major problem with this
methodology. If you are designing everything yourself in the course of
personal multi-tasking then it's fine, but as soon as a team is involved
I regard it as highly risky.
Whether it's risky would depend on several other "usage-of-the-tool" factors
(more later), but I can say our software group has multiple people all
working concurrently and this is not an issue. However, they're also using
SourceSafe which then dictates a different type of work flow anyway, but the
bottom line is that when the integrator/builder person needs to create a
build they simply add a label to the top level project like
"xyz_Ver_1.0.10", then they check out that labelled version out and do their
build. I'm not trying to get into the relative merits/demerits of
SourceSafe versus Subversion here, my only points are:
- It is simple for the builder to create a new version that can then be
built
- There are no manual steps or checks that must be done to create the
labelled version, so there are no chances for mistakes when the those steps
get skipped. During crunch time, near product release, when time is very
valuable and scarce, the value of this probably should not be
underestimated.
- The build and test is a validation of what is in the trunk at a particular
moment. [1]
- That build can be recreated at any future time, regardless of what has
happened in the repository
The head should really carry the tag 'under
development'.
This seems to be an area where we differ somewhat. While I agree it is the
'under development' area, I don't think it should be used as scratch pad,
commits to the trunk should be understood to be contributing to the
development and should not 'break the build' or cause a test failure.
Also, it's very
useful to be able to check into the head from a workstation and pick it
up again from a lap-top when on the road and continue working.
That would be a misuse of commits in my opinion. It's just as easy to
create a patch file and put the patch on the laptop, no commits are
necessary to handle this situation.
Of course you could argue that the developer should make a branch first
and work there, merging back to trunk when he is finished.
That would be the other way to do it. For the 'pick it up on the laptop
later' scenario that you just described, the branch/merge would probably not
be a very good way for the developer to handle the situation, that's one
thing that patches are good for. For an extended development branch/merge
makes more sense. The point of creating the branch in the first place is to
totally decouple the widget from the trunk for the time being. It creates a
private work area for the developer...for now.
But this is
only forcing the responsibility on the developer of the reusable.
Since the developer is making the changes, this is where the responsibility
belongs.
Shoving the responsibility to each integrator to discern when the changes
are completed (what notifies them to do this) and then make possibly
numerous changes (i.e. to update all of his references to any newly changed
things) and putting this task on the critical path to the build (since the
task of updating those references can not even be started until after all
the developers creates their new tags) at a time of high stress (getting the
new build to fix the last problem/problems) is potentially error prone.
An 'svn copy' to a tags or releases directory could be regarded as a
'contract'. The developer should be implicitly saying he has
fixed/improved/extended something, tested it and now makes it generally
available. IMHO, only reusables carrying this stamp should ever be
incorporated into a super-project.
Contracts involve agreement between at least two parties and in this
instance (the creation of a new tag by a developer) there appears to be only
one, the developer. The creation of the new tag by a developer is not
anything the integrator would willingly agree to (but it is something that
can of course be imposed on them by local custom on how the version control
tool should be used). What it means to the integrator is that they must now
go in and update any references to the old thing that the developer made and
have it now point to the new thing. Multiply this task by having several
developers working on their own widgets and the integrator being responsible
for producing several different product builds and you quickly have a
potential mess...and ticked off integrator(s) who will greet each change as
an onerous burden rather than a relatively straight forward thing to handle.
Instead if the contract between integrator and developers is that things are
only committed to the trunk when they are "fixed/improved/extended" then the
integrator's work is straight forward, create a snapshot of the trunk (i.e.
create a release tag) and build it. Doing so has the following benefits:
- You haven't burdened the integrator to make changes in their stuff simply
to accomodate a new commit by a developer.
- You lessened the burden on the developer, there is no need for them to
create a new tag to follow the commit that they just did.
- You've lessened the need for problematic communication by the developer
announcing the availability of their new widget since now the developer does
not need to keep track of who all the integrators that might choose to use
their widget.
- The trunk then is the one place where one needs to go in order to get the
absolute latest/greatest/believed-to-be-best
Now of course the usual objection to this approach is that if the trunk is
the 'golden code' and a developer commits something that has some problem
with it then they've created a problem that needs to be fixed. OK, but the
problem exists, it is checked in, it needs to be fixed. With the approach
that you subscribe to, the developer has announced his new widget, the
integrator(s) cheerfully updates all of their references to the new widget,
does the builds and low and behold you're in the same spot, there is a
problem that needs fixing.
The only way you avoid having the problem appear is because of a breakdown
in communication between developer and integrator where the integrator was
unaware of the new widget and didn't update their references. Counting on a
breakdown in your system is probably not a 'good' thing to rely on. Finding
problems in the trunk early is better than finding them later. At crunch
time, if the problem can not be easily fixed, the integrator can choose to
roll back to the previous version by updating the references to widget to
point to the earlier working version. The solution and effort for this work
around is the same whether you follow my approach or yours, in my case
though this effort is the exception rather than standard operating
procedure.
Thanks again for explaining how you go about doing things, it's always good
to hear about different ways of approaching the same basic problem.
Kevin Jennings
[1] The assumption heres are that
- Trunk code that references reusable components does so via references to
components that do NOT specify specific revision levels (this would have to
be manually checked by the integrator, but also can be automated somewhat
and does not need to be a critical path thing to do)
- The creation of the tag or labelled version locks down specific revision
levels for that tag, but not to references that may be the trunk