Software life-cycle modelling is the business of tracking source code as it goes through various stages thoughout its life, from development, to testing, release, reuse, and retirement. This document describes PERFORCE's support for life-cycle modelling and provides a reference model. But first it describes life-cycle modelling the way other SCM systems support it, using the "promotion" model.
The salient feature of the promotion model is how the source code trunk is used. Contributing features are whether the model supports promoting individual files or whole projects and how branching is used.
In the promotion model the souce code trunk goes through different stages over time. The stage of each revision of each file is indicated by some attribute(s) whose definitions are worked out in advance to reflect the intended life-cycle of the source code. Typical values are in "development", "QA", "released", or "retired". The various revisions of each trunk file will usually be in different stages: the tip revision might be in "development" while an older revision from a year ago may be "released."
The concept of promotion comes in to play when a revision of a file is considered ready to move to the next stage. At that time, the revision is promoted. For example, after an engineer is finished adding enhancements and is ready to have them tested, he might promote the new tip revision from "development" to "QA." Sometimes a revision can be demoted; if it fails to pass QA it might be demoted back into development for further work. Because of this promotion/demotion notion, stages are usually refered to as promotion "levels."
SCM systems that support the promotion model always have some way of asking for the latest revision of a file at a given promotion level. The QA engineer will request the last QA'ed revision of all files. The developer will work against the "development" revisions. A released product would be built from the revisions marked as "released."
Often, SCM systems assign each user one or more "roles" that defines their access to revisions at each promotion level. For example, only QA engineers will be able to check out files whose status is "QA", and only a release manager will be able to promote "QA" files to "released."
A tricky problem arises when someone needs to change a revision of a file other than the tip. Typically the tip will be "in developement," but if QA finds a bug after a developer has made further enhancements then a non-tip revision may need updating. One solution for this is when the SCM system can make an ad-hoc branch at the revision that needs updating. ClearCase takes this approach. If a lot of activity is needed to get the code past QA the trunk can sprout quite a few branches and the final release might be quite "bushy." Another approach is to check in the updated non-tip revision as the new tip anyhow. The system must then "weave" the related revisions (those at the same promotion level) up the trunk of the file's revision history. This essentially treats different promotion levels as separate branches in the file. PVCS uses this approach.
Aside from these ad-hoc branches, branches off of the trunk are used largely for parallel development. There may be many branches off of the trunk for various projects, each periodically merging its contributions back. Branches themselves may go through promotion levels as well, but they usually are all considered to be at the "development" level.
Some coarser-grained SCM systems group files into "projects" and their promotion model supports promoting these whole projects rather than the individual files. The advantage to this is that there is much less detail that the user must potentially remember; on the downside, it limits flexibility because the granularity of promotion is determined when the project is created, rather than when it is promoted.
Systems which support projects often limit their branching to whole projects as well. This is sometimes described as "baseline branching", because the whole baseline of a product is branched at the same time. With baseline branching comes a slightly greater capability for promotion: each project can have its own promotion levels. The trunk may remain the main line of development, with promotion levels reflecting the development cycle. At some time a baseline branch of the development project(s) can be used for a release, with promotion levels reflecting the release cycle.
The major downside to the promotion model is that important information is obscured. In addition to the file's name, the revision number and its promotion level all determine the current purpose of the file. While the file's name is always visible, the significance of the revision number and the promotion level are much less apparent. Most SCM systems use hard-coded protection mechanisms to keep (otherwise honest) engineers from modifying the wrong files.
Further, tracking history can be complicated. The history of a file's trunk may be incomplete (with ad-hoc branching) or quite confusing (with branches woven in as promotion levels).
Finally, promotion history is often not versioned as well as regular file history. If a file is promoted and then demoted, it may not be possible to reproduce a release made when the file was in its promoted level. Usually only one revision can be at any promotion level. If a file was promoted to "released" last year and now a new revision is up for a new release, either a different promotion attribute must be created or the promotion level of the previous release will be lost.
In the PERFORCE model the source code trunk retains a single purpose: it is the main line of development. That is, its promotion level would always be considered "development."
PERFORCE implements promotion by branching. PERFORCE's fast, low-overhead branching and integration support makes this feasible. The first time files are promoted they are branched from the trunk into a branch. Subsequent revisions that are to be promoted are merged from the trunk to the branch. Because the different promotion levels are in fact separate branches, they can evolve independently.
PERFORCE's branching mechanism, called Inter-File Branching TM, makes branches by (virtually) copying files and giving them new names. Each file then proceeds with independent revisioning. So when a file in the trunk is branched, an example might be that //depot/main/db/dbhdr.h gets branched into //depot/maint/2.1/db/dbhdr.h. This contrived example matches the ones that are to follow, but it is important to note that PERFORCE can branch any file into any other file. //depot/a/b can be branched into //depot/c if desired. For our branching, we choose to use the identifiers right after //depot to indicate the branch name, and we refer to that branch as a "code line."
PERFORCE can branch individual files, groups of files, or the whole depot. PERFORCE does not, however, support ad-hoc branching, where a file can be checked out of one branch and into another. One reason for this is that it is much simpler to understand -- branching is always an explicit act. PERFORCE's branching performance makes branching large groups of files at the same time feasible.
Thus when promoting files, the recommended approach with PERFORCE is to branch all files that are to be promoted.
This section describes a way of using the PERFORCE model in a particular way. A few variations are provided as well.
It is possible to mimic the promotion model described above with PERFORCE, using branching to promote groups of files from //depot/development to //depot/qa, then //depot/release, etc. But this might require that the "release" code line be used over and over again for multiple releases, each time integrating the changes from the "qa" code line (and that in turn from the "development" code line). This is certainly possible, but really the separate releases are distinct entities and should be named as such.
A more precise criterion is that a code line should be branched if its intended use is incompatible with its current use policy. For example, the policy of the development line (that it can accept new functionality) is usually incompatible with making stable releases, and so release lines should be branched from the development lines. Further, old releases generally have a policy that permits changes only for emergency patches. This is inconsistent with a the policy of a newer release, which permits more frequent bugfixing.
So we propose a model that takes advantage of PERFORCE's low-overhead branching by making a separate branch for any code line that has a unique policy.
In the reference PERFORCE model, the trunk is the primary development line. It is called "main", meaning its files live under //depot/main, and it represents the family jewels of the company. While newer code may be being developed off in special development branches, the mainline is the ultimate destination for all software development. Bug fixes and porting changes made in release lines are expected to make it back into the mainline. It is possible for certain changes to be made directly to mainline if that is desirable. A good policy for the mainline is that it should always build. A better policy is that it should always pass its tests.
During the course of product development, releases will need to be made. At the point where the mainline's policy diverges from the needs of a release -- that it, when new functionality is no longer desired in the release -- the mainline is branched. The new line is called a maintenance line and given a name that reflects the release name. For example, for release 3.5 of a product the line would be named //depot/maint/3.5.
Creating a maintenance line is somewhat analogous to promoting the files from "development" to "QA". But the line is named after its intended use rather than its current user, and its name includes the release number. By including the release number we make it clear that this line is not to be reused for other releases.
After the maintenance line has been created it is insulated from changes made to the mainline. Moving changes in either direction requires explicit user action. PERFORCE makes this action easy, but it is still driven by explicit request. Propagating changes from the mainline to the maintenance line is analogous to promoting new revisions to "QA". Unlike the promotion model, which only allows changes to move up the promotion scheme, the PERFORCE model allows independent development (customization, bug fixing, etc) to occur in the maintenance line and later be merged back into the mainline.
During the course of testing, the maintenance line will be found to be ready for release. At the point where the maintenance line's policy diverges from the needs of a release -- that is, when only emergency patches are permitted -- the maintenance line is branched. The new line is called a release line and given a name that reflects the release name. For example, for the first release of our 3.5 line we would branch //depot/maint/3.5 into //depot/release/3.5/01.
Creating a release line is analogous to promoting the files from "QA" to "release". The release line, with any luck, will never change after it is branched. It can, however, serve as the line for one or more emergency patches if the need arises.
The maintenance line from which the release line was branched may go on over time to take on bug fixes or selected enhancements from the mainline. If so, it will spawn further releases (/02, /03, etc). Such activity can continue up until (and even after) the mainline spawns another maintenance line, such as //depot/maint/3.6.
Neither the maintenance lines nor the release lines ever lose their identity. Retirement of these lines simply occurs when activity ceases. A line can be pulled out of retirement simply by using it again.
An important feature of the PERFORCE model is that the relevance of a file is encoded in its name: //depot/release/3.5/01/db/dbhdr.h is a file that is part of a release, and clearly not the place for miscelleanous enhancements. Similarly, //depot/main/db/dbhdr.h is clearly not where shippable products are built. Further, the whole of release 3.5/01 can be found under //depot/release/3.5/01 and not anywhere else in the depot. This plain-as-the-nose-on-your-face approach is the hallmark of PERFORCE's branching model.
An equally important feature of the PERFORCE model is that a code line can give rise to more than one line "at the next promotion level." That is, the mainline can spawn multiple maintenance lines, and they can be active at the same time. The normal promotion model doesn't permit this, because only one revision can be at a given promotion level. Unfortunately, multiple active releases off of multiple active maintenance lines are realities with large software products.
Development need not occur directly on the mainline. Individual developers or groups can branch from the mainline into project lines named //depot/dev/project, where "project" is the name of the user or group. In this case, it is probably not necessary to branch the whole of the mainline, but only the areas that are likely to see changes. For example, the database development group might branch the files under //depot/main/db into //depot/dev/fast-db/db for a performance enhancement project.
Not all products need both maintenance lines and release lines. Sometimes release can be made directly from the maintenance lines. This is good for products that are small or have a short life cycle. Truly small projects could actually be released from the mainline.
It is not necessary to create the branch at the time the policies diverge. By using a label to mark the intended branch point, actual branching can be delayed indefinitely. If, for example, the mainline is deemed stable enough to enter testing then the current revisions can be marked with a label. If the testing reveals the mainline has a long way to go, the mainline can be fixed and then the label moved up. If, on the other hand, the testing reveals that the mainline (at the label) is ready to be moved onto a maintenance line, PERFORCE can branch the mainline at the label into the maintenance line.
PERFORCE's life-cycle support and its reference life-cycle model build upon high performance Inter-File Branching TM. By branching whole code lines and using the file name space to denote branches, PERFORCE provides plain, understandable software life-cycle support.