Saturday, May 09, 2009

Work Item customization tidbits: custom controls (part 14 of X)

In one of my previous posts I mentioned that I consider custom controls in WI one of the most complex types of customization to implement. Since I got asked related question let me expand on the topic.

Custom work item controls provide a way to implement truly specialized behavior for WI, by writing managed class conforming to well-known interface. Sometimes it may be very tempting to write the logic in C# instead of learning intricacies of WIT XML syntax (and sometimes there is no alternative).

Why is this type of customization so complex? Because you have to code, integrate, test & deploy additional component, and that in a way different from other WIT customizations in XML. And not only that - consider the following important drawbacks custom control has:

  • Additional version of the control needs to be implemented if you want to support the same logic in Web UI as in Visual Studio environment
  • Custom control is not supported when editing WI in Excel (or MS Project)
  • Custom control assembly needs to be deployed on every client machine (or on Web server if the custom control targets Web UI)

All of the above means that custom WIT control should be implemented only when you have absolutely no other answer to outstanding business requirement.

For further information there is extensive summary article on the topic by Ognjen Bajic. Another interesting article by Neno Loje provides additional details on customizing Work Item types depending on the client (WinForms or Web), which is very relevant for custom controls.

Related posts:
- Work Item Customization: limits of complexity (part 13)
- Work Item Customization: estimate the effort (part 12)
- Work Item Customization: customization and global lists (part 11)
- Work Item Customization: customization process (part 10)
- Work Item Customization: customization tools (part 9)
- Work Item Customization: special fields (part 8)
- Work Item Customization: fields maintenance (part 7)
- Work Item Customization: global lists (part 6)
- Work Item Customization: system fields (part 5)
- Work Item Customization: user interface (part 4)
- Work Item Customization: state transitions (part 3)
- Work Item Customization: conditional field behavior (part 2)
- Work Item Customization: fields definition (part 1)

Mirror from MSDN blog

Wednesday, May 06, 2009

Work Item customization tidbits: limits of complexity (part 13 of X)

Today I’d like to talk about WIT customization recommendations that will mostly become applicable as your custom Work Item types increase in complexity.

Keep the number of custom fields limited (per TFS server)

One can have a maximum of 1024 fields defined per Team Foundation Server (as every field is represented by a column in SQL Server table, the limitation is that of maximum number of columns per table in SQL Server). That means that if you define new fields (FIELD with the distinct refname attribute) per WIT, you can easily hit this limit after creating a few complex Work Item types. Once the limit is reached, you have to deal with fields maintenance chores (you must delete some of the fields, and to delete them the fields must not be used in any WIT) – not a lot of fun when what you actually tried to achieve was to create new template.

How do you prevent this problem from occurring? Reuse is the key here – remember that even though it may look like you define a new field per Work Item type, fields are (precious) server resource; and even if the same field is used in WI you can specify different behavior for the same field in a different WIT.

Keep the number of rules limited (per Work Item Type)

While you can create multiple rules in WIT, be aware that rules not only affect maintenance complexity (you have to make it work ;), but also affect the performance. So your users may experience less than stellar performance when they create or modify work items. And there is an additional consideration which I will expand upon in the next section, which is called

Keep the number of WI types small (per Team project)

While there is no hard limit on the number of WIT you can create in one Team project, there is technology limitation (SQL Server again!) on how much complexity one may have per project, with numeric complexity index in this case being defined as [Number of rules in WIT] x [Number of WIT in project]. When you have too many WIT (or few of very complex ones) you may hit a limitation of maximum size of columns in SQL Server statement (65,535). It turns out all rules you define in WIT in Team project are eventually represented as part of real complex SQL statement used for WI validation when changing its data (read more techy details in this forum post by Amit Ghosh)

Keep the number of reportable fields small (per TFS server)

If you are not planning on including the fields into SQL Reporting reports, do not mark fields reportable just for the heck of it, since the reportable fields will propagate into TFS data warehouse and that would add extra in terms of performance and space on your TFS data layer.

By the way, to really understand how reporting in TFS works (and how it fits in a big picture) read this excellent post from Vince Blasberg.

In conclusion, I’d like to highlight once more the importance of having test environment whereto you deploy the potential WIT changes prior to production rollout. Consider the situation where you have just deployed new WIT to a Team project, and as a result the users cannot update any WI in the project. Not a happy place to be, is it?

Related posts:
- Work Item Customization: estimate the effort (part 12)
- Work Item Customization: customization and global lists (part 11)
- Work Item Customization: customization process (part 10)
- Work Item Customization: customization tools (part 9)
- Work Item Customization: special fields (part 8)
- Work Item Customization: fields maintenance (part 7)
- Work Item Customization: global lists (part 6)
- Work Item Customization: system fields (part 5)
- Work Item Customization: user interface (part 4)
- Work Item Customization: state transitions (part 3)
- Work Item Customization: conditional field behavior (part 2)
- Work Item Customization: fields definition (part 1)

Mirror on MSDN blog

Friday, May 01, 2009

MSBuild UsingTask gotchas

One significant drawback of MSBuild UsingTask element is that you must specify exactly the task name you are importing. That is if the assembly you are importing contains 200 tasks, you will have to import them explicitly one by one. And since you probably do not want to do that in every project you author, usually these 200 tasks will be defined in separate project file that can be imported whenever the tasks are needed.

While there is no workaround for specifying the task name, there is another, somewhat easier way to make sure that the tasks are available to your projects without explicitly importing tasks project file.

Let’s suppose that you have created MSBuild project file that contains UsingTask statements for all custom tasks you want to have available in your projects. Then if you rename this project file to have .tasks extension and place it in .NET framework folder (e.g. C:\WINDOWS\Microsoft.NET\Framework\v3.5 folder for .NET 3.5), the tasks defined there will be available in any project using that version of MSBuild without explicit import statement.

This is the mechanism used to make tasks shipped with MSBuild by default available to all projects (look into Microsoft.Common.tasks file to see these tasks defined there). No magick required!

By the way, looking into Microsoft.Common.tasks file imparts two additional pieces of wisdom (to quote):

NOTE: Listing a <UsingTask> tag in a *.tasks file like this one rather than in a project or targets file can give a significant performance advantage in a large build, because every time a <UsingTask> tag is encountered, it will cause the task to be rediscovered next time the task is used.

Another useful comment relates to the way the tasks are defined in UsingTask – you can either specify fully-qualified task name (including namespaces) or a short one; however, (again, quote from Microsoft.Common.tasks file):

NOTE: Using the fully qualified class name in a <UsingTask> tag is faster than using a partially qualified name.

In addition to performance win, you will also be able to disambiguate the task used. For example, both SDC tasks and MSBuild Community tasks packages define a bunch of tasks that differ only by name. In such cases you will have to be explicit both in UsingTask statement and when using the imported task:

<!-- Import SDC Sleep task -->
<UsingTask AssemblyFile="Microsoft.Sdc.Tasks.dll" 
          TaskName="Microsoft.Sdc.Tasks.Sleep"/>
<!-- Import MSBuild Community Sleep task -->
<UsingTask AssemblyFile="MSBuild.Community.Tasks.dll" 
          TaskName="MSBuild.Community.Tasks.Sleep" />
<!-- Use SDC Sleep task, full name to disambiguate -->
<Target Name="Sleep">
  <Microsoft.Sdc.Tasks.Sleep SleepTimeout="1"/>
</Target>

Mirror from MSDN blog