March 2007 - Posts
Now we have hierarchy in our Work Item, we can take things to another level. The Hierarchy implies a relation between these Work Items, so it is natural to think that when one's is evolving, it impacts its surroundings.
For instance, you have a Change Request that has three child Tasks:
- The Request becomes Active when at least one of the tasks turns to Active.
- The Request will becomes Resolved when all the Tasks will be Closed.
- The Request will be Closed when everything will be integrated, tested and validated by the testing team.
What is important here is that the Change Request is assigned to the Team Leader of the evolution to realize, each Task are assigned to developers. When a developer starts working on a Task, he switches its state from Proposed to Active. This field change will trigger an alert that will result in the activation of the owner Change Request, and the Team Leader will get an email to inform him that the Change Request is finally starting (because one of his Work Items was changed by someone else)!
This is just a simple example of what we can do, but we can imagine things more complicated, that would be real time saver for team management and communication.
The "Models" we've implemented so far are:
Project Management
The project management model ensures the synchronization between the states of the Change Request and Bug Work Items. A Change Request can contains zero or many Change Requests or Bugs. A whole project can be organized is a hierarchical way, and you know easily what is still planned, in progress, realized, closed, and that at a macro or micro level!
Synchronization rules are simple:
-
A parent is Proposed if all its children are Proposed.
-
A parent is Active if at least one of the children is Active.
-
A parent is Resolved if all its children are Resolved.
-
A parent is Closed when all its children are Closed.
Change Request
This model is made of a Change Request that contains one or many Tasks. The rules are:
-
The Change Request becomes active when at least one of its children Task becomes Active.
-
It turns to Resolved when all the Tasks are Closed.
-
It turns back to Active at least one Task was reactivated because of a test that failed.
-
It turns to Closed if all validation and tests was successfully accomplished.
Bug
This model has two cases:
a) A simple bug, it will contain one child Task that will be assigned to the developer.
b) A complex bug, it will contain a Change Request using the "Change Request" model to develop the fix.
The first case follows the same logic than the "Change Request" model, but with only one child Task. The second case is an instance of the "Change Request" model.
Task development
Code reviews are a must for us, and for a given category of developers we want to validate the code before it is checked-in. This model takes care of that. The Task Work Item has a child Review Work Item in a Proposed state. When the developer has finished its code, he switches the state of the Task from Active to Review Pending. This state transition will activate the Review, and the code reviewer will be aware it's time to make it! If the review failed, the Work Item will turn back to Proposed, putting automatically the Task in Active state. If the review succeeds, the code reviewer will pass the Review Closed, which will automatically set the Task's state to Pending Check-in (a developer can't set this state). The developer then will be able (thanks to a check-in policy) to check his code in, and the Task will turn to Closed.
These descriptions of models are a simplification of what we're really doing right now.
Things were tricky to design at first, but once the main models with the main cases were done, the implementation went smoothly, and the day-to-day utilization is now really intuitive.
There're few things I want to share about the WorkItemStore::GetWorkItem() method.First, it may sound clear for everybody, but:
WorkItem a = wis.GetWorkItem(10);
WorkItem b = wis.GetWorkItem(10);
The instance a and b won’t be the same, you’ll have two separate objects for the same Work Item!
WorkItem instances could have been considered as singleton, with only one instance of a given WorkItem in the store. Would that made sense to you?
Personally, yes, it would.
GetWorkItem() is slooooow, I mean it, really, on my WebService which tracks states changes to synchronize related work item, I found out that 90% of the time execution was in that call (believe me, there’re much more than that in this WebService).As I was getting many time the same ID, I quickly made a class that implement a Work Item cache, based on a List<> (I know it’s maybe not the fastest way to find a occurrence from a given key, but well…)On my WebService, it turns out I was six times faster with this implementation…If Work Item were considered as singleton, I think I wouldn’t have had this performance issue.
And one last thing: if you modify a, then b, then a.Save() and b.Save(), you’ll have a nice exception throwing at you on the second Save call, with the impossibility to conciliate both changes (easily at least)…Not very cool !
Create a custom field in all your concerned Work Items named "ParentWI" for instance, of type integer.
Now, say you want to link two Work Items, the method will looks like:
public void LinkWorkItems(WorkItem parent, WorkItem son)
{
RelatedLink rl = new RelatedLink(son.Id);
parent.Links.Add(rl);
son.Fields["ParentWI"].Value = parent.Id;
son.Save();
parent.Save();
son.SyncToLatest();
}
I put a specific comment in the link to mark it as a hierarchy kind of link.
Take care to the last line, you may wonder why I do a SyncToLatest(), the reason is quite simple:
Work Item links are bi-directionals. Once you link a Work Item A to a Work Item B, the opposite link is created automatically when you save A.
Then you better do a SyncToLatest() to get the other Work Item up to date.
For our hierarchy evaluation, it might be a problem because you don’t know if the links you’ll evaluate are for children or the parent.
But there’s a simple way to evaluate if a given link is to a child: just get the ParentWI of that child and compare it with the current Work Item ID.
Here's a snippet of a method that get all the children of a given Work Item:
public IEnumerable WIGetChildren(WorkItem wi)
{
ArrayList array = new ArrayList();
// We evaluate all the links for this Work Item
foreach (Link link in wi.Links)
{
// Hierarchy links have this comment
if (link.Comment == "")
{
// Get the linked Work Item
RelatedLink rl = link as RelatedLink;
if (rl == null)
{
// It's another kind of link, go to the next one
continue;
}
// Get the corresponding Work Item
// (it's supposed to be the child)
WorkItem linkedwi = GetWorkItem(rl.RelatedWorkItemId);
// Check if the ParentWI of the child is this Work Item
// If it's not the case, it's a child to parent relation
if (wi.Id != (int)linkedwi.Fields["ParentWI"].Value)
{
continue;
}
// It's a child, we add it
array.Add(linkedwi);
}
}
return array;
}
That’s it, you have everything you need to implement hierarchy in your Work Items!
Relationship between Work Items is something important to me.
The first thing that is obviously missing is a sense of hierarchy. Hierarchy is everywhere in life, so it is in a project management. Of course you can live without this notion in Team System thanks to Areas and Iterations, but it’d cost you more time to manage things if you can’t relate your Work Items with a parent/son relationship.
Here is a concrete case of what I wanted to be possible:

Project management becomes easier, and programmers' life too.
Yellow stars are Change Requests, Green checks are Tasks, Red crosses are Bugs, and the Warning-like icon is an Issue.
Change request are owned by Project Leaders, Tasks are assigned to developers, Bugs are created by the Testing Team, and Issues are declared by users when they can't complete a given task due to an external reason.
A picture like that talks a lot more than a Query result on a given Area, don't you think?
Another benefit of the hierarchy, and it's not the least one, is you can make Work Items interacting each other automatically.
For instance:
- When a developer starts a task by setting it active, the parent Change Requests turn to active too (and your project leader knows by email that a development is starting).
- When all the tasks are closed, the owner Change Request becomes Resolved, and is waiting for approval from the Testing Team to be Closed.
- There are many other examples we could mention, like being aware when an Issue you created was solved, knowing that you have to start a Code Review, knowing your code was approved and you can check-in, etc.
Two weeks ago, here's what I discovered when building a "remaining work" report.
Ok, you can say we don't use these things a lot (it'll change in the future, I can assure you) because it took time for us to notice.
But still, the issue is annoying, and I had to fix it!
Here is what I got from the Log:
TF53010: An unexpected condition has occurred in a Team Foundation component.
The information contained here should be made available to your site administrative staff.
Technical Information (for the administrative staff):Date (UTC): 3/19/2007 11:21:25 AM
Machine: PTFOUNDATION01Application Domain: /LM/W3SVC/3/Root/Warehouse-4-128187766414349430
Assembly: Microsoft.TeamFoundation.Warehouse, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a; v2.0.50727Process Details: Process Name: w3wp Process Id: 3316 Thread Id: 2144 Account name: CEGEDIMtfsservice
Detailed Message: Microsoft.TeamFoundation.VersionControl.Adapter: An error occurred while processing changeset 2284, unexpected exception: Exception Message: Thread was being aborted. (type ThreadAbortException) Exception Stack Trace: at Microsoft.TeamFoundation.VersionControl.Adapter.Hatteras.retrieveChanges(Changeset changesetInfo, Int32 changePositionInChangeSetToProcess) at Microsoft.TeamFoundation.VersionControl.Adapter.VCAdapter.processChangesets()
Well, the changeset 2284 in question was causing trouble to the updating process because it was made of nearly 37000 files (we can say it's big, ok...).
Then a timeout occurred before our server could analyze it, failing the whole process.
Thanks to Eric Le Loc'h from Microsoft France, I could fix it by doing the following things in IIS:
1. Create a new TFSWarehouse application pool.
a. Disabling any recycling settings in the Recycling tab.
b. Disabling timeout in the Performance tab.
c. Set the TFSService account in the Identity tab.
2. Moving the Warehouse application to the new application pool, and voilà !
The warehouse spent few hours to make it up to date, and everything is back to normal now!

The development team I'm working on moved to Team System in September 2006. The shift from what we used before was pretty huge, mainly because we weren't using SCM at all ("WinMerge rulez!" you may say).
Of course, things had to evolve smoothly, and I can say it did pretty well!
First we started using the Source Control part, discovering the many benefits of the Shelve feature (backup, code review helper) and the Workspace one (working on different versions at the same time became something easy).
The next step was introducing the notion of Work Items in our development.
I customized the CMMI Process Template, it was more a slaughter than a customization, I remove many WITs to keep only Task, Review and Bug. I also removed many fields "too complicated for us".
One of the great feature of Team System is you can keep on customizing your existing projects, your process evolves as your development does, thanks to the feedback of your teams.
Anyway, when everybody started being comfortable with these WITs, as I just didn't wanted them to lay back and finally "stopping learning this Team System thing and start coding again!!!", I planned a major evolution of the whole thing.
Our goal, like many companies, is to progress in the CMMI certification, so I have to introduce more "CMMI proofed stuffs" in our project.
So I bring back "Change Request" (how could we've lived without it?) and "Issue" (because the life of a programmer is not always that easy...).
So here we are, using five types of Work Item: Task, Change Request, Bug, Issue and Review.
One thing immediately stroked me: all these types are for specific purpose, but the instances should "somewhere" be related, and because they're used by different people (product leader, team leaders, developers) they should ease the communication in our team (and by ease, I mean things should be automatic).
All I was seeing in Team System is a bunch of Work Items, related with an iteration of development, a specific area of our project and Work Item Queries that returns already a lot of results where it's hard to find what you're looking for!
I think we can do better than that, don't you? :)
See you at the next post!