Monday, February 25, 2008

Modifying Work Item Type definition using the Object Model

I'm in the process of easing the installation of the Work Item Creator.
To do that, I wanted to detect in runtime if a given Team Project doesn’t have its Work Item Types (WITs) supporting hierarchy and then asking the user to add them.
It’s not very complicated to do, once you know how to do it (as always you might say).

To get the definition of a given Work Item Type and add a field, it’s not complicated:

 2412 // Get the Xml Document for the given WIT

 2413 XmlDocument doc = wit.Export(false);

 2414 XmlElement fields = doc.SelectSingleNode("*/WORKITEMTYPE/FIELDS") as XmlElement;

 2415 

 2416 // Look for each field, and add the ones that are not present

 2417 XmlElement field = fields.SelectSingleNode("FIELD[@refname=\"Cegedim.ParentWI\"]") as XmlElement;

 2418 if (field == null)

 2419 {

 2420     field = doc.CreateElement("FIELD");

 2421     field.SetAttribute("name", "ParentWI");

 2422     field.SetAttribute("refname", "Cegedim.ParentWI");

 2423     field.SetAttribute("type", "Integer");

 2424     field.InnerXml = "<HELPTEXT>The ID of the Parent Work Item</HELPTEXT><DEFAULT from=\"value\" value=\"0\" />";

 2425     fields.AppendChild(field);

 2426 }

To validate the type before importing it:

 2453 WITValidateSucceed = true;

 2454 prj.WorkItemTypes.ImportEventHandler += new ImportEventHandler(WorkItemType_ValidationEventHandler);

 2455 WorkItemType.Validate(prj, doc.OuterXml);

 2456 if (WITValidateSucceed == false)

 2457 {

 2458     MessageBox.Show("Work Item Type couldn't pass validation, something went wrong", "Work Item Creator", MessageBoxButtons.OK, MessageBoxIcon.Error);

 2459     return false;

 2460 }

The registered event will be fired if the validation failed. Why the Validate method doesn’t return a bool, I don’t know…

 2473 void WorkItemType_ValidationEventHandler(object sender, ImportEventArgs e)

 2474 {

 2475     WITValidateSucceed = e.Severity == ImportSeverity.Error;

 2476 }

Then, you’ll have to call Import from the WorkItemTypes collection to update your type:

 2461 prj.WorkItemTypes.Import(doc.OuterXml);

prj being your Work Item “Project” instance.

Now there’s a small trick and if you don’t know it, you’ll be like me, wasting 2 hours trying to figuring out why your application is totally crashing when you try to modify two WITs in a row.

Importing an existing WIT will update the server side, but apparently the definition of your WITs are cached in local, and this cache is not updated by the Import method (it could have been…), so if you try to modify a second WIT, somehow the Team System Object Mode doesn’t like it!
The solution is not that hard though, after your import, you only have to call these two methods:

 2401 m_WIS.RefreshCache();

 2402 m_WIS.SyncToCache();

m_WIS being your instance of the Work Item Store. This way you local version is updated, and you can keep working on WIT modification!

Posted by Loïc Baumann at 13:14:32 | Permanent Link | Comments (0) |

Thursday, April 19, 2007

A change in handling Hierarchy

My team came up with a request that looked at first « easy to code » but which turned out to be a real pain: managing order in siblings.

As I wrote in a previous post, I was using the Work Item's Links (to link a son with its father) and a custom field "ParentWI" to handle the Hierarchy.

The pros:

  • I'm relying on existing features of Team System, it's supposed to make the enhancement tighter with the original software.
  • I thought it would be easier to code it that way... Well, until I had to code it!

The cons:

  • It turned out that the Links of type "Work Item" are bidirectional, and then automatically created on the opposite way when you create a new link. This is a REAL PAIN for the implementation, because you constantly have to SyncToLatest() the opposite Work Item after creating a Link. And looks like it's not always working: there are some times when I have exceptions raising because of my Work Item not up to date with the server.

    This issue is emphasized by the fact that you CAN'T merge Work Item: I you made changes locally and the Work Item was changed (due to the bidirectional link creation, for instance) by the time you save it, it throws you an exception...Not very handy or easy to encounter...

  • There is no order between siblings, not even a chronological one. I first thought that the order will be chronological, but it turned out it has no sense at all (on a functional point of view). And my teammates yell at me "why the order changed suddently!!!"

I came to the point that I had to implement hierarchy in a different way: forget about the Links, this is just a nightmare for WI Hierarchy and I can't really see the advantages for the price I pay to use them.

The solution was not complicated to find: add two more custom fields.
"FirstChildWI", it contains the ID of the first child of the Work Item.
"NextWI", it contains the ID of the next sibling.
I don't need a "PrevWI" kind of field, parsing backward is not very useful, and I can still do it without it.

Another solution would have been to create a "ChildrenWI" custom field of type String that references all the children in a given order. But I assumed (maybe I'm wrong) that the String type has a limited size, and I wouldn't want to limit the count of children.

So here I am, three custom fields for the hierarchy, no more Links to handle, a simplified saving process, and I still kept the ability to create new Work Items in a hierarchical way WITHOUT saving them right away (which lets the user the possibility to "delete" the Work Item if needed).

The user has the ability to reorder its Work Items, life is good! :)

Posted by Loïc Baumann at 23:23:20 | Permanent Link | Comments (0) |

Wednesday, April 04, 2007

WI Creator and WINetwork in action !

 I've made some videos of the WICreator application, used with the WINetwork system.
Check them out, I think they worth it!
  • This one is about the creation of a project and the realization of a task with a code review. Both processes use the WINetwork to ease the communication and synchronization of Work Items.
  • Use of the Recycle Bin.
  • An example (in French) of a real project.

I should have disabled the ClearType font antialiasing for the Video Capture, looks ugly because of it...

One last thing, and not the least, if you want to know how the whole thing works internally, check out this XML file. It defines what type of Work Items we can create in respect of the hierarchy, and also describes all the Work Item Network Models I told about in this post.

Posted by Loïc Baumann at 22:32:53 | Permanent Link | Comments (5) |

Work Item Creator

Yes I know, spare me with the poor naming of this application, this is what happens when you allow yourself no more than 30sec to find something...

Anyway, as I told in previous posts, hierarchy in Work Items are a must for us, so we had to develop an application which allow people to create Work Items in a hierarchical way.

To make the application works, all you have to do is create a "ParentWI" integer field!

There are some features like the Recycle Bin one that is just cool for everyday use. As you can't destroy a Work Item, I created a Recycle Bin one where all the Work Items people don't need any more are stored. I also change the Area Path of the Work Item when it's moved there, to get it out of every scope.

Here what the application looks like.

Posted by Loïc Baumann at 22:11:02 | Permanent Link | Comments (0) |

Friday, March 30, 2007

Work Item Network Models

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:

  1. A parent is Proposed if all its children are Proposed.
  2. A parent is Active if at least one of the children is Active.
  3. A parent is Resolved if all its children are Resolved.
  4. 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:

  1. The Change Request becomes active when at least one of its children Task becomes Active.
  2. It turns to Resolved when all the Tasks are Closed.
  3. It turns back to Active at least one Task was reactivated because of a test that failed.
  4. 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.

Posted by Loïc Baumann at 21:20:31 | Permanent Link | Comments (1) |

Friday, March 23, 2007

Getting Work Items from the Store

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 !

Posted by Loïc Baumann at 16:39:41 | Permanent Link | Comments (0) |

Simple way to create Work Item Hierarchy

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);

    rl.Comment = "";

    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!

Posted by Loïc Baumann at 13:00:22 | Permanent Link | Comments (0) |

Wednesday, March 21, 2007

Hierarchy in 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:

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.
Project management becomes easier, and programmers' life too.
Posted by Loïc Baumann at 22:51:02 | Permanent Link | Comments (0) |

Monday, March 19, 2007

Work Items, an urgent need of evolution!

 

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!

Posted by Loïc Baumann at 22:57:56 | Permanent Link | Comments (0) |