Processes and Conventions for Code Development, Source Code Control, and Build Verification
All software that ships must be precisely reproduceable from source in-house at any time in the future.
All acceptance testing of software should only be performed on software that meets this requirement.
The ability to reproduce any product exactly requires verification. Engineering builds are not acceptable until they can be reproduced (bit for bit) outside the engineering department.
Loosely speaking, the Source database can be divided into two logical branches. The left branch focuses on reusable code, such as our core technology software, 3rd party frameworks and SDKs, and miscellaneous code that is likely to be used in more than one deliverable.
The right branch is the focal point for building projects. Each of its projects represent complete trees containing whatever is needed to build the project with the fewest possible steps, which are also documented and archived together with the project (see documenting builds).
These two logical branches are actually implemented for convenience as six directories. The “left” branch is comprised of:
· Core: Contains core technology. Code likely to be shared by different applications and different platforms.
· Platf: Contains platform specific frameworks, utilities likely to be shared by more than one application on any given platform.
· Misc: Appropriate for high level code which is shared by more than one application, but does not properly fit in either of the other categories.
The right branch of the database is comprised of:
· Apps: Each project it contains is a discrete deliverable application.
· Test: Similar to Apps in purpose, but is designed to contain experimental projects, and white box test applications. Its projects are either not intended to ship, or in too early a development phase to be part of Apps.
· Util: Contains source to projects that are intended for in-house use, rather than shipping. (e.g. A serial number generator, A utility for generating tables shipped with a product, installer plug-ins, etc.)
The illustration above shows an example of an imaginary application, ColorMaven™. The project itself is stored in the Apps directory of the source database. It appears completely self contained. It shares components with other applications from both the Core and Platf directories in the database.
SourceSafe allows, and defaults to, many non-recursive variants of operations. This is not what you usually want.
Remember the following mantra: Files are dynamic; projects are static. Only the files are dynamically shared between projects, whereas the projects themselves are unique copies. Shared projects will not reflect changes in project membership (adding and deleting files). The simplest solution is to delete and then reshare the project from the application tree.
Fixing bugs or other modifications to shared code can be done directly from the application project in which you work.
Prior to making any major design changes to an application or library project, create a recursive branch of the project. Bug fixes will go into the branch, while the original project can be redesigned at will. See the section below “Reliably recreating older versions” for details.
Learn the mantra Label, branch, label, branch…; SourceSafe (and most other version control systems) will not be able to reproduce anything useful in the future if users do not recognize where these functions need to be applied.
Unlike files, whose version numbers are incremented with each check-in, project histories only record two kinds of events:
1. Changes in project membership (adding or deleting subprojects and files), and
2. Project labels.
Let’s say that two developers have sequentially checked-in their respective modifications to the project. Robert has made several bug fixes the QA department is dying to verify, and Simon has subsequently checked in some great new features, unfortunately, they were not adequately tested, and still need some work. If Robert did not create a label after check-in, QA may be unable to get a build they can test until Simon works out all of his bugs (which could be days), or Simon goes through and rolls back all of his changes to re-stabilize the code (which could introduce new problems).
Labeling is a quick and inexpensive operation. While a project manager should decide when to label a project for major milestones, anyone working on the project should apply canonical labels whenever a significant fix or other modification has been made to the project.
I recommend the following labeling convention for labels. A label applied on Jan 14, 1999 should be called L19990114. In case of more than one label applied on the same day, the second label should be L19990114.1, the third L19990114.2, etc. This convention allows any developer to label the database at any time, for any reason, without making any claims about the state of the project.
As mentioned above, most version control systems are adequate at reproducing versions of the contents of individual files, but will not reproduce the entire prior state of a project, even if labeled, if files have been deleted, renamed, or moved. Unfortunately, even modest modifications can require branching to reproduce previous versions.
One of the most annoying defects of SourceSafe is that, unless you work around it via conventions, it is cumbersome to determine how a branch is related to the main trunk of a project. Rather than create the branch with a shared history, or even with no history (as it might as well do), branches are created with a history of the process of their replication, giving them meaningless version numbers.
For this reason we adopt a naming convention for branches which tell us what we want to know. First we label the main trunk, which guarantees a version number for the project. Then we branch and name the new project after the main trunk and its version number at the time the branch was created.
For each library use, the project manager decides whether to subscribe to a pinned version of a project, one subject to maintenance, or the main trunk of a project under development. If the project team acts only as a consumer of the library, and it is considered reasonably functional, subscribing to a pinned version makes sense. If some members of the team are also likely to find and fix bugs, then subscribing to an unpinned branch of the tree is a better choice. If there is any significant development or redesign taking place in the main trunk of the library project, then subscribing to it “live” poses real risks to the project manager. Developments in the library—such as API changes, changes in dependencies, and of course the introduction of major bugs—will destabilize any application projects that subscribe to it, and require constant overhead to keep up with the changes that a project cannot afford to meet its milestones.
While we strive for “push-button” builds, there will always be reasons why we may fall slightly short of the objective. It will always be necessary to document—as part of the versioned, archived product itself—all information needed to reproduce the project from source.
This document should be a plain text file, located at the root of the project, named according to convention (something like projectname.doc). It should contain:
1. A list of all tools and exact version numbers needed to replicate the project;
2. A list of all source files and libraries that are for some reason not archived, yet needed to to build the project;
3. An accounting of the options used to compile and link the project (for each type of target) and rationale for the settings;
4. A map describing the layout of the project, the components it contains, and rationale for inclusion of each of the components;
5. An explanation of which targets need to built to achieve any given end;
6. Release notes for the project (list which features added, which bugs fixed, etc.).
1. To facilitate push button builds. One recursive get from the database gives you everything you need to build a project. The alternative of getting the individual pieces is too complex .
2. Allow different projects to use different versions of core technology. Where multiple projects are under simultaneous development, they are not always ready to upgrade to new versions of shared code at the same time. This becomes the decision for the project lead on each individual project, any other system forces all projects to upgrade at the same time.
Not necessarily. Using SourceSafe, you can modify the files comprising the shared code from within your application tree, and these changes apply everywhere. For adding and deleting files, see the section Using SourceSafe Features.
Yes, and this is what you want, since the only alternative is to assume that all projects are sharing the same version of a library at all times, and must all bear the burden of upgrading continuously and simultaneously.
Unfortunately, few of the potential benefits of SourceSafe can be realized without these or similarly cumbersome procedures.
 Although immediately after a branch, it may appear that you have two equivalent projects, there is an important difference between the original and the branch. In SourceSafe, the branched projcects do not share the same history. In other words the original project has the complete historical record of project modifications, but the copy created during the branch has a less useful history which only documents the replication of the project.
 Actually, project branches also increment the version number.
 SourceSafe seems to lack a file-obsoleting feature, which is so useful in Projector.
 Incredibly enough, the name of a file is not versioned, so old builds will break if you simply rename a file in the future. Getting a previous version of a project will give you the old wine in the new bottles.
 Branching is a relatively expensive operation, particularly in SourceSafe, which creates separate copies of each of the files in case they should be modified in the future. For this reason it is preferable to think carefully about issues such as file names and locations prior to adding them to the database, and to avoid making these types of modifications piecemeal. Rather, mods of this type are better saved and implemented all at once when branching is deemed a necessity.
 In other words, when the project details change, this document should change, and version control of this document gives us a history of the project development, when tools transitioned between versions, when features where added, etc.
 This is especially necessary in build environments where something needed to make the project work is for some reason not set in the make file itself (where it should go if at all possible), but rather in an environment customization.
 If the shared project is pinned to a specific version, its files cannot be modified. If the shared project is the latest version, then its files are updated live. With SourceSafe, the best solution is to branch the shared project which is undergoing major changes, and projects that share the older branch can make bug fixes to their version. (Care must be taken to apply the same fix in parallel, where applicable to the latest version of the library under development.)