Welcome to MSDN Blogs Sign in | Join | Help

Influencing Executives

Preparing Your Idea

The first real step in preparing a proposal with a greater chance of success is finding a subject you’re passionate about. Even if you present all the data to support your idea, your lack of passion for the subject will give you the disadvantage when asking an executive to take a risk on you and your idea. Once you have that, you need to ensure you’re not duplicating effort occurring elsewhere in the industry or within your own company. Once you’re in the clear on that you must refine your idea to make it crisp.

Executives take risks on people, make it count. Having clearly and concisely articulated your vision, the same must be done for the ROI associated with implementing your vision. Often ideas undertaking major changes are not specifically actionable (or at least cannot be easily explained and understood in 30 seconds), so they must be decomposed. In doing so the constraints of organization budget become less of a factor—individual actionable items can be accomplished in various stages to accomplish the larger vision. Additionally, if you’ve clearly explained the value of your vision, it is understood by the sponsor, and it is the right thing for the company to do, there is a greater chance you will get funding.

Making the Pitch

At this point you should be well prepared for your meeting. Ensure you can clearly articulate your vision in less than 30 seconds (elevator pitch) and remember to bring the passion. Data is optional, passion is not. It also good to note the clear separate between what you like to have and what is needed to be successful.

If in the event your sponsor does not approve your proposal, don’t give up. In the meeting debrief, consider the following questions:

  • Is the vision clear?
  • Is this really the right thing for the company?
  • Has the distinction between what you would like and what you need been clearly made?
  • Is there history of you not delivering results?
  • Is the scope granular enough so it can be accomplished?

Don’t give up. Iterate on your idea and your materials and try again. If your vision is clear and sufficient ROI present, your chances of getting approval are high.

Reporting Status and Delivering Results

Once you have funding it is now important that you deliver regular status updates and deliver. You may find that your executive sponsor wishes to be involved in your project—indulge them. Let them feel your passion and excitement by being involved. However in any circumstance, ensure that when you deliver your status that it is done so clearly and often, typically being less than 1/2 page. It is also important that mistakes made during your project are surfaced quickly and that responsibility and remediation is clearly evident. Surfacing mistakes made can potentially save large amounts of time, effort, and money to other team members or organizations within your company and will be appreciated by your sponsor.

It is also important to think of your project plan, and its artifacts, as results delivered for a “blue chip” company, even if yours is not. Blue chip results are based out of lean project plans, where results are consistent, of high quality, and are widely accepted. Much like companies of the same name, projects executed in this manner can weather changes in economic conditions and build reputations of stability and reliability.

Easy String to Resource file refactoring

During the development of internal tools we often have to stop working on features and clean up after ourselves to ensure that strings and such are embedded in the appropriate resource files and not hard coded into our applications. This can be a very tedious and time consuming process. Luckily there is a refactor extension that makes this very easy.

Resource Refactoring Tool 

Resource Refactoring Tool provides developers an easy way to extract hard coded strings from the code to resource files.

Features for Resource Refactoring Tool

Works with C#, VB.Net languages. Supports all project types that ships with Visual Studio 2005 including web sites and web application projects.

  • A preview window to show changes.
  • Finds other instances of the text being replaced in the project automatically.
  • Lists existing resources by their similarity level to the text being replaced.
  • Automatically replaces hard coded string with a reference to resource entry.

More information at http://www.codeplex.com/ResourceRefactoring

Posted by Richard Murillo | 1 Comments
Filed under: ,

Utilizing memoization and Dijkstra’s Fibonacci algorithm to compute large values

More of an acute fascination than anything else I expanded my use of memoization for computation to use a more efficient means of calculating Fibonacci sequences for values of n greater than 40 (previous Fibonacci example takes several minutes to compute value at 45 and is fairly unusable beyond that). To perform the computing of Fibonacci I utilized Dijkstra's algoritm for graph search pathing (algorithm details can be found in EWD654 "In honor of Fibonacci").

Dijkstra's algorithm for Fibonacci:

D(2n) = (2D(n-1) + D(n))D(n)
D(2n-1) = D(n-1)2 + D(n)2 

This algorithm in C#:

public static Func Dijkstra = n =>
{
if( n < 2 )
return n;

double half = ( n % 2 == 0 ) ? n / 2 : ( n / 2 ) + 1;

double p1 = Dijkstra( half );
double p2 = Dijkstra( half - 1 );
double result = default( double );

if( n % 2 == 0 )
result = ( 2 * p2 + p1 ) * p1;
else
result = Math.Pow( p2, 2 ) + Math.Pow( p1, 2 );

return result;
};

Utilizing the memoization technique the amount of computations performed drops significantly. To compute the value of 50 the following computations are performed:

F(50) = F(25) and F(24)

F(25) and F(24) = F(13) and F(12)

F(13) and F(12) = F(7) and F(6)

F(7) and F(6) = F(4) and F(3); F(3) and F(2)

F(4) and F(3) = F(2) and F(1)

F(3) = F(2) and F(1)

F(2) = F(1) and F(0)

F(1) and F(0) are 1 and 0

Utilizing this technique the number of computations required is 14. At the cost of some space the computations become faster as the graph becomes denser.

Technorati Tags: ,,,,

Significantly speeding up computations with smart predicates

There is a technique that allows optimization of repeated calculation results for a set of inputs called memoization. This technique is particularly helpful when working with numeric computations, pathing, such as for tree searches, etc. where the time taken to traverse the result set is expediential. What's more interesting is that the technique is applied on top of the System.Func object allowing for transparent optimization of those delegate types. Here is the method that I use to perform the optimization.

public static class SystemMemoizationExtension 
{
private static object lockObject = new object();
public static Func Memoize( this Func func )
{
Dictionary t = new Dictionary();
return n =>
{
if( !t.ContainsKey( n ) )
{
lock( lockObject )
{
if( !t.ContainsKey( n ) )
{
var result = func( n );
t.Add( n, result );
}
}
}
return t[ n ];
};
}
}

To utilize the method simply assign the result of the Memoize method back to your delegate as shown in the example below.

Func<int, int> Fibonacci = null; 
//Recursive Fibonacci algorithm
Fibonacci = n >=n <= 1 ? n : Fibonacci(n – 1) + Fibonacci(n-2);
//Optimize lookups
Fibonacci = Fibonacci.Memoize();

While this is an overly simplistic example of recursion optimization you can see that by calling the code once then again using the same input that a dramatic improvement is made performing the computation (an input for F(n) where n = 42 takes several seconds to compute, while the subsequent call takes sub seconds). The technique itself is useful for reducing the traversal time for any top-down parsing.

Technorati Tags:

Extensions I found useful while developing with WPF and LINQ to SQL

 

When I observe developers writing solutions using LINQ to SQL or Entity Framework, I see a number of conversions occurring time and time again. Below are some of the more trivial utility method extensions I used when developing solutions based on LINQ to SQL and WPF—simple as they are I found them useful in a variety of situations.

Extension to remove data from a collection using a predicate.

public static void Remove<T>( this ICollection<T> data, Func<T, bool> predicate )
{
if( predicate == null )
{
data.Clear();
}
else
{
foreach( T item in data.Where( predicate ))
{
data.Remove( item );
}
}
}

 

Converting an enumerable to an ObservableCollection for data binding

public static ObservableCollection<T> ToObservableCollection<T>( this IEnumerable<T> collection ) 
{
List<T> list = new List<T>( collection.Count() );
using( IEnumerator<T> enumerator = collection.GetEnumerator() )
{
while( enumerator.MoveNext() )
{
list.Add( enumerator.Current );
}
}
return new ObservableCollection<T>( list );
}

The same but for a list

public static ObservableCollection<T> ToObservableCollection<T>( this List<T> collection ) 
{
return new ObservableCollection<T>( collection );
}

Software development outsourcing and client proximity

I had a recent comment come in that I wanted to share:

I was wondering what your take was on Consulting firms. Although it is not offshore outsourcing, in some sense, it is still outsourcing their projects to firms. I totally agree with you regarding the lack of communication and planning to execute and deliver projects when attempting to have someone work on a project 2000 miles away from you.

The short of it is there is still risk in outsourcing no matter the proximity, however, I believe that there are three key tenets that facilitate failure in the situation:

  • Spoken and written language comprehension
  • Cultural awareness and differences
  • location, location, location

Communication plays a fundamental role in project success, whether it is with the local project team, virtual team members, or external parties. I believe the biggest challenges we face with traditional overseas outsourcing revolves around this, however I have experienced similar challenges with outsourced work with American vendors for different reasons all together, so there's a project risk either way.

Fundamentally it comes down to a risk management decision for the client. I have found that groups and companies that do not have their own crisp corporate governance, operational and infrastructure policies are more often than not unsuccessful in outsourcing (root cause is uncontrolled chaos undermining communication plans and data management policies). In a vendor/client model there are a few things we have exercised to be successful: emphasis on information security, a clear and well understood communication protocol, and frequent audits to ensure policy compliance. Above all of that there's also the associated business risk of the outsourcing deal that needs to be managed up front. In either "near" or "far" outsourcing, the recognition of a failing deal is pivotal to shifting risk back on to the vendor.

Visual Studio 2008 Released

After months of waiting, I can finally say that Visual Studio 2008 was released last week. There are hundreds of new features, language enhancements, and technology integrations in this version. To help you get your head around what is new in Visual Studio 2008 and .NET Framework 3.5, get the training kit from Microsoft download center.

Some new features that I am excited about:

  • Visual Studio performance improvements
  • AJAX integration with javascript intellisense
  • Cider integration (WPF visualizer)
  • Multi-core builds
  • Windows Server 2008 / SQL Server 2008 support (TFS)
  • Vista UAC compliance
  • Continuous integration
  • Web Access
  • Integration of Database Edition (VSTS SKU)
  • T-SQL Static code analysis
  • SQL Dependency tree visualization
  • Schema reporting for documentation
  • T-SQL refactoring
  • New designers for SOA scenarios
  • Hotpathing (tell me where perf in my application sucks)
  • LINQ

Why moving work offshore fails

Not to say that all offshore projects fail, I have both been a contributor and leader in projects that have been a great success and those that have been complete failures. Each project had its own reasons for failing and were defined by the business (e.g. why are you sending it offshore to begin with) that typically include cost savings, quality, increased turnaround in deliverables, and customer satisfaction--all of which are key drivers for moving work offshore, but in doing so there are key areas your business must pay close attention to.

According to Gartner, businesses will spend more than $50 billion USD on offshore and "near-shore" outsourcing by 2007 and many projects will fail because of poor planning. Gartner also maintains that there are benefits achieved by those businesses that successfully outsource their non-core processes, however, rewards will not be instant.

Reasons for Failure

Often times, the effort and time involved in communicating with offshore team members and maintaining that relationship is underestimated. In my experiences with offshore teams to date, there has often been a lack of key items to complete awarded work effectively (like infrastructure, soft skills, planning). Additionally, coordinating between the teams requires longer hours, detailed planning, and cultural training—all of which are more expensive when working with offshore than with your own staff and can, as I have observed here, lead to lower morale and reduced deliverable output. Gartner also observes that lack of productivity in the offshore is also an issue for several reasons including high staff turnover and skill levels, especially in highly competitive markets such as Bangalore and Hyderabad, India.

Much like the dot com days, new programmers coming into the field of work are inexperienced, attaining only the necessary core skills for them to receive a job in this field and often struggle with ambiguities in specification or shifting directives. As such, the teams typically do not operate with clear processes and depend on the competence and heroics of those more experienced and not on the use of proven processes. In spite of the chaos, these teams often produce usable work products; however, they frequently exceed the budget and schedule. More often than not these teams over commit, abandon any established process in times of chaos, and may not be able to repeat past successes again.

What's more, senior executives are not involved to keep strategy on track and morale high—they are only in the picture when a significant escalation occurs or to sign a new deal. As I mentioned in my previous entry, in order for an offshore deal to succeed there needs to be a good level of communication between all parties. Requirements, goals, and expectations have to be defined clearly and in detail. Your onshore managers need to explain to the coordinating staff why the work has been sent offshore and what benefits are expected.

More often than not, the cultural differences will come into play creating havoc for the project; classic incarnations of this include not questioning authority and just pressing forward by the offshore team. All too many times do we find out late that guidance or requirements had been ignored for cross cutting to please the schedule rather than announcing a slip.

How can Visual Studio Team System help?

Gartner advises companies that plan on offshoring work to figure out their IT process maturity and identify gaps in your process. As previously mentioned, it is important to set all expectations clearly up front with your vendor. When using Visual Studio 2005 with Team Foundation Server, several mechanisms out of box enable teams to work effectively in these environments:

  • Process: out of the box, Visual Studio Team Foundation server includes MSF for CMMI Process Improvement Level 3 and MSF for Agile Development work item templates. By utilizing the templates and the process behind them, teams can effectively work across physical boundaries with increased confidence and transparency, allowing software development activities to be predictable and success repeatable.
  • Communication: Visual Studio Team System facilitates the transparency between individuals and teams with work items, a shared team portal, integrated change management, and a common data repository. The availability of information, and insight into an individual's progress, creates a more unified work environment regardless of physical location. Project managers can stay informed on an individual's progress without having to visit each individual—having real time information about each individual's work and their progress allows project managers to create precise schedules and report more accurately to management
  • Productivity: utilizing the common repository, managers and leads can answer common questions such as: What's in the current build that QA can test today; are requirements being met; are my teams adhereing to quality standards; is the product ready. Further, it provides the single team portal for integrating source code, issue tracking, project plans, vision statements and others that are critical assets to a project team.

Outsourced Projects using Visual Studio Team System

Having been included in two separate teams where our outsourced projects don't go as well as expected I cannot help but to take a step back and ask why things are consistently failing with separate teams, and separate organizations.

The commonalities in both projects were fixed-bid (i.e. fixed price, features and time) using a modified waterfall model (to account for geographic locations). I know—you say the waterfall model doesn't work. Be that as it may organizations revert to this model and are thus handicapped; unable to make adjustments to the changing business and unable to make definitive decisions on how to improve their process, but more on that later. Other commonalities included high level and low level designs, unit test cases, test cases, etc.

I have heard that groups similar to mine are having great success with outsourced projects, and I myself have also been involved with projects that were executed to great success, however I assert that for us there are areas of improvement. At a high level, I can sum it up in one word: process.

Where have my two projects failed? IMHO it is in the analysis of the requirements. The requirements had the vendors pegged implementing features on product technologies they were unfamiliar with—some churn in requirements and with new technology. Traditionally engineering teams would perform proof of concepts and experiments to validate design, and clickable prototypes to share with customers to stabilize requirements (business and technical). While some of that was done here, I still see where it could have been improved. In both instances, we started with a solid vendor relationship that quickly begins to fall apart due to lack of trust. IMHO the biggest areas we are lacking are:

  • Trust between teams
  • High SNR in communication (i.e. direct, candid communications on issues, risk and status)
  • Close coordination between said teams

IMHO in both projects are considered high risk when examining the vendor skill set, staffing model, and experience with projects of this complexity. In most situations you can apply the Parento principle (AKA 80-20 rule) where 80% of staff is offshore while 20% is onsite for R&D phases, moving to a 90-10 planned iterative model for build and less onsite still for stabilization.

In both projects the offshore team encountered additional issues during implementation that require workarounds for resolution, R&D, or a complete shift in approach. On both projects we tried to mitigate risk by having frequent check-ins with the offshore team and checking progress on a tight basis (one was almost daily, the other bi-weekly). Alas when significant and unexpected delays arose the relationship fell to pieces and in response we put in-house staff on the project to sure it up and get it going in the right direction.

Lessons Learned

  • Complete as many iterations as you can: That is, don't disrupt forward progress on the project for the sake of getting a work product from the team, but do get deliverables as often as it makes sense. Some of our projects get some weekly, others monthly.
  • Use collaborative tools to increase confidence in deliverables: Your in-house staff does not have to wait until the end of the formal delivery cycle to perform review or check in with the offshore team. Utilize tools like LiveMeeting Net Meeting, Windows Live Messenger, etc. to increase collaboration
  • Code review, code review, code review: DO NOT UNDERESTIMATE THIS. A majority of issues we found on one project were found in code review by in-house staff familiar with the business rules. In both projects the adherence to offshore code reviews prior to sending to our in-house staff was not maintained, resulting in many bugs raised later in the cycles. In the reviews we took code that was a representative sample (chosen at random, but was a deep slice) and did a review. Additionally we looked at key strategic areas for performance bottlenecks and security to ensure code conventions, standards, and requirements were being met
  • Integrate as frequently as possible: Our teams use branches to logically separate the project or feature into areas for work. As a matter of practice, the more frequently these branches can be integrated the faster you can identify and resolve defects.
  • Where possible, leverage frameworks: Use application blocks (Enterprise Library), Guidance Automation (Web Client Software Factory, Smart Client Software Factory) to solve common problems. Where possible, create your own frameworks and reuse them on projects to reduce the amount of custom code required to be written, which decreases development time and improves quality.
  • Use Design Patterns: These patterns illustrate common ways to solve problems. Being standard, they can convey meaning across geographical boundaries. Further, by implementing patterns maintenance complexity is reduced and documentation and clarity is improved. A different vendor in a different country, maybe even in-house staff, may need to understand and modify the code—using a proven design allows ramp up to easily occur.
  • Use useful metrics to measure quality and progress: Build metrics into SLAs and look at meaningful metrics, such as defect density, bug reactivations, code churn, code coverage (unit test or otherwise), project velocity, etc.

Leveraging Visual Studio Team System

I have found that VSTS handles the needs of geographically dispersed development teams (and their inherent challenges) in a variety of ways:

  • "Better" communication and coordination: Team Foundation Server provides the ability to track work items (tasks, bugs, issues, requirements, risks, change requests) in addition to source code and documentation. The architecture, utilizing web services and cache servers, is optimized for distributed teams working over slow or unreliable connections. The product also allows for customizable notification of events to give you the clarity you need from the projects and help improve onsite/offshore communications
  • "Better" status reports: Coupled with the data warehouse maintaining statistics and work item history, reports can be generated to give you insight in to some of the metrics I mentioned above. The platform is also extensible, utilizing SQL Analysis Services (SSAS) and SQL Server Reporting Services (SSRS) to allow team members to gather information with various levels of granularity.
  • "Better" code quality: the product also includes a unit testing framework that works with the centralized build and reporting portions to give indications of code churn, unit test coverage, and pass rates. Check in policies can be configured to check if the code compiles, run static code analysis, even run selected tests

Each one of these allow the onsite team to ensure compliance with corporate standards and gain trust in confidence in the offshore team's ability to deliver a quality, stable product.

Team Foundation Server Power Tools (tfpt) 1.2 Released

Today the Team Foundation Server team announced the release of version 1.2 of Team Foundation Power Tools (formally known as Power Toys). What are the Power Toys you say? They're extra functionality delivered out of band for Team Foundation Server including some really useful stuff (get changes for changeset, consolidated annotation of a file, command line history, and rollback to name a few).

In the latest release they have included support for Windows Vista (woo-hoo!) and several new tools:

[from announcement]

  • Workspace Command (tfpt.exe) - Use the workspace command for additional workspace operations not supported in the currently shipping Team Foundation Server command-line tool (tf.exe).
  • Treeclean Command - Use the treeclean command to see and optionally delete files in the current directory and all subdirectories that are not under version control.
  • Process Template Editor - A tool that provides a user interface for authoring work item types and some of the associated process template components.
  • Check-in Policy Pack - A set of custom policies that address often expressed customer needs. For example, the Custom Path Policy allows you to filter the specific items upon which another policy acts.
  • Build Test Tools Task - An MSBuild task that allows you to run unit tests by specifying the DLLs  or a file name pattern in the TfsBuild.proj file instead of using .vsmdi files to specify which tests to run.

One thing that I am very excited for is the new path policy (included in the Check-In Policy Pack). This allows policies to be applied to specific paths in team foundation server (i.e. don't check for valid unit tests on a directory with 3rd party source code). The other policy I'm excited for is the work item query policy—my project teams have several builds operating concurrently within the same team project and sometimes a private build is executed and picks up work items and associations not belonging to it specifically creating false relationships and throwing off some of our reporting.

To download version 1.2, go to the Microsoft Download center at http://www.microsoft.com/downloads/details.aspx?familyid=7324c3db-658d-441b-8522-689c557d0a79&displaylang=en Help for the new tools can be found on the TFPT Forums at http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=930&SiteID=1

Additional information on the tools in depth can be found on Rich's Developer Tools Blog

Getting my Sandcastle Team Build targets file to work with Sandcastle September CTP

A few things before we get started:

  1. You will need the HTML Help Workshop installed
  2. September CTP of Sandcastle
  3. My September CTP Sandcastle Targets File (attached)
    This file needs to be copied to your %programfiles%\MSBuild directory

Next you will need to make some modifications to the standard configuration file (I am using the VS2005 style)

  1. Make a copy of %programfiles%\Sandcastle\Presentation\vs2005\configuration\sandcastle.config
  2. Change references of
    1. ..\..\ to %programfiles%\sandcastle\
    2. ..\cpref_reflection to %programfiles%\sandcastle\examples\cpref_reflection

Update your TFSBuild.proj to include the following:

  1. Add a new Import tag referencing the sandcastle targets file
  2. Add a new target called DocumentCLR
    <Target Name="DocumentCLR">
    <CallTarget Targets="SandcastleDocument" ContinueOnError="false" />
    <MakeDir Condition="!Exists('$(BinariesRoot)\Documentation')" Directories="$(BinariesRoot)\Documentation" ContinueOnError="false" />
    <Copy SourceFiles="$(SandcastleWorkingDirectory)\Output\$(SandcastleDocumentationName).chm" DestinationFiles="$(BinariesRoot)\Documentation\$(SandcastleDocumentationName).chm" ContinueOnError="false"/>
    </Target>
  3. Add an additional target that overrides the AfterCompile target
    <Target Name="AfterCompile">
    <CallTarget RunEachTargetSeparately="true" Targets="DocumentCLR" ContinueOnError="false"/>
    <OnError ExecuteTargets=" OnBuildBreak;"/>
    </Target>
  4. Update your TFSBuild.rsp file to include some configuration
    /p:SandcastleDocumentationName=NameOfYourCHM
    /p:SandcastleConfiguration="C:\Path_TO_MODIFIED_CONFIG\sandcastle.config"
    /p:SandcastleDocumentationOutput=$(BinariesRoot)\Documentation
    /p:SandcastleDependencies="%windir%\Microsoft.NET\Framework\v2.0.50727\*.dll,\\lcabuildvm01\3rdParty\Dependencies\*.dll,%windir%\assembly\GAC_MSIL\Microsoft.VisualStudio.QualityTools.UnitTestFramework\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll"
    /p:SandcastleHelpGeneration=CHM
Posted by Richard Murillo | 2 Comments
Attachment(s): Sandcastle.targets

Reusable MSBuild Sandcastle Targets File

Based on a past post, I have an external targets file you can place in your $(MSBuildExtensionsPath) folder (attached in zip).

 You can call it like this:

  <Import Project="$(MSBuildExtensionsPath)\Sandcastle.targets"/>

<Target Name="AfterCompile">

    <CallTarget RunEachTargetSeparately="true" Targets="DocumentCLR" ContinueOnError="false"/>

    <OnError ExecuteTargets="OnBuildBreak;"/>

  </Target>

<Target Name="DocumentCLR">

    <CallTarget Targets="SandcastleDocument" ContinueOnError="false" />

    <MakeDir Condition="!Exists('$(BinariesRoot)\Documentation')" Directories="$(BinariesRoot)\Documentation" ContinueOnError="false" />

    <Copy SourceFiles="$(SandcastleWorkingDirectory)\Output\$(SandcastleDocumentationName).chm" DestinationFiles="$(BinariesRoot)\Documentation\$(SandcastleDocumentationName).chm" ContinueOnError="false"/>

  </Target>

 

The following is configuration from my msbuild response file:

/p:SandcastleDocumentationName=MyProjectDocumentation

/p:SandcastleConfiguration=C:\YOUR\CONFIG\sandcastle.config

/p:SandcastleDocumentationOutput=$(BinariesRoot)\Documentation

/p:SandcastleDependencies="%windir%\Microsoft.NET\Framework\v2.0.50727\*.dll,C:\YOUR\Dependencies\*.dll,%windir%\assembly\GAC_MSIL\Microsoft.VisualStudio.QualityTools.UnitTestFramework\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll"

/p:SandcastleHelpGeneration=CHM

 

Note: tested with build 2.0.2426.28539

VSTF Feature Request

There have been several instances when working with multiple teams that they need to build different build configurations on the same build machine. For example, we have a central build type that encapsulates the compilation of the bits, database installation and unit testing, and packaging of the compiled bits into an MSI. We also have build configurations that separate each. With OOB functionality you get an error message with the details of a soap exception explaining that only one build can be run at a time, which is understandable, but what about queuing?

To get around this issue, I built a queuing web site that can be used to invoke builds instead of through the team explorer. The code uses the thread pool to wait for the active build to complete then starts its build task

Using Sandcastle August CTP and MSBuild to produce CHM documentation automatically

First, we created a cmd file to do the build for us. Syntax for calling the file is Build.cmd "PathToBinaries" "Name of the documentation" (more on this later)

@echo off

PUSHD %1

"%programfiles%\Sandcastle\ProductionTools\mrefbuilder.exe" *.dll /out:%~dp0\reflection.org /dep:%windir%\Microsoft.NET\Framework\v2.0.50727\*.dll,C:\deps\*.dll,%WINDIR%\assembly\GAC_MSIL\Microsoft.VisualStudio.QualityTools.UnitTestFramework\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll

IF ERRORLEVEL 1 EXIT /B 1

POPD

"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\AddOverloads.xsl" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\AddGuidFilenames.xsl" reflection.org /out:reflection.xml

IF ERRORLEVEL 1 EXIT /B 1

"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToManifest.xsl" reflection.xml /out:manifest.xml

IF ERRORLEVEL 1 EXIT /B 1

if not exist Output mkdir Output
if not exist Output\html mkdir Output\html
if not exist Output\art mkdir Output\art
if not exist Output\scripts mkdir Output\scripts
if not exist Output\styles mkdir Output\styles
copy "%programfiles%\Sandcastle\Presentation\art\*" Output\art > NUL
copy "%programfiles%\Sandcastle\Presentation\scripts\*" Output\scripts > NUL
copy "%programfiles%\Sandcastle\Presentation\styles\*" Output\styles > NUL

"%programfiles%\Sandcastle\ProductionTools\BuildAssembler.exe" /config:sandcastle.config manifest.xml
IF ERRORLEVEL 1 EXIT /B 1

"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToChmProject.xsl" reflection.xml /out:Output\%2.hhp

IF ERRORLEVEL 1 EXIT /B 1

"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToChmContents.xsl" reflection.xml /arg:html=Output\html /out:Output\%2.hhc

IF ERRORLEVEL 1 EXIT /B 1

"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToChmIndex.xsl" reflection.xml /out:Output\%2.hhk

IF ERRORLEVEL 1 EXIT /B 1

CD OUTPUT

"%programfiles%\HTML Help Workshop\hhc.exe" %2.hhp

CD ..

 

There is also a configuration file we're using referenced in our call to BuildAssembler.exe; here is that

<configuration>

  <dduetools>

    <builder>

      <components>

        <!-- Create skeleton document -->

        <component type="Microsoft.Ddue.Tools.CopyFromFileComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

      <data file="%programfiles%\Sandcastle\Presentation\transforms\skeleton.xml" />

      <copy source="/*" target="/" />

    </component>

        <!-- Copy in reflection data -->

    <component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <index name="reflection" value="/reflection/apis/api" key="@id" cache="10">

            <data files="reflection.xml" />

          </index>

          <copy name="reflection" source="*" target="/document/reference" />

    </component>

    <!-- Copy in container data -->

    <component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <copy name="reflection" key="string(/document/reference/containers/container/@namespace)" source="*[not(local-name()='elements')]" target="/document/reference/containers/container[@namespace]" />

    </component>

    <component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <copy name="reflection" key="string(/document/reference/containers/container/@type)" source="*[not(local-name()='elements')]" target="/document/reference/containers/container[@type]" />

    </component>    

    <!-- Generate syntax -->

    <component type="Microsoft.Ddue.Tools.IfThenComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

      <if condition="not(starts-with($key,'Overload:') or starts-with($key,'R:'))" />

          <then>

      <component type="Microsoft.Ddue.Tools.SyntaxComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

        <syntax input="/document/reference" output="/document/syntax" />

        <generators>

              <generator type="Microsoft.Ddue.Tools.CSharpDeclarationSyntaxGenerator" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\SyntaxGenerators.dll" />

              <generator type="Microsoft.Ddue.Tools.VisualBasicDeclarationSyntaxGenerator" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\SyntaxGenerators.dll" />

              <generator type="Microsoft.Ddue.Tools.CPlusPlusDeclarationSyntaxGenerator" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\SyntaxGenerators.dll" />

            </generators>

          </component>

          </then>

    </component>

    <!-- Copy in comments -->

    <component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <index name="comments" value="/doc/members/member" key="@name" cache="100">

            <data files="Documentation\*.xml" />

          </index>

          <copy name="comments" source="*" target="/document/comments" />

    </component>

    <!-- Copy in reflection data and comments for members -->

        <component type="Microsoft.Ddue.Tools.ForEachComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <variable expression="/document/reference/elements/element/@api" />

          <components>

            <component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <copy name="reflection" source="*[not(local-name()='elements')]" target="/document/reference/elements/element[@api=$key]" />

        </component>

            <component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

              <copy name="comments" source="summary" target="/document/reference/elements/element[@api=$key]" />

            </component>

          </components>

        </component>

    <!-- transform -->

        <component type="Microsoft.Ddue.Tools.TransformComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <transform file="%programfiles%\Sandcastle\Presentation\transforms\main_sandcastle.xsl" />

        </component>

    <!-- resolve shared content -->

        <component type="Microsoft.Ddue.Tools.SharedContentComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <content file="%programfiles%\Sandcastle\Presentation\content\shared_content.xml" />

          <content file="%programfiles%\Sandcastle\Presentation\content\reference_content.xml" />

    </component>

    <!-- resolve reference links -->

    <component type="Microsoft.Ddue.Tools.ResolveReferenceLinksComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

      <targets files="reflection.xml" type="local" />

    </component>

    <!-- save the result -->

        <component type="Microsoft.Ddue.Tools.SaveComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">

          <save path="concat('Output\html\',/html/head/meta[@name='guid']/@content,'.htm')" indent="false" omit-xml-declaration="true" />

        </component>

      </components>

    </builder>

  </dduetools>

</configuration>

 

Now we have to hook it up to MSBuild. Within the TFSProj.proj file, a new target was created called by an override to the Team Build AfterDrop target

<PropertyGroup>

    <SandcastleDocumentDirectory>$(TEMP)\SandcastleDocument</SandcastleDocumentDirectory>

</PropertyGroup>

<Target Name="SandcastleDocument">    

    <CreateProperty Value="MyDocumentation">

      <Output TaskParameter="Value" PropertyName="SandcastleDocumentationName"/>

    </CreateProperty>

    <RemoveDir Condition="Exists('$(SandcastleDocumentDirectory)')" Directories="$(SandcastleDocumentDirectory)" ContinueOnError="false"/>

    <MakeDir Directories="$(SandcastleDocumentDirectory)" ContinueOnError="false" />

    <CreateItem Include="$(SolutionRoot)\Sandcastle\Aug 2006 CTP\Build.cmd">

      <Output ItemName="SandcastleBuildScript" TaskParameter="Include"/>

    </CreateItem>

    <Copy SourceFiles="@(SandcastleBuildScript)" DestinationFiles="@(SandcastleBuildScript -> '$(SandcastleDocumentDirectory)\Build.cmd')" ContinueOnError="false" />

 

    <CreateItem Include="$(SolutionRoot)\Sandcastle\Aug 2006 CTP\sandcastle.config">

      <Output ItemName="SandcastleConfiguration" TaskParameter="Include"/>

    </CreateItem>

    <Copy SourceFiles="@(SandcastleConfiguration)" DestinationFiles="@(SandcastleConfiguration -> '$(SandcastleDocumentDirectory)\sandcastle.config')" ContinueOnError="false" />

 

    <MakeDir Directories="$(SandcastleDocumentDirectory)\Documentation" ContinueOnError="false"/>

    <CreateItem Include="$(BinariesRoot)\x86\Debug\*.xml">

      <Output ItemName="CodeDocumentationFiles" TaskParameter="Include"/>

    </CreateItem>

    <Copy SourceFiles="@(CodeDocumentationFiles)" DestinationFiles="@(CodeDocumentationFiles -> '$(SandcastleDocumentDirectory)\Documentation\%(Filename)%(Extension)')" ContinueOnError="false"/>

 

    <Exec WorkingDirectory="$(SandcastleDocumentDirectory)" Command="Build.cmd &quot;$(BinariesRoot)\x86\Debug&quot; $(SandcastleDocumentationName)" ContinueOnError="false" />

 

    <CreateItem Include="$(SandcastleDocumentDirectory)\output\$(SandcastleDocumentationName).chm" ContinueOnError="false">

      <Output ItemName="SandcastleDocumentationFiles" TaskParameter="Include"/>

    </CreateItem>

    <MakeDir Condition="!Exists('$(BinariesRoot)\Documentation')" Directories="$(BinariesRoot)\Documentation" ContinueOnError="false" />

    <Copy SourceFiles="@(SandcastleDocumentationFiles)" DestinationFiles="@(SandcastleDocumentationFiles -> '$(BinariesRoot)\Documentation\%(RecursiveDir)%(Filename)%(Extension)')" ContinueOnError="false" />

 

    <OnError ExecuteTargets="OnBuildBreak;"/>

  </Target>  

I'm on Channel9!

Yay!

I'm on the front page of Channel9 with an interview about using Visual Studio Team System in MSIT's Legal group.

Full link for your reference: http://channel9.msdn.com/showpost.aspx?postid=220125

More Posts Next page »
 
Page view tracker