Software Quality

December 18, 2009

Code Contracts improve Microsoft CRM Workflow code

Filed under: Case Study, Code Contracts — Tags: — David Allen @ 4:24 pm

Producing reliable, supportable software is hard. Providing reliability when integrating various different platforms poses even more challenges. Aggressive use of Code Contracts can substantially improve reliability, and speed the diagnosis and resolution of problems. Let’s see how the use of contracts is especially helpful when integrating custom workflow code into Microsoft CRM Workflows.

Background

In my current job, we develop solutions for our enterprise using the Microsoft CRM platform, and we have written custom code in C# that is integrated with custom workflows. One of the problems we face is related to inadequate handling of exceptions within the Microsoft CRM platform. When exceptions occur in a workflow, the workflow will fail, but no error messages are written to the event log. Instead, such errors are only revealed when you enable platform tracing, and examine the resulting trace files. This entire process is much more tedious than examining an event log.

Solution

We learned from this pain. We now use the following techniques to improve the speed of diagnosis:

  1. Wrap all custom workflow activity code in an outer exception-handling backstop,
  2. Include Microsoft Code Contracts liberally to overcome the limited diagnostic capabilities of the CRM Workflow platform.

Trap exceptions in our custom code

Our first solution was to wrap all custom workflow activity code in an outer exception-handling backstop, which writes exceptions to the Event Viewer before rethrowing them. In this way, when exceptions occur in our custom code, we can write those exceptions to the event log for easy diagnosis. I would think this is best practice for ANY application. We did not think of this at first because we did not think of our custom workflow code as an application. Instead, we thought of it as a component within the larger workflow application. However, we don’t have fine-grained control over the exception handling behavior of the asynchronous workflow engine implemented by the Microsoft CRM platform. So, by treating our custom code as if it were a separate application, and further by detecting and reporting all exceptions within the boundaries of that application, we have complete diagnostic information for exceptions that occur within our custom code.

Of course, detecting and reporting exceptions is enhanced when we use code contracts liberally. With contracts, our

Write stricter contracts to accommodate the needs of the platform

What exactly do we mean when we say “use code contracts liberally” above?

At first, we were happy with our exception handling mechanism. It looked like this.

public Lookup GetQueueContact(ICrmService crmService, PrimaryServiceSettingIdentifier serviceSettingIdentifier)
{
#region Contracts
Contract.Requires(crmService != null);
Contract.Ensures(Contract.Result<Lookup>() != null, "Lookups should NEVER be nulll in the CRM platform. Use Lookup.Null instead.");
Contract.Ensures(! Contract.Result<Lookup>().IsNull,
"CIC Queue Contact lookup cannot be Lookup.IsNull");
#endregion
...
< implementation >
...
return ...;
}

But we soon ran into another scenario which needed stronger contracts to enhance our diagnostic capabilities. Our custom code was designed to return a Microsoft CRM contact identifier. Our initial postcondition was to ensure that this contact was a valid identifier. But this was a weak postcondition because the custom workflow in the CRM platform, which used the results of our custom code, needed to actually find that contact and obtain the e-mail address. If it successfully retrieved an identifier from our custom code, but the identifier did not correspond to a valid CRM contact with a primary email address, it would fail, using the “not-so-helpful” diagnostic information previously described. So we enhanced the postcondition to fully express everything that the CRM platform would need. That way, if there were any shortcomings, we could detect them in our code and report them using our improved diagnostic mechanism. Here are the enhanced contracts. Notice that the last postcondition is complex and relies upon an external helper method that contact and examine the e-mail address. These are much more expressive assertions because they begin to speak to the true semantics of the software, rather than merely addressing superficial aspects of the code.

public Lookup GetQueueContact(ICrmService crmService, PrimaryServiceSettingIdentifier serviceSettingIdentifier)
{
#region Contracts
Contract.Requires(crmService != null);
Contract.Ensures(Contract.Result<Lookup>() != null, "Lookups should NEVER be nulll in the CRM platform. Use Lookup.Null instead.");
Contract.Ensures(! Contract.Result<Lookup>().IsNull,
"CIC Queue Contact lookup cannot be Lookup.IsNull");
Contract.Ensures(Contact.Exists(Contract.Result<Lookup>().Value, crmService),
"CIC Queue Contact must exist as a valid CRM contact, but no contact could be found with the id");
Contract.Ensures(Contact.ExistsAndHasEmail(Contract.Result<Lookup>(),crmService),"CIC Queue contact must have an email address but none was found");
#endregion
...
< implementation >
...
return ...;
}

Summary

By using strong postconditions within our custom code, we are able to detect and logic or data errors as early as possible, and report them in a convenient manner that allows quick diagnosis and rapid problem resolution. The lesson for me is to be creative about how you use contracts when you are at the interface between two systems.

You might think it is difficult to anticipate all possible situations. However, in many cases, all you have to do is pay attention to errors that arise during the development process, and use them as indicators of weakness in the software. In our case, the richer post-conditions we implemented were discovered by doing the root cause analysis on errors that arose during our development and unit testing. I suspect that many developers miss opportunities to improve the design and robustness of their software because they overlook errors that arise during development. They may simply think “Oh I see there is a problem. I will correct the underlying code and that will be the end of it.” And in some cases, that may be the correct response. But in other cases, the faults that occur during unit testing may reveal vulnerabilities that will still be present in the production environment in some form. Or they may reveal vulnerabilities in the code that would trip up other programmers who might make changes during the maintenance process.

2 Comments »

  1. […] and overall quality of the custom code portion of this solution.  I wrote previouslyhttps://codecontracts.info/2009/12/18/code-contracts-improve-microsoft-crm-workflow-code-2/  about the exact way in which we apply code contracts to detect and prevent faults, and resolve […]

    Pingback by We use Microsoft Code Contracts in our Microsoft CRM custom code « Software Quality — January 14, 2010 @ 10:06 pm

  2. […] Code Contracts Enhance Systems Integration Filed under: Uncategorized — David Allen @ 11:23 pm Integration of software systems is a challenging job. Our company has several systems that are connected.  I have observed  that adding Microsoft Code Contracts improves the speed of diagnosing problems, and improves the readability of our integration code.  I noticed this when we wrote custom workflow activity code, and installed it within our Microsoft CRM system. I wrote about that in an earlier article. […]

    Pingback by Code Contracts Enhance Systems Integration « Software Quality — March 9, 2010 @ 11:24 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: