Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / TFS

Project Definition and Versioning

4.86/5 (11 votes)
25 Feb 2013CPOL63 min read 19.5K  
Project Structure and build scenarios

1. Applicability and Scope

The recommendations and guidance presented in this document apply to Team Foundation Server Version Control, Visual SourceSafe, and Subversion as of the publication date. Follow the project structure guidelines for Visual SourceSafe projects since these will soon be migrated to Subversion or Team Foundation Server.

2. Purpose and Sources

This document attempts to minimize the focus on using particular products and is aimed at providing guidance and justification for the recommended repository, project, and solution structures based on scenarios that occur in software projects in any organization and the best practices promoted by the IT industry and Software Configuration Management (SCM) in general. I aim to show you how to accomplish specific goals as they relate to SCM and the decisions and concepts involved.

This document draws upon the combined published experience of developers using a variety of version control systems (VCS). The recommendations for the core version control structure (BTT) are published and promoted primarily by Subversion users. In itself, this represents the combined experience of millions of developers worldwide over the past 21 years on a variety of projects of all sizes. Each VCS vendor, of course, has their own guidance and recommendations on this subject with various slants to highlight the capabilities of their own systems.

This document also includes project structure guidance that, while not specifically related to any type of version control, certainly enables some of the version control tasks to be performed cleanly and simply. The project structure guidance itself draws upon sources both related and unrelated to version control and software configuration management (SCM). This guidance incorporates the theory and practical advice of a multitude of IT disciplines, project models and recommendations from developers and vendors on all platforms.

This document will be followed by a set of focused "how-to’s" demonstrating each of the scenarios and tasks presented using the products and tools currently in use.

3. Words of Warning

Good version control systems are effectively time machines. You can delete things to your heart’s content and remain confident that you can always get it back at any time if you should need it. The view provided by most version control systems shows you a directory structure that looks very similar to a file system. It is important to realize that the view you’re shown is only the structure as it exists at a particular point in time (typically the present, unless you tell it to show you the system as of some prior date or change).

The fact that a good version control system will faithfully store anything you put in there and never lose it makes it fairly important that you never store anything that you don’t want to keep a record of for all time. Private passwords, credit card or bank account numbers, personal data and any form of PHI should never placed in version control. Although it can easily be deleted from the current view, it will always remain available in the system’s historical views; accessible to anyone with appropriate access.

If the version control system is used to maintain source code, be sure that you only store the source code information and dependent binaries that are necessary to build your software solution. For example, do not store the ISO image of the Visual Studio installation DVD or the installation packages for other tools. This would simply be a waste of space, as these are readily available from other sources and, if placed in version control, can never be truly removed.

With that said, please do delete anything and everything that you no longer have a use for. The default, current view of the system should only show you what is relevant and supported or in active development now. Do not leave dead or retired branches in the current view any longer than necessary. If you ever have need of them again, they will still be there.

"Destroy" supported in TFS 2008

Astute readers may be quick to point out that the "Destroy" capability, the ability to permanently remove an item from version control, is available in Team Foundation Server 2008. This is a double-edged sword.

The ability to completely eradicate all traces of data is certainly important from a security perspective (PHI, or Personal Health Information, for example) and from a repository maintenance perspective (CD/DVD images or SQL databases accidentally committed to version control, for example), but must be used very sparingly and with extreme caution.

Keep in mind that two of the main purposes of version control are to allow people to share information and to keep a history of all changes to that information. The ability to destroy an item defeats both of these purposes.

The ability to destroy can have drastic unintended consequences:

Consider first, a file that contains a piece of PHI that must be removed from the system, regardless of consequence. This file has itself been changed numerous times, branched to six different releases and merged several times with otherwise ‘safe’ information. You decide to "Destroy" the file where the PHI first appeared. What happens to the other variations, both before and after the change that incorporated the PHI? What happens to the history of that file?

Consider also, the situation where a release is branched to the wrong place. Instead of moving the new branch, it is branched again to the correct location, and instead of deleting the errant branch, you decide to use "Destroy" to remove it permanently. What happens to your history of the correct branch…is that gone? Does the correct branch even exist since the basis for that branch was destroyed?

4. Version Control Models

There are two primary version control models in use; the Lock/Edit/Release model and the Copy/Modify/Merge model. For a description and comparison of the benefits and drawbacks of each, visit Versioning Models.

The first is the Lock/Edit/Release model in which a user must request exclusive access to a file in order to edit it, and then remember to commit the change (and release the lock) to allow others to modify the file in the same manner. This is the model used by default in Visual SourceSafe and all work on individual files needs to be serialized (one user after another).

The second model is the Copy/Modify/Merge model, in which the user can edit any file at will after retrieving it from the server, but must resolve any potential conflicts introduced by other users when committing changes back to the server. This is the model used by default in TFS and allows work from multiple tasks to progress in parallel.

Users migrating from Visual SourceSafe should specifically be aware of these changes. While in most version control systems the term ‘checkout’ refers simply to the act of creating a working copy from a specific URI and version on the server; in TFS, this action means ‘make writable’ and retains the terms ‘Get Latest’ and ‘Get…’ in order to perform the checkout. When you perform a ‘Check Out’ in TFS, it will not retrieve any changes from the server (it only switches the read-only attribute on the file) and by default, it will not prevent other users from checking in their changes.

While TFS can be modified to work more like VSS, including exclusive locking semantics, do not set these options. You will reduce or eliminate many of the benefits of parallel development and revert to a serialized, unproductive working style.

One argument recently heard in favor of the Lock/Edit/Release model is "Our team is diverse enough in our efforts and not as tightly integrated as other teams. We also are going to be growing again this year. So, we don’t feel there is enough day-to-day collaboration and communication to allow multiple individuals to work on the same file…call it a fail-safe, if you will." This argument is flawed. Many diverse and globally distributed users use the Copy/Modify/Merge model daily (and simply would not be able to work using the Lock/Edit/Release model). Take a look at any given Open Source Software (OSS) project as an example. All code on CodePlex, Google Code, SourceForge.net, and many other public and private repositories are developed using this distributed model by groups of developers who may even be unaware of each others’ existence in time and space. A very few concrete examples of highly successful projects developed in this fashion include the Microsoft Enterprise Library, NUnit, and the ASP.NET AJAX Controls.

We will enforce the multiple check-out option at the Enterprise level and remove Team Project Administrators’ ability to adjust these options if that becomes necessary. The necessary level of collaboration to support large and geographically dispersed teams is already enforced through Changeset Comments Policy.

5. Log Messages and Changeset Comments

"All version control systems have to solve the same fundamental problem: how will the system allow users to share information, but prevent them from accidentally stepping on each other's feet? It's all too easy for users to accidentally overwrite each other's changes in the repository." – Versioning Models

The Copy/Modify/Merge model enables parallel development, and is required in order to use modern programming tools effectively. For example, refactoring tools (built into Visual Studio 2005) can modify large numbers of files with a single change...this would not be possible in the Lock/Edit/Release model if any of those files were locked (exclusively checked out) by another user. Even the simple act of adding a new file to your project modifies at least two files (the project file and the file being added) and potentially several more (designers, code-behinds, etc.).

The drawback of the Copy/Modify/Merge model, however, is that people must communicate what they’re doing. Good version control systems provide the ability to enforce this communication by rejecting any attempted commits unless they are accompanied with a message describing the changes made or associated with a request for those changes.

Team Foundation Server can go one step further, if you enable this option, and require that every set of changes be associated with a requested Work Item. This implies that any change made to any business project would need to be preceded by a request for that specific change and those requests and their associated changes can be traced back to a business or technical requirement. These change requests would have to be itemized in detail by a project manager or tech/team lead before they could be worked on by developers.

Implementing Work Item tracking would require an extreme level of discipline among every team member and places an additional and unwanted burden on project managers and team leads that is not present in current development models. As a result, we feel that this implementation is simply unfeasible at this time. (As a side note, this is the default implementation used in the MSF for CMMI process template for TFS.)

In lieu of requiring that every change be associated with a request, we use and recommend an implementation where every change must be associated with a description of that change. This is known in TFS as the Changeset Comments Policy.

Every commit of any set of changes in version control must be associated with a comment describing why the changes were made. This is a requirement and must be understood and communicated clearly to all members of the team.

Unfortunately, TFS also gives individual users the option to override this policy with each commit, but you must still specify the reason why you are overriding the policy in order to perform the commit. Do not attempt to override the policy and place the description of your changes in the Policy Override Reason. This is an inappropriate use of both the comment and the policy override.

The comment itself must describe why the changes were made and/or the intent or goal in making those changes. Comments such as "sdf", "added changes", "modified function", "daily check-in", etc. will be rejected and must be corrected by the developer or, failing that, their team lead or Team Project Administrator. Consider what the comment will mean next week, or in three months, or two years from now. Next to the comments before and after the current set of changes, will it sufficiently convey to you or your readers what changed and why? Examples of good comments include "Corrected spelling errors in documentation", "Added unit test project to solution", "Changed web.config to enable impersonation", and "Removed deprecated BaseDAO.cs file – it is no longer needed or used in the project".

The Enterprise Architecture team reviews the comments for all commits to all Team Projects and may mark specific comments as bogus or vague and uninformative, specified in the wrong location (Policy Override Reason), or both.

When such issues are detected, and for every such issue detected, the Enterprise Architecture team will respond with an e-mail describing the correct use of these features and copy all Team Project Administrators for your project to inform them that this information and policy should be redistributed to your team members and that it is their responsibility to ensure that this practice is understood and consistently applied.

When such messages are received, we suggest having the original committer update their comment as soon as possible while their changes are still fresh in their mind. If the developer cannot be reached or does not respond in a timely manner, then the responsibility falls on the team lead or Team Project Administrator to make these updates, and this will often involve a ‘Diff’ of the existing changeset with the previous changeset to determine what changed and why in order to provide an appropriate comment.

Descriptive comments are required, and informative and goal-oriented comments preferred. This is the only means at our disposal to determine at a glance why changes have occurred on the project without digging into the source files themselves. If you cannot describe why you’re doing something, then you probably shouldn’t be doing it (undo your changes instead of committing them).

6. Common Terms

URI (n.)

The term URI (Uniform Resource Identifier) is used here to refer to the path to an item in a version control system. Version control URI’s start with a dollar sign character followed by a slash, followed by zero or more path components separated by slashes, as in ‘$/Enterprise Architecture/trunk/ Application Blocks/v2.0/Src’.

Branch (n., v.)

A branch is any independent line of development. In this document, the noun ‘branch’ is used to refer to one or more paths in version control that share a common history (see cheap copy). The verb ‘branch’ is used to refer to the process of creating a cheap copy of a software solution at a different path in version control.

BTT (n.)

The BTT structure refers to the /branches, /tags and /trunk root directories commonly used in enterprise version control systems. Within TFS the BTT structure is created inside each team’s Team Project.

Cheap Copy (n.)

A cheap copy is created when the version control server creates a new URI and points the contents of that URI to an existing URI and version. The end result is that no actual data is copied, but from a user’s perspective, there now exists two complete source trees containing the same data.

When a modification is made to Tree A (currently at version 534), it begins to diverge from the source in Tree B, since the source in Tree B is based on version 534. The next version on either tree would be 536 and above. When modifications are made to Tree B, it will diverge from Tree A in the same manner.

Commit (n., v.)

A commit refers to the process of sending a set of changes to the server. In a system that supports atomic commits, either all of the changes are successfully relayed to the server, or none of them are. TFS represents such a system.

A clean commit implies that the set of changes are all somehow related. For example, a ‘Rename…’ refactoring may modify several – even hundreds – of individual files across several projects, and be considered a clean commit when those changes are sent to the server with the comment ‘Renamed Foo to Bar’.

A dirty commit implies that there is no meaningful relationship in a set of changes. In the example above, if the developer also added a new class to the project and failed to mention this in the comment (or, as often happens, forgot what changes were made), this constitutes a dirty commit. Dirty commits should be avoided if possible because they make it difficult to track which changes accomplished which goals.

Conflict (n.)

A conflict occurs when the system does not have enough information to perform an automatic merge successfully. For example, if both the source and target of a merge operation contained changes to the same line of code and each change was different, a conflict would occur and the system would prompt the user to decide how to handle the situation.

Merge (n., v.)

A merge refers to the process of incorporating a group of committed changes to a different URI from the branch where the changes occurred. The source of the merge is the URI containing the changes that should be incorporated, and the target of the merge is the URI containing the branch that you wish to update. When a merge is performed, all changes made to the target branch are pending until the changes are committed; this allows you to examine the results of the merge before making them permanent.

Working Copy

The working copy refers to the structure and files of a project present on a user’s hard drive that are associated with equivalent items stored in version control. Changes in the working copy are not reflected on the server (or made available to other users) until these changes are committed.

Shelve

Changes in the working copy can be shared with other users by shelving the changes, instead of committing. Shelve can be used for code review purposes.

7. Core Version Control Structure using BTT

The main line of development is defined in /trunk, although this is not where typical development occurs. The trunk should always contain the most stable current release(s) of your software solutions. Some organizations insist that the trunk remain in a perpetually deployable state and limit write access to the trunk to select individuals responsible for preparing a release.

Offshoots from the main line of development, including new versions that have not been deployed, are defined in /branches. Typical development occurs in one or more branches in this sub-tree. There are two fundamentally different kinds of branches based upon the intended use of the branch; feature branches and version branches.

Feature branches are used to isolate potentially breaking changes without unnecessarily affecting developers working in other branches. The purpose of a feature branch is to introduce and stabilize a new feature (or feature set) and then merge the changes into a more stable branch. As such, feature branches tend to be short-lived and are deleted after the feature branch is merged.

Version branches are used to introduce a new line of development while maintaining the existing version. The purpose of a version branch is to add/change/enhance/retire functionality for the next release. Bug-fixes and changes to the existing version are rolled forward to this branch, and the version branch eventually becomes the current release and promoted to the /trunk. The source of this branch – the original URI – is eventually retired and then deleted.

The purpose of the /tags URI is to contain ‘snapshots’ of your projects at various points in time that are deemed interesting from a business perspective. Typically, these ‘points in time’ will coincide with a release, but this is not their only use. The important thing to remember about tags is that they should be considered and treated as read-only once they’re created. To make any change at all to a tag branch defeats the purpose of the tag. In fact, if an automated build system is in place, it should be the only entity with sufficient privileges to create a tag branch, while everyone else has read-only privileges. In this scenario, when a release is actually ready to be executed, the build system would create a tag from the trunk, build the tag, and then perform the deployment (if automated) or turn the results of the build over to a release engineer for manual deployment.

Note that the value of the BTT structure rests in adherence to its intended use and the semantics attached to each name in the structure. If a release is performed from sources in the /branches sub-tree, without first promoting it to the /trunk, or if the /trunk itself is broken for several days on end while a major refactoring effort is underway, or if any change at all is made to a /tags sub-tree; then the value of this structure is significantly reduced. While some of this can be enforced electronically (such as the correct use of /tags in the automated build example above), much of this relies on social contracts that cannot be enforced through software.

The ongoing feasibility of this structure is highly dependent on the ability to successfully relocate a project without making changes to the project (e.g., to fix up reference paths, virtual directories, etc.). The recommended project structure addresses this need by making each business project completely self-contained, requiring only the necessary framework and compilers in order to build and test the resulting application.

Please note that Visual Studio 2005 SP1 Web Application and Web Service Application projects will require special handling in this regard because of their dependency on IIS virtual directories, while Web Site and Web Service projects do not.

8. Core Project Structure

The core project structure as it is defined here is what you should expect to see as shown in the /trunk sub-tree in the BTT structure described above. The variations in this structure as they are used in the /branches sub-tree are noted in the branching tasks and scenarios.

The core project structure defines at least two folders in a parent-child relationship. The parent folder holds the name of the business project, while one or more child folders hold the names of the targeted releases. The parent folder is referred to in this document as the ‘project folder’, and child folders are referred to as ‘release folders’. The project folder will remain until the business project is retired (at which time it can be deleted), while new release folders will be added or removed as necessary to coincide with planned releases. At any point in time, one of these release folders exists for each such release ‘in the wild’ (in some public environment, even if that environment is internal).

It will be the release folders in this structure that are themselves the source and target of branch and merge operations. The graphic to the left shows a naïve view of what this structure might look like using a product that should be familiar to all readers.

Using the example shown, let’s assume that Office 2003 (v11) just shipped, Service Pack 1 (v11SP1) was already being ‘dogfooded’ internally (equivalent to our TEST environment), and Service Pack 2 (v11SP2) was in active development.

At that point, all the v11 directories would be present as well as the v11SP1 directories (since it was released internally), but v11SP2 would only exist in the /branches sub-tree. Additionally, the RibbonToolbar project would not even have been created yet because the business is still finalizing the Office 2007 (v12) requirements and correlating user feedback – development hasn’t begun on this version.

Developers would be working in their respective /branches either on v11SP2 or responding to defect reports on v11SP1 and Quick Fix Engineering (QFE) requests on v11. Before each internal release of v11SP1, the changes would be merged into their corresponding folders in /trunk, stabilized, tagged in /tags, and released.

As v11SP1 readies for the CTP and Early Adopter Program release (equivalent to our QA), v11SP2 is released internally and finally makes it into /trunk. In addition, the v12 folders are created in /branches by branching /trunk/[Project Name]/v11SP2 (as the most current release) to /branches/[Project Name]/v12. Since v12 will incorporate a new technology called a Ribbon Toolbar, a new project is created for it in /branches and development on Office 2007 begins in earnest.

Some important takeaways from this model are:

  1. Active development occurs only in /branches. The /trunk is reserved for integration and stabilization purposes (the target of merges from various sources), and /tags are created for each actual release.
  2. Each business project shown is independently testable. Any release of ‘CommandBar’, even though it represents a common library (or set of libraries) used by multiple products, doesn’t need the full-blown ‘Excel’ or ‘Word’ programs to be tested. It only needs a simple test harness that exercises the API that ‘Excel’ and ‘Word’ are going to expect.
  3. The structure is organized to the extent that automated tools can be provided to show a list of business projects and, once selected, their target releases, to be built, analyzed, tested or deployed at any time.
  4. The actual software projects defined in these release directories are moved around…a lot (branching, merging, branch promotion to trunk and then tags, etc.). These projects can be checked out by anyone with appropriate access to any location on their machine and built and worked on locally. In short, everything inside one of the release directories is and needs to be self-contained.
  5. A cycle exists between /branches and /trunk. Features and fixes are worked in /branches and then branched to or merged into /trunk for release. The branch in /trunk is then branched back to /branches for the next feature set or round of fixes.
  6. Clean-up is important. Since each release folder essentially represents a complete copy of the prior release with some changes applied, it should be a regular practice to simply delete your local copy of any release you’re not currently working on, and then check it out again from the server when you need it. You would not want to check out the entire /trunk – or worse, the entire repository ($/), since you would receive a complete copy of every release of every project currently in any environment.

9. Extended Project Structure

Within each release folder, the actual components of a software solution are defined in a particular structure that enables this self-contained model. Fortunately, with appropriate branching, this structure need only be defined once for each business project (and even that can be automated or stored as a ‘template’ branch to reduce the possibility of human error).

We make the assumption that you’re using Visual Studio 2005 to create your software. If the software uses older technologies (especially the Visual Studio 6.0 suite of development tools), then other guidelines may apply as these tools have a tendency to put things where they want them.

The release folder contains, at the very least, a "Src" directory that is intended to be the root of your Visual Studio solution. The Visual Studio *.sln file itself is defined in this directory. The purpose of the "Src" folder is to contain all of the source code assets for your software solution, including all of the Visual Studio projects and files that are part of the solution.

If your solution uses any external file references that are not part of the application proper, such as the Application Blocks, third-party libraries, or common libraries from other project folders, these should be kept in a folder named "Lib" defined at the same level as "Src" in the release folder. The purpose of the "Lib" folder is to contain all of the external file references that are used by various Visual Studio projects in your solution along with their dependencies.

If there is a need to store developer-to-developer documentation that is specific to the business project or release, this documentation should be kept in a folder named "Doc" defined in the release folder. The location of this folder simply serves as a convenient place for developers to create and read documentation about the software under development that will be versioned along with the software itself.

Following these recommendations, the release folder and its contents should appear something like this:

Within the "Doc" and "Lib" folders, you may define any additional internal structure that is appropriate for your application. Additional guidance for the structure of your "Src" folder is provided in the Solution Structure section. Do not rename these folders or reinterpret their meaning or purpose. Doing so will prevent automated tools from accessing them or using them appropriately based upon this naming convention.

Each Visual Studio project that references a binary dependency in the "Lib" folder (or one of its subfolders) does so using a relative path. This structure guarantees that anyone can check out the release folder to any location on their hard drive and immediately perform a build. The relative paths in the Visual Studio projects will remain valid no matter where the release folder may be located.

It is at this point that many developers start wondering whether they can create a ‘shared’ library folder that can be referenced by several projects, especially when the dependencies of one solution are the output of another that is shared by several different business projects. On the face of it, this does make sense – after all, common libraries = common location. If other developers have the same structure on their machines, it should work, right? …right? The following graphics show variations of this theme in use today:

Do not reference shared libraries from mapped drives or shared folders outside of the release folder. This is exactly the situation that should be avoided. There are several reasons for this warning:

  • Version management – Let’s say that, using the graphic above, someone got Solution A up and running and all (known) bugs finally worked out. They get the latest sources on Solution A and rebuild in preparation of adding new functionality and suddenly everything breaks. There are no changes in the history of Solution A from the time it worked perfectly, so what’s wrong? If this model were used, then it is quite possible that someone updated Common Lib incorrectly…you just don’t know. Note that if something does ‘suddenly’ break, you’re very lucky. Typical issues like these don’t manifest themselves so readily, until they’re in production and some piece of functionality that was previously tested thoroughly is exercised by an end-user with the ‘unknown change’ in its place. If something breaks, you should be able to track it back to a change in the solution itself, or to a change in environment (Add/Remove Programs, virtual directory deleted, hardware/network issues, etc.).
  • SCM practices and Audit compliance – When Solution A (again, from the graphic above) is tagged and deployed, the only information available about the external reference that was deployed with it is the relative path where it existed at the time of deployment. Which version of CommonUtility.dll was deployed along with it? It is difficult to be sure, since Common Lib was not included in the tag.
  • Portability – Each software solution should exist as a self-contained entity. Any time you refer to an item outside of the solution root, you introduce a dependency that must be replicated to every machine using the solution and you lose the ability to branch and tag effectively. If projects in the solution reference libraries from a directory shared among your team, then these references may be suddenly broken when you create a branch or tag, and will certainly be broken when another user who is not aware of this dependency retrieves the solution or, even if aware, retrieves the solution at a different local path.
  • Unintended dependency explosion – Each reference to a compiled library in your application may be dependent on other references, which are dependent on others, and so on. Unless these dependencies are ‘in your face’ and explicitly managed, by the time you’re ready to actually deploy, you may be copying hundreds of assemblies to your deployment folder just to satisfy a couple of project references. Each of these dependencies is a tight coupling and a change in any one of them may inadvertently break your application. What’s worse, these dependencies may share a common dependency at different versions. For example, LibraryA references LibraryB and LibraryC; LibraryB references version 1 of LibraryD, and LibraryC references version 2 of LibraryD. This will only be made apparent to the developer if they manage these references explicitly. If it is not made apparent and the code is deployed, things won’t work as expected, because there can’t be two different versions of LibraryD in the same directory.

Unfortunately, the shared library model, as attractive as it may seem, becomes progressively more difficult to manage effectively over time. The self-contained model, though it requires a little more up-front work, becomes progressively easier to manage. The Enterprise Architecture team is updating the Reference Application with these guidelines, and to make this explicit dependency management even easier, there is now an ‘UpdateExternalDependencies.cmd’ batch script in the "Lib" directory to pull in the latest version of the Application Block references (and their references, etc.). The dependency management is still explicit, but with a mouse-click we can now test the Reference Application with the latest changes in the Application Blocks.

It is entirely appropriate to copy only the required shared libraries from a mapped drive or common folder shared by your team members into the "Lib" directory, especially when these components are maintained outside your group. The key difference is that this drive or common folder is not under version control (and should not be under version control). For example, if the Infragistics controls were purchased by your team, then a common directory would be set up and shared with your team from which the purchased version could be obtained. In order to be used in your project, the specific DLL’s you need would be copied to your release’s "Lib" directory and referenced from that location rather than the common location. If a newer version was obtained and placed in the common folder, it would not affect your application until you were specifically ready for it, giving you the opportunity to build and test with the newer version and resolve any issues that may arise from the upgrade.

There is one appropriate use (and place) for shared libraries in .NET…the Global Assembly Cache (GAC). The GAC shell extension (Fusion.dll) goes to great lengths to hide the complexity of effectively managing multiple versions of shared libraries, but for an illustration of the complexity involved, you may use the following registry scripts to enable or disable this shell extension. The GAC is viewable at %windir%\assembly (C:\WINDOWS\assembly).

10. Solution Structure

The contents of the "Src" directory are further organized roughly by Visual Studio project types. The "Src" directory itself contains the Visual Studio solution file and other Solution Items, as shown in Visual Studio’s Solution Explorer.

The recommendations in this section are based largely upon the needs expressed by build engineers (those responsible for building and ultimately deploying the software) and enable automated tools and humans alike to easily recognize deployable and non-deployable source code projects.

As such, the names and semantics provided should be used as they are, but please consult with Enterprise Architecture to determine if new ‘project types’ should be added to this structure.

It should be pointed out that individual elements of this structure should only be created if there is a need. That is to say, do not create any of these folders unless it contains one or more Visual Studio projects that match that project type; do not create the entire structure and then leave parts of it empty.

A description of each folder in this structure and its purpose follows, but the major project types identified thus far can be expressed using the following terms: "Data", "Hosts", "Installers", "Libraries", and "Tests". A graphic depiction of a solution containing all of these project types is shown at right. In your own projects, you may have only "Hosts" and "Libraries", or "Hosts", "Libraries", and "Tests", or just "Data" by itself. Other combinations exist and you should use the combination that is appropriate for your application.

I. Data Folder

The "Data" folder is intended to contain database projects and batch scripts used to create and initialize databases (i.e., database ‘source code'). This includes the Visual Studio "Database Project" type and the new "SQL Server 2000" and "SQL Server 2005" project types introduced with Visual Studio 2005 for Database Professionals. These projects typically contain SQL scripts, database schemas, and other files required to create, initialize, load, and change relational databases. There are advantages to using these project types in order to store database configuration scripts in version control. The Visual Studio 2005 for Database Professionals edition even extends the ‘Rename…’ refactoring support to database object names and allows the database schema itself to be versioned along with the rest of your solution.

The scripts found in these projects are typically used during deployment to ensure that database changes are reflected in version control (this can easily be accomplished by having SQL Enterprise Manager or the SQL Server Management Studio script the database prior to each release and moving the resulting scripts into one of these projects). These scripts may also be handed over to a DBA to affect database changes in other environments.

II. Hosts Folder

The "Hosts" folder contains your solution’s *.EXE and Web Site/Web Application projects. Each Visual Studio project in "Hosts" represents a deployable project and is, in fact, deployed during a release. Each host is independently "runnable" (or browsable, in the case of Web Site and Web Application projects), and can be set as the "Startup Project" in Visual Studio.

Each business project and release folder that will be deployed should have at least one "Hosts" project defined, and multi-tier applications typically have at least two hosts (Web tier and App/WebService tier) and potentially many more. Keep in mind that neither the solution nor the business project itself is deployed, only "Hosts" are deployed. This implies that a business project may encompass multiple ‘applications’ with shared core functionality and a solution’s "Hosts" projects are not limited to a single tier.

The term "Hosts" is used instead of an alternative such as "Webs" or "Exes" to indicate that these projects should act as ‘hosts’ for the application functionality defined in other project types (specifically "Libraries"). No project in "Hosts" should ever be referenced by another project (other than possibly "Tests"), and any functionality defined in a host that is needed by other Visual Studio projects should be moved into a re-usable library.

III. Installers Folder

The "Installers" folder is used to contain and define the installer(s) for your software solution, if the business project requires this. These projects include Visual Studio "Setup Project", "Merge Module Project", "CAB Project", "Web Setup Project", "Setup Wizard", and "Smart Device CAB Project" project types as well as other project types used for this purpose (such as WiX, or Windows Installer XML, project types).

IV. Libraries Folder

The "Libraries" folder contains your solution’s Visual Studio Class Library projects (and related project types, such as Windows Control Library, Web Control Library, WCF Service Library and Windows Workflow Library projects). This folder and its contents comprise the majority of your application’s functionality and this folder typically contains the largest number of individual projects in your solution.

Any Visual Studio projects defined in the "Libraries" folder are not themselves deployable, but rather expose functionality and services that are consumed by other libraries or by projects in the "Hosts" folder. For example, there would be little value in deploying the Application Blocks, in and of themselves, to a server in any environment without a host (such as your application) that exercises their functionality.

V. Tests Folder

The "Tests" folder contains your solution’s Visual Studio Test Projects along with unit and integration tests. These projects are libraries, but are treated differently because they are typically not deployed and not subject to the same analytics (Code Analysis, Code Coverage and Performance Profiling) as other project types in your solution.

Testing guidance is outside the scope of this document, but we strongly suggest that you differentiate the test projects in this folder as containing either unit tests or integration tests by suffixing the project name with ‘.Tests’ and ‘.Integration’, respectively. These terms are defined as follows:

Unit Tests – Programmer-defined tests that exercise the functionality of a class or method in isolation. Unit tests require only the code under test, the runtime and framework on which it depends, and a test harness. Specifically, unit tests do not require any other products to be installed or available (such as databases, performance counters, event logs, or external services), or any type of network access.

Integration Tests – Programmer-defined tests that exercise the functionality of a collaborative group of classes or components. Integration tests may require the additional setup and use of external services and software in order to function.

As an example of the differences between these types of tests, let us assume we wish to test a method that writes a row to the database. The method’s signature is as follows:

C#
internal int AddCustomer(DbCommand command, string firstName, string lastName);

The unit test project would define a MockDbCommand to pass in place of the DbCommand and used to test various scenarios.

The first set of unit tests would make sure that this method throws the appropriate ArgumentNullException if any of the parameters were specified as null.

The second set of unit tests would make sure that the appropriate DbCommand.ExecuteNonQuery(); command was called inside the method and that it is populated with the appropriate DbParameter objects filled in with the values of firstName and lastName.

The next set of unit tests would determine whether the appropriate action was taken in the face of various possible errors that can occur during the call to DbCommand.ExecuteNonQuery(); by simulating various error conditions such as DbException (encompassing SqlException, OleDbException, and OracleException), IOException, and others.

The final set of unit tests would determine that the return value from this method represented the correct value (in this case, let’s say that it is supposed to be the new Customer ID, and not the number of rows affected). Our MockDbCommand.ExecuteNonQuery(); method will return the value of 1 (as the number of rows affected), but we add an output DbParameter to our MockDbCommand named "@CustomerID" with the value of 5. With the test, we verify that the return value from the method under test (AddCustomer ) is indeed 5.

In contrast, the integration tests for this method would pass a real SqlCommand to this method initialized with a real connection to a real database.

The first integration test would pass a valid firstName and lastName to the method, and then read the row in the database indicated by the return value to ensure that the row was added successfully (e.g., "

SELECT FirstName,
LastName FROM Customers WHERE CustomerID = @CustomerI
D"). This verifies the success scenario. Notice that this verifies the expected interaction of the AddCustomer method along with SqlCommand, SqlConnection, SqlParameter, and any other objects in the chain, right down to the database server itself and the network required to communicate with it.

The next set of integration tests would verify the expected behavior of various failure scenarios (for example, by modifying the SqlCommand’s Connection property to point to an invalid or non-existent database, or attempting to add the same customer twice and causing a unique key violation).

Both types of tests are required to fully specify the expected behavior of the system under test.

VI. Visual Studio Project Layout

One or more Visual Studio project folders will exist in each of the folders described above; one folder per project. Do not nest these internal project folders. If additional organization is required, use the ‘Solution Folders’ feature in the Visual Studio Solution Explorer to represent this additional organizational structure. Solution Folders do not map physically to folders on your hard drive or in version control, and simply exist as a convenient organizational mechanism within a Visual Studio solution. We do recommend that you mimic the physical layout described above using Solution Folders, but you may add to this as you see fit.

To illustrate, let’s examine a claims processing pipeline software solution as a scenario. This hypothetical solution incorporates a Windows thick client for paper-based claims entry, Web Services for providers to submit claims electronically along with a Web application for manual entry, as well as a Web application used internally to provide statistical management information, a Mobile web application used to provide alerts and notifications to Blackberry devices for application health monitoring, and Windows and Web services to provide back-end processing and batch processing capabilities.

Such a system might have the following projects and structure. Note that this solution represents a fairly complex set of applications, and additional *.sln files would likely be present in the "Src" folder that reference only those projects necessary for the current development effort in order to provide a more focused view.

11. Windows MAX_PATH Limitations and Team Build

The Windows® operating systems have historically (through Vista™, at least) had a limit on the number of characters that can be represented in any file system path. This limit, set at 260 characters, is generally well within reason, but as folders and files may themselves have long, descriptive names, you may run into this limitation, especially during build scenarios.

The version control provider itself does not have these same limitations, so it is quite possible to have deeply nested folders under version control, each with long, descriptive names. This would result in items in source control that cannot be checked out to a local machine in the same structure and is a situation to be avoided.

Team Build also uses the concept of a ‘Build Type’ to define various build options and solutions to be built together. By default, when the build server checks out items to be built, it will follow the same structure that is used in source control (starting at the Team Project root), but the root of the check out will be ‘F:\MyBuilds\[Team Project Name]\[Build Type Name]\Sources\’ (where [Team Project Name] and [Build Type Name] corresponds to your Team Project and Build Type names, respectively). This has the effect of appending 22 + Team Project Name length + Build Type Name length characters to the version control URI length, and limiting useful paths to well under 238 characters. For example, the Enterprise Architecture group defines a build type of AB (Application Blocks), limiting the maximum useful path of any item in version control to under 212 characters. Longer Team Project and Build Type names only exacerbate this problem.

These issues and limitations are mentioned just to raise awareness. Individual projects within a Visual Studio solution have in the past been created with descriptive names such as ApplicationBlocks.UIPPersistence and/or Microsoft.Practices.EnterpriseLibrary.Configuration; creating both a folder and file (*.csproj) of that name, making these paths correspond to ApplicationBlocks.UIPPersistence\ ApplicationBlocks.UIPPersistence.csproj and Microsoft.Practices.EnterpriseLibrary.Configuration\Microsoft.Practices.EnterpriseLibrary.Configuration.csproj, respectively. It may be prudent to create the project with a shortened name (such as UIPPersistence and Common.Configuration for the examples above), and then rename the project and set the root namespace and assembly name properties explicitly.

12. Scenarios

I. Scenario #1 – New Project or Technology Migration

Your team has just landed a new project (or is converting a VB6/ASP/COM application) and a home for development needs to be created in version control. The project’s name is Medical Records Request Tracking and, for brevity, is known among the team as simply MRRTracking. The first planned release of this application is the 8.2 release (Feb. 2008). Your Team Project name in TFS is ‘Provider Services’.

Using your version control tools, you would add a new project folder named ‘MRRTracking’ to the $/Provider Services/branches URI to make the $/ProviderServices/branches/MRRTracking URI. To that folder, you would add your release folder named ‘v8.2’ to make the $/ProviderServices/branches/MRRTracking/v8.2 URI.

At this point, commit your changes with the comment ‘Created Medical Records Request Tracking project and release folder’. This notifies any subscribers what these folders are for and the project they will contain and will serve as a reminder for anyone viewing the history of this project. Notice that the abbreviated form ‘MRRTracking’ was not used in the comment.

Now that the release folder has been created, go ahead and add the Doc and Lib folders and place within the Doc folder a simple text file named ‘Glossary.txt’ containing the following line:

MRRTracking = Medical Record Request Tracking

This can serve as the project glossary and should be the first place new contractors, developers, and reviewers look when they’re unfamiliar with a term. Understand that this code will be looked at by someone who is not familiar with your project (reviewers, at the very least), and in the case of off-shore contractors, may even be developed by someone who is unfamiliar with culture and terminology in general or the project itself may be handed to a different team entirely. The acronym CIM will mean Common Information Model to developers familiar with Windows Management Instrumentation (WMI), it will mean Corporate Information Management to others. Distinctions like this must be made in an easily accessible location available to all team members. It makes sense to streamline communications with seasoned team members who were ‘in on the joke’, but corporate and team jargon is nothing short of gobbledygook to others. Providing the means for self-help in making sense of it is an extremely valuable productivity gain that prevents miscommunication and constant interruption of other team members.

The following URI’s should now be in an ‘added’ state (not yet committed):

$/Provider Services/branches/MRRTracking/v8.2/Doc
$/Provider Services/branches/MRRTracking/v8.2/Doc/Glossary.txt
$/Provider Services/branches/MRRTracking/v8.2/Lib

Commit your changes with the comment ‘Added project glossary and Lib’ or, for a ‘cleaner’ commit, commit only the folder changes with the comment ‘Added Doc and Lib folders’ and then the addition of Glossary.txt (still a pending ‘add’) with the comment ‘Added project glossary’.

Next, in the release folder, create a new, blank solution named ‘Src’ in Visual Studio (this will create the ‘Src’ directory) and immediately rename the solution. You may use either MedicalRecordRequestTracking or MRRTracking for the solution name; whatever will be understood more clearly, first considering new developers and contractors who may be brought into the project at some future date, and then considering those who will be viewing it on a daily basis. These considerations are prioritized because you will likely want to get any new staff up to speed quickly, rather than spending hours or days ‘giving them the tour’ or worse, giving them no information at all.

After renaming the solution, you may add any of the Solution Folders you may need for this project. Keep in mind that Solution Folders do not map to physical folders; you will still need to add the appropriate solution structure folders described earlier as you add projects into those folders.

Add/commit the initialized solution to version control with the comment ‘Created initial project structure’. Such a solution may have the following URI’s (many are not shown, such as the individual *.csproj files and AssemblyInfo.cs files and Properties folders):

$/ProviderServices/branches/MRRTracking/v8.2/Src
$/ProviderServices/branches/MRRTracking/v8.2/Src/MedicalRecordsRequestTracking.sln
$/ProviderServices/branches/MRRTracking/v8.2/Src/Hosts/Web
$/ProviderServices/branches/MRRTracking/v8.2/Src/Libraries/Controllers
$/ProviderServices/branches/MRRTracking/v8.2/Src/Libraries/ClientServices
$/ProviderServices/branches/MRRTracking/v8.2/Src/Libraries/Common
$/ProviderServices/branches/MRRTracking/v8.2/Src/Libraries/Core

II. Scenario #2 – Existing Project, Migration to TFS

Your team has an existing project in one of server environments or a thick client application in the hands of users or testers. The source for this application is currently in VSS and you want to move it to TFS. The existing application in the ‘public view’ (testers, end-users) is the 1.0 release, but work has already begun on the 2.0 release. You have been following the prior EA guidelines and created a ‘Branch’ in VSS for these releases, but the 2.0 release has had a few critical bug-fixes applied and off-cycle turns. The project name is Turn Center Wizard, but people on the team call it TCW. Your Team Project name in TFS is ‘Enterprise Architecture’.

First, inform your team that you will be moving the 2.0 release to TFS and have everyone get to a point where they can check in their changes and the project will compile. Additionally, ensure that everyone who will be working on the project has the appropriate Team Foundation Server tools installed.

Delete any existing 2.0 release directory from your hard drive and perform a "Get Latest…" action on this branch from VSS.

Open the 2.0 release (still bound to VSS), and first make sure that it compiles. If it doesn’t, then make any changes that are necessary while it is still bound to VSS until you can get a good build. After checking in all changes made, contact your VSS administrator (typically the EA team) to set all access on the project to ‘read-only’ and undo any remaining checked out files. This step will prevent any changes from being made to the project in VSS until and after it is migrated. After the VSS administrator has completed this task, perform another "Get Latest…" action (just in case anyone else made edits before the project was set to read-only), and re-verify that you have a good build.

The final act before closing this solution and saying good-bye to VSS is to unbind the solution from VSS. Use the "File|Source Control >|Change Source Control…" menu option to open the "Change Source Control" dialog and "Unbind" each project and the solution. Close the open solution, saving any changes, and set your Source Control plug-in to Team Foundation Server.

Using your version control tools, add a new project folder named ‘Turn Center Wizard’ to the $/Enterprise Architecture/branches URI to make the $/EnterpriseArchitecture/branches/Turn Center Wizard URI. To that folder, you would add the release folder named ‘v2.0’ to make the $/EnterpriseArchitecture/branches/Turn Center Wizard/v2.0 URI.

Next, create the ‘new’ project structure folders (Doc, Lib, Src) to get the following URI’s:

$/Enterprise Architecture/branches/Turn Center Wizard/v2.0/Doc
$/Enterprise Architecture/branches/Turn Center Wizard/v2.0/Lib
$/Enterprise Architecture/branches/Turn Center Wizard/v2.0/Src

All of the folders created so far are still in a pending ‘added’ state, but are present in your working copy. Copy the solution and project folders from your 2.0 VSS working folder into your Src folder in the TFS working copy.

Next, create the solution structure folders in your Src directory and drag or move each project folder into its corresponding solution structure folder (e.g., *.exe and Web applications into "Hosts", libraries into "Libraries", any "TestCases" projects into "Tests", etc.).

Use Notepad or some other plain-text editor to open the solution file itself and correct the location where it will look for each of the project files.

Save your changes and then open the solution to verify that it can find each of the projects. Do not attempt to build at this time. When all of the projects are represented (and loaded) in Solution Explorer, right-click on the solution and choose the menu option "Add Solution to Source Control…" This registers the solution file and project structure as pending ‘adds’ with the version control provider.

If you open the ‘References’ node of any given project, you will probably see a number of broken references. These are the external binary references used by your project that should be placed in the "Lib" directory.

Copy each external reference and its dependencies into the "Lib" folder, and update each project to retrieve the appropriate reference from that folder.

You may also wish to place the VBScript file below into your "Lib" folder and modify any Web Application, AJAX Web Application, and Web Service Projects to execute it prior to building the project. This will ensure that the appropriate IIS directories and virtual directories are created for the project and pointed to your project’s root folder. This script belongs in the "Lib" folder because it is an external file reference (albeit a build reference, and not a project reference), and it is not part of your solution’s source code.

The necessary projects can be updated by right-clicking on the project and choosing the ‘Unload Project’ context menu item. After the project is grayed out (unloaded), then right-click on the unloaded project and choose the ‘Edit …’ context menu item.

This will show the actual MSBuild project file used for the project. Toward the bottom of the file you will see an area that has been commented out (shown below).

XML
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

Other similar extension points exist, see Microsoft.Common.targets.

XML
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->

Uncomment this section and replace the BeforeBuild target with the following (beware line breaks in the Exec command…there are none in this file fragment):

XML
<Target Name="BeforeBuild" DependsOnTargets="GetFrameworkPaths">
<Exec Command="cscript.exe &quot;..\..\..\Lib\EnsureIISVDir.vbs&quot; "$(MSBuildProjectFullPath)" "$(FrameworkDir)" />
</Target>

No matter where the project is located on your hard drive or what IIS virtual directory you use, you can now build and run it within IIS. The above script also sets the Framework version in IIS to the current version being used by Visual Studio.

Now, you just need to build your project to verify that all required assemblies and scripts have been placed in the Lib folder. Correct any errors that may occur, and then commit the whole project with the comment "Migration of Turn Center Wizard from VSS".

III. Scenario #3 – Clean First Release

Your team manages the Medical Records Request Tracking project, known among team members as MRRTracking. You are the Build Engineer for that project, and your Team Project name in TFS is ‘Provider Services’. It’s mid-February, 2008, and the project’s requirements have been met for the 8.2 release and the code review came back clean on Changeset 738. All developers on the project have their code checked in and are over at TGIFriday’s having beers and congratulating each other on a job well done. You only need to complete this one final task before you can join them.

The project itself is new and has never been released before, so no directory exists for it in the /trunk. This is the 8.2 release, and the next release is scheduled for 8.4.

Using your version control tools, navigate to the current development folder $/ProviderServices/branches/MRRTracking/v8.2 and perform a branch operation. The UI for your version control provider will ask which Changeset you want to branch (defaulting to the most recent) and where you want to branch it to.

Explicitly set the Changeset to 738, as the version that was reviewed, and set the target branch to $/ProviderServices/trunk/MRRTracking/v8.2. If you have the opportunity to switch to or create a local working copy out of the target branch, then set that option and execute the branching operation.

A copy of the software solution as it existed in Changeset 738 will be created on your hard drive and in version control at the target branch URI. Open the solution in the $/ProviderServices/trunk/MRRTracking/v8.2/Src folder and verify that it compiles. (If it doesn’t, delete the branch and call some of those developers back into the office to fix their code.)

Commit the branch to version control with the comment ‘Initial 8.2 release of Medical Records Request Tracking’.

Next, select the release folder at $/ProviderServices/trunk/MRRTracking/v8.2 and perform another branch operation. Again, the UI will ask which Changeset you want to branch (defaulting to the most recent) and where you want to branch it to.

This time, leave the default Changeset (latest version), and set the target branch to $/ProviderServices/branches/MRRTracking/v8.4. If you do not need to work on this branch, then do not set the option to switch to or create a local working copy of it. Now execute the branching operation.

A copy of the 8.2 release will be created in version control at $/ProviderServices/branches/MRRTracking/v8.4.

Commit the newly created branch with the comment ‘Initialized 8.4 development from r738’ and blast out an e-mail to the entire team informing them that all 8.4 functionality should be developed in this branch and only bug-fixes should be worked on in the 8.2 branch.

If you have an automated build system in place, instruct the build system to build and tag the solution in the $/ProviderServices/trunk/MRRTracking/v8.2/Src folder (and optionally, if it also performs the deployment, where to deploy each Hosts project it finds). If this is the case, then you’re done, and can head over to TGIFriday’s and join the team. If not, then continue reading for the manual steps.

IV. Scenario #4 – Dirty First Release

Your team manages the Medical Records Request Tracking project, known among team members as MRRTracking. You are the Build Engineer for that project, and your Team Project name in TFS is ‘Provider Services’. It’s mid-February, and the project’s requirements have been met for the 8.2 release and the code review came back clean on Changeset 738. The developers have noticed and have been busy fixing a few bugs that they found after the code review and refactoring some of the code that they still want to get into the 8.2 release...no work has started on the 8.4 release and no branch yet exists for it. The latest Changeset is 813 and this is the version you have been instructed to release. All changes have been committed by all team members.

The project itself is new and has never been released before, so no directory exists for it in the /trunk.

Using your version control tools, navigate to the current development folder $/ProviderServices/branches/MRRTracking/v8.2 and perform a branch operation. The UI for your version control provider will ask which Changeset you want to branch (defaulting to the most recent) and where you want to branch it to.

Explicitly set the Changeset to 813, and set the target branch to $/ProviderServices/trunk/MRRTracking/v8.2. If you have the opportunity to switch to or create a local working copy out of the target branch, then set that option and execute the branching operation.

A copy of the software solution as it existed in Changeset 813 will be created on your hard drive and in version control at the target branch URI. Open the solution in the $/ProviderServices/trunk/MRRTracking/v8.2/Src folder and verify that it compiles. If it does not, then delete the branch and have the developers fix their code.

Commit the branch to version control with the comment ‘Initial 8.2 release of Medical Records Request Tracking – Reviewed at r738’. This indicates to any onlookers that the code being released is not necessarily the code that was reviewed (this will also CYA when auditors ask why the EA team reviewed 738 and you released 813).

Next, select the release folder at $/ProviderServices/trunk/MRRTracking/v8.2 and perform another branch operation. Again, the UI will ask which Changeset you want to branch (defaulting to the most recent) and where you want to branch it to.

This time, leave the default Changeset (latest version), and set the target branch to $/ProviderServices/branches/MRRTracking/v8.4. If you do not need to work on this branch, then do not set the option to switch to or create a local working copy of it. Now execute the branching operation.

A copy of the 8.2 release will be created in version control at $/ProviderServices/branches/MRRTracking/v8.4.

Commit the newly created branch with the comment ‘Initializing 8.4 development from r813‘ and blast out an e-mail to the entire team informing them that all 8.4 functionality should be developed in this branch and only bug-fixes should be worked on in the 8.2 branch.

If you have an automated build system in place, instruct the build system to build and tag the solution in the $/ProviderServices/trunk/MRRTracking/v8.2/Src folder (and optionally, if it also performs the deployment, where to deploy each Hosts project it finds).

V. Scenario #5 – Truly Dirty First Release

Your team manages the Medical Records Request Tracking project, known among team members as MRRTracking. You are the Build Engineer for that project, and your Team Project name in TFS is ‘Provider Services’. It’s mid-February, 2008, and the project’s requirements have been met for the 8.2 release and the code review came back clean on Changeset 738. The developers have noticed and have been busy fixing a few bugs that they found after the code review and refactoring some of the code that they still want to get into the 8.2 release. Some developers have even begun implementing 8.4 features and have committed changes for that release in the 8.2 folders. The latest Changeset is 906. All changes have been committed by all team members.

The project itself is new and has never been released before, so no directory exists for it in the /trunk.

Using your version control tools, navigate to the current development folder $/ProviderServices/branches/MRRTracking/v8.2 and perform a branch operation. The UI for your version control provider will ask which Changeset you want to branch (defaulting to the most recent) and where you want to branch it to.

Explicitly set the Changeset to 738, as the most recently reviewed, and set the target branch to $/ProviderServices/trunk/MRRTracking/v8.2. If you have the opportunity to switch to or create a local working copy out of the target branch, then set that option and execute the branching operation.

A copy of the software solution as it existed in Changeset 738 will be created on your hard drive and in version control at the target branch URI. Open the solution in the $/ProviderServices/trunk/MRRTracking/v8.2/Src folder and verify that it compiles. If it does not, then delete the branch and have the developers fix their code, as well as have it resubmitted for review in the hopes of a clean first release.

Commit the branch to version control with the comment ‘Preparing 8.2 release of Medical Records Request Tracking – Reviewed at r738’. This indicates to any onlookers that the code being released is not necessarily the code that was reviewed.

Next, select the development folder at $/ProviderServices/branches/MRRTracking/v8.2 and perform a ‘Merge…’ operation. The UI for your version control provider will ask for the source and target branches of the merge and whether you want to merge all changes or only selected changes. At this point, select the option to merge only selected changes, and set the target of the merge to your $/ProviderServices/trunk/MRRTracking/v8.2 release folder.

The merge UI will show you all of the changes that have taken place on the project since the branched version (738). At this point, you can cherry-pick the changes that need to be in the 8.2 release. See the screenshot below for an example of this UI. Note the value of good comments and the value of clean commits in making your decision (what should be in the 8.2 release vs. what should be in the 8.4 release).

Once you have selected the Changeset(s) to merge, execute the merge. This will update the files in your local working copy with the specified changes. Open the solution at the target branch, verify that it builds correctly, and then commit the changes with the comment ‘Merged changes r###-r###), where ### are the starting and ending Changesets being merged.

Repeat the merge process from your 8.2 development folder to your 8.2 release folder in the /trunk for any non-contiguous set of changes that need to be in the 8.2 release.

Once you are satisfied that the 8.2 release is ready and all changes specific to it have been incorporated (while excluding any changes specific to 8.4), take note of the changeset number (let’s say that it is 916 at this point) and select the release folder at $/ProviderServices/trunk/MRRTracking/v8.2 and perform another branch operation. Again, the UI will ask which Changeset you want to branch (defaulting to the most recent) and where you want to branch it to.

This time, leave the default Changeset (latest version, 916), and set the target branch to $/ProviderServices/branches/MRRTracking/v8.4. This time, do set the option to switch to or create a local working copy of the new branch and execute the branching operation.

A copy of the ‘real’ 8.2 release will be created in version control at $/ProviderServices/branches/MRRTracking/v8.4.

Commit the newly created branch with the comment ‘Initializing 8.4 development from r916‘ and blast out an e-mail to the entire team informing them that all 8.4 functionality should be developed in this branch and only bug-fixes should be worked on in the 8.2 branch.

At this point, the 8.2 development branch still contains changes that are specific to 8.4, so we need to get them merged into the 8.4 development branch and revert the existing 8.2 development branch to match what is currently in the /trunk.

Select the development branch at $/ProviderServices/branches/MRRTracking/v8.2 and perform another ‘Merge…’ operation. This time, the target of the merge is $/ProviderServices/branches/MRRTracking/v8.4, but we still want to select specific changesets to merge.

Because TFS tracks merges, the UI should show you only those changes that were not previously merged into the 8.2 release. Select all of the relevant changesets and execute the merge.

This will update the files in your local working copy of the 8.4 development branch with the changes made in 8.2 that were specific to 8.4. Commit the changes with the comment ‘Merged r###,r###-r###,r###’, where ### is the changeset number of each changeset, or starting and ending changeset numbers of contiguous changesets, that were included in the merge.

Now that the 8.2 release folder in /trunk contains what it should, and the 8.4 development folder in /branches contains what it should, we can set the 8.2 development folder in /branches to match the release.

In a good version control system, you can’t "Undo", but you can always overwrite. We will use that fact to undo the changes made in 8.2 that were specific to 8.4.

Select the 8.2 release folder at $/ProviderServices/trunk/MRRTracking/v8.2 and perform yet another ‘Merge…’ operation. Set the target of the merge to be the $/ProviderServices/branches/MRRTracking/v8.2 development folder, then select all changes and execute the merge.

After the merge operation completes, the 8.2 development folder now matches, directory for directory, file for file, line for line, the content in the 8.2 release folder, effectively undoing those changes that were specific to 8.4. Commit these changes with the comment ‘Merged from r916 to undo 8.4-specific changes’.

If you have an automated build system in place, instruct the build system to build and tag the solution in the $/ProviderServices/trunk/MRRTracking/v8.2/Src folder (and optionally, if it also performs the deployment, where to deploy each Hosts project it finds).

VI. Scenario #5 – Initial Development

Your team manages the Medical Records Request Tracking project, known among team members as MRRTracking. You are a developer on that project, and your Team Project name in TFS is ‘Provider Services’. The project has been defined in version control at $/ProviderServices/branches/MRRTracking/v8.2 and the solution has been created in the corresponding "Src" folder.

In order to work on this project, you will first need to obtain a copy of it from the server. Using your source control tools, navigate to the $/ProviderServices/branches/MRRTracking/v8.2 development folder and check out the project from TFS by performing a ‘Get Latest’ action.

This will create your local working copy of the project’s sources and dependencies at some location on your hard drive. You may now open the solution file either from Windows Explorer or from within Source Explorer. Continue reading the Day to day Development scenario for additional tasks.

VII. Scenario #6 – Day to day Development

Your team manages the Medical Record Request Tracking project, known among team members as MRRTracking. You are a developer on that project, and your Team Project name in TFS is ‘Provider Services’. The project has been defined in version control at $/ProviderServices/branches/MRRTracking/v8.2 and the solution has been created in the corresponding "Src" folder. You already have a local working copy of the project and you need to make some changes or implement new functionality. You currently have no uncommitted changes in your working copy.

Using your source control tools, update your local sources with any changes that may be present on the server ("Get Latest" in TFS), and then open the solution either from Windows Explorer, the IDE’s Most Recently Used list, or the Source Explorer.

The very first action that should be taken after opening the solution with a recent source update is to perform a local build. This action guarantees that you will be aware of the project’s current state and not waste time adding functionality or features to a non-functional project. The local build, or compilation step, serves as your ‘smoke test’ (a term borrowed from the electrical engineering discipline, where a component is ‘tested’ by plugging it in…if it starts to smoke, then something is obviously wrong, if not, then it may not work, but nothing is obviously broken).

If the project does not compile, contact the most recent contributor to the project. You can find this information and the name or e-mail address of the person you need to contact by viewing the history for the branch using your source control tools. You may see output similar to the following screenshot:

Given the user ID in the user column, you can determine which user made the change by running the following command (replacing sxd7278 with the user ID of interest):

Once you know who the most recent contributor is, call or send them a message asking them if they have completed their commits and informing them that the project does not compile. This may simply be a situation where the other contributor is in the middle of a multi-step task and has not yet committed all parts of the task, or it may be that the contributor unwittingly introduced a dependency that is only available on their machine.

If the contributor is reachable, then work through any issues with them until the project is stable and perform another update of your sources and build.

In many cases, it may not be possible to reach out to the contributor immediately. To name only a few reasons; time of day, time zone differences, meetings, transfers and terminations can all affect the availability of the most recent contributor. In these cases, instead of stopping your work, you must get the most recent functional version of the project before making your changes.

13. Additional Material

Please read the following material for additional sources and justifications for the guidance presented in this document. Software Configuration Management (General)

I. Team Foundation Server

II. Microsoft Visual SourceSafe

III. Project Folder Structure (General)

[1] "Lib" folders commonly contain subfolders that correspond to particular third-party vendors, such as Infragistics, Oracle, Log4Net, etc. This sub-structure makes it simpler to update each individual vendor’s library set when new versions are acquired.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)