In today’s modern development environment where clients are demanding higher quality products in shorter timeframes it is imperative that organizations find ways to deliver higher quality products in a shorter time period. An area in development that has traditionally taken a long time to complete is integration. In the past integration has always been a difficult time when two parties are trying to get their code to talk to each other. To help solve this challenging issue the industry has come up with some tools and techniques to make integration a relatively painless issue. Some of these techniques are as follows:
- Continuous Integration
- Dependency Replication
- Automated Unit Testing and Code Coverage
- Automated Deployment
- Build Verification Tests
- Deployment Verification Tests
In this post I explain how to setup up some of these concepts using Team Foundation Server as the backbone.
Explanation of Key Concepts
Continuous Integration is the concept of monitoring a section source code control repository for changes and once they have been detected starting off a build. Pictorially a continuous integration looks like:
For modern development projects the CI build becomes its heartbeat. If the build is broken then there is something wrong with the project and it should be the first the first priority of all developers to ensure that the build is fixed. A continually broken build is a sign of a development team that is heading towards chaos. Normally, as part of a CI build you would also run automated unit tests to verify the build .
Dependency Replication is the ability to automatically copy (replicate) one or more outputs (dependency) of a successful build of one project to all of the other projects that utilize that output. This ensure that all projects that require on that component automatically have the latest version of that particular component. Pictorially dependency replication looks like:
Automated Unit Testing
Unit testing is a procedure used to validate a particular module of source code is working properly from one modification to the next. Automated unit testing take this process one step further and requires that the unit test are developed in a way in which they can be run by a build process. When combined with a continuous integration build, automated unit test help identify where or not a particular check in by a developer has caused other parts of the system to break.
Code coverage is a mechanism that can be used to understand how much of the source code has been test. It is normally measure in a percentage of the source code exercised with a higher number being better. Code coverage is a useful tool to inform how much code has been exercised by a suite of unit tests. However, by itself it doesn’t provided any information on whether or not the program does what it is specified to do. It should also be noted that 100% code coverage does not mean that all possible scenarios have been tested.
Automatic deployment is the process of releasing software without human intervention based on some event. With TFS the trigger that cause the automatic deployment is the changing of the build quality. Normally as part of the automatic release you would run your build verification and deployment verification tests. . Pictorially dependency replication looks like:
Build and Deployment Verification Tests
Build and deployment verification tests are similar types of tests. Firstly, build verification tests are a suite of automated tests that are run after you have successfully deployed and application into a test environment to validate the stability and quality of a build. They are different to unit tests in that they are typically long running functional tests that is testing an application from a holistic point of view rather than just at a component or unit level. Deployment Verification tests are similar to build verification tests except they are design to verify that the application and all of its required components have been correctly installed. They are also useful when troubleshooting issues such as communication failures and incorrect configuration settings.
Overview of Current situation
Currently we have already implemented Continuous Integration, Dependency Replication, Automated Unit Tests, Code Coverage and automatic deployment. To help achieve this things the following technologies the following components:
- Visual Studio 2005 Team Suite for Automated Unit Test and Code Coverage.
- Team Foundation Server for Source Code Control, Work Item Tracking and Team Build
- TFS Integrator for Continuous Integration and Dependency Replication (Third Party Add On)
- TFS Deployer for Automated Deployment. (Third Party Add On)
At a high level the current build and release process looks like:
Development Environment Setup
The development environment has been arranged in the following manner:
Source code Organisation
Within Team Foundation Server, there is a concept called a Team Project. A Team Project allows a project team to group everything related to a project under a single umbrella. Underneath a team project the source code can be arranged however a team likes. However, it is recommended to keep the structure of your source code repository quite flat. For example:
The reason that I separate setup projects from the source code is to ensure that only files that should be released can be included into the setup project also as I normally use WIX as my setup project they require modification of the team build project. For reference, the TeamBuildTypes directory is an inbuilt directory that is maintained by TFS and is where all of the Team Build project files are stored.
Continuous Integration Configuration
Normally I setup one Continuous Integration Team Build Type per solution. Using the above source tree as an example, I would create the following CI Team Build Types
|Solution1Continuous||CI team build type for Solution1. Each time a file is checked into the path $/TeamProject/Solution1 this build is started. All of the Unit tests for Solution1 are run as part of this build.|
|Solution1Setup||CI build project for the Setup Program for Solution1. $/TeamProject/Solution1Setup this build is started.|
One of the other critical components when designing a source code control structure is how to manage project dependencies. To ensure that a solution is independent and can built it is own right it is important to stored all of the solutions dependent dll’s etc together with the solution.
The way that I normally achieve this is to introduce another folder called Dependencies under each of the solution directories. Into that folder all dll’s and other files that the solution is dependent upon are placed:
From a source code tree point of view it looks like:
I then normal use the dependency replication of TFS Integrator to manage the dependencies between solutions in the same team project.
Another useful thing that I normally draw out is a diagram depicting the dependency tree for a team project for example:
This allows you to very quickly and easily to view what your applications dependencies are. As an aside, one of the nice to have features for TFS Integrator that I have been thinking about is a front end that allows you to view the dependencies based on the information defined in the dependencyreplication.xml file.
From the point of view of TFS Integrator the dependencies are managed as follows:
For details on what is replicated look at the DependencyReplication.xml file in the C:\Program Files\TfsIntegrator directory on the server where TFSIntegrator is running.
One of the things that I try and achieve is to always ensure that the CI build process completes in the shortest period of time. Developers love quick feedback. There are always tasks that you are need to package a project up for release, that normally don’t need to be done as part of a CI build. Examples are:
- Backing up the Database
- Creating the Setup Program
- Zipping up all the source code
- Removing unnecessary files
- Creating Release Notes
Normally, what I do is create a project called <TeamProject>NightlyBuild. So that these tasks can be completed easily and in automated manner.
I then normal use a feature in TFS called Build Quality to manage what builds I have released. At a high level my process looks like:
 Build Quality is a feature in TFS which allows you to place against any build the state of that particular build. This allows you to manage where in your application lifecycle at what stage a particular build is at. An example of build quality would be “Ready for Initial Test” to indicate that build is ready for testing or “Released” to indicate that build has been released.