Code Contracts – A brilliant way to do validation in your code and even do more
In this post, I will try to introduce Code Contracts – a perfect way to implement, enforce validation and even do more in your code; C#. VB.NET or your language of choice. It is one the tools I keep in my “Development Mentoring Toolkit Bet”.
Fist lets start with the official introduction by “Microsoft Research” (https://research.microsoft.com/en-us/projects/contracts/).
Code Contracts provide a language-agnostic way to express coding assumptions in .NET programs. The contracts take the form of preconditions, post conditions, and object invariants. Contracts act as checked documentation of your external and internal APIs. The contracts are used to improve testing via runtime checking, enable static contract verification, and documentation generation.
Code Contracts bring the advantages of design-by-contract programming to all .NET programming languages.
I will try introduce the Code Contracts with a few examples (the language I have chosen is C# but remember Code Contracts is language-agnostic). We will try to enforce some validation of parameters before the execution of the logic as well as validation of the results after the execution of the code block. We will have write a console application where we utilize a manager class (PowerfulManager) that will act like a business tier object. In this manager class, we will see how to enforce some “contracts”. (To keep things simple, we will not example the console application but as you can easily guess, it will be an application that will create an instance of PowerfulManager and call the related functions.)
The PowerfulManager class will have a public property called UserId. We will first try to enforce that during the initialization of the class, a user id has to be provided which will be of type string. Our first rule will be to make sure that the provided user id parameter is not null or is not empty. Our class code would look something like below:
1: public PowerfulManager(string userId)
2: : this()
3: {
4: if (string.IsNullOrEmpty(userId))
5: {
6: throw new ArgumentException("userId");
7: }
8:
9: this.UserId = userId;
10: }
With Code Contracts, the code above will be transformed into something like below:
1: public PowerfulManager(string userId)
2: : this()
3: {
4: Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(userId), "userId");
5: this.UserId = userId;
6: }
As you can see from the example above, we introduced the rule of userId parameter not being null or empty using the Contract.Requires static function.
Let’s now try to create a function that will take 2 integer parameters and return an integer result. The rules should be something like as follows:
- minValue hould be greater or equal to 0
- maxValue should be greater or equal to 0
- minValue should be smaller than maxValue
- The result should be smaller than maxValue
The original implementation would be something like this:
1: public int DoSomething(int minValue, int maxValue)
2: {
3: if (minValue >= 0)
4: {
5: throw new ArgumentException("minValue");
6: }
7:
8: if (maxValue >= 0)
9: {
10: throw new ArgumentException("minValue");
11: }
12:
13: if (!(minValue < maxValue))
14: {
15: throw new ArgumentException("minValue, maxValue");
16: }
17:
18: var result = maxValue - minValue;
19:
20: if (!(result <= maxValue))
21: {
22: throw new Exception("Something went wrong");
23: }
24:
25: return result;
26: }
Now let’s see how this will can written using the Code Contracts.
1: public int DoSomething(int minValue, int maxValue)
2: {
3: Contract.Requires<ArgumentException>(minValue >= 0);
4: Contract.Requires<ArgumentException>(maxValue >= 0);
5: Contract.Requires<ArgumentException>(minValue < maxValue);
6:
7: Contract.Ensures(Contract.Result<int>() <= maxValue);
8:
9: return maxValue - minValue;
10: }
I believe this is much neater, much more readable. Here we also see the “Contract.Ensures” method (line 7). This call allows us to define what should happen when we are returning from the function. As you can see in the code, we retrieve the value that we are returning using the Contract.Result method and check it against the maxValue.
Let’s now add one more function with the following logic and rules:
- Let the function take two integer parameters and always return –1 after a successful run
- Let’s set the class’s UserId property to “NewUserId”
- As a rule, if we have to throw a BusinessException exception, we have to make sure we undo the UserId property to its old value
- As a rule, when this function completes it’s execution, the UserId should never be null or empty
To simulate different possible scenarios, we will calculate maxValue modulus 4 and perform the following actions according to the value we get:
- If value is 0, work as normal
- If value is 1, throw a new Business Exception exception
- If value is 2, first undo the change to the UserId property, then throw a new BusinessException exception
- If value is 3, set the UserId property’s value to String.Empty
Now this is what the code will look like:
1: public int DoSomethingElse(int minValue, int maxValue)
2: {
3: Contract.EnsuresOnThrow<Exceptions.BusinessException>(Contract.OldValue<string>(this.UserId) == this.UserId, "UserId value is instable");
4: Contract.Ensures(!String.IsNullOrEmpty(this.UserId));
5:
6: var evaluationResult = maxValue % 4;
7:
8: var oldUserIdValue = this.UserId;
9:
10: this.UserId = "NewUserId";
11:
12: if (evaluationResult == 1)
13: {
14: throw new BusinessLogicLayer.Exceptions.BusinessException("Exception occured, I should undo the userId");
15: }
16:
17: if (evaluationResult == 2)
18: {
19: this.UserId = oldUserIdValue;
20: throw new BusinessLogicLayer.Exceptions.BusinessException("Exception occured, I should undo the userId");
21: }
22:
23: if (evaluationResult == 3)
24: {
25: this.UserId = String.Empty;
26: }
27:
28: return -1;
29: }
At like 3, we define a rule saying that if BusinessException is thrown, old value of UserId property should be the same as the current value of UserId (in other words, any changes done to the UserId property should be undone). At Line 4, we define a rule where we say that, no matter what, when the function completes, UserId property should not be null or empty.
I find “Code Contract” fascinating, fun to use and great to experiment with. The examples I have provided above are just simple examples of what you can do with them. If you read the documentation (the documentation is over explanatory), you will see that there are a great number of more functionality provided such as Contract.ForAll, Interface Contracts and Object Invariants.
Object Invariants is a great feature where you can define what conditions that should hold true on each instance of a class whenever that object is visible to a client. Literally, you can enforce the object to be in a “valid” or “good” state. Depending on the feedback, I may try to provide some examples around Object Invariants.
Comments
Anonymous
November 02, 2010
The comment has been removedAnonymous
November 02, 2010
The ugly thing I find aboud Code Contracts, and the reason I wouldn't recommend it to anyone (as a matter of fact, I would recommend against using it) is the fact that it isn't a feature of the framework itself, but rather is some functionality provided by some tools. And there isn't any valid license for VS Express Edition. So bye bye Code Contracts Other than that, yes, it's awesomeAnonymous
November 02, 2010
I see so many CodeContracts articles that always seem to either: not cover the static code analysis; or mistake a compiler error for a static code analysis result. You should REALLY do a follow-up on what the static code analysis does; because it is absolutely brilliant!Anonymous
November 03, 2010
Seems that this is just another wrapper / assert macro. If you don't like if/then blocks, or loop tests at the beginning of your function, you can always wrap it in a function called ValidateParameters (or preferably a more specific name that indicates what kind of validation, or the purpose of the validation). In the old days, you used a comment to indicate your assumptions, but that is worse now since comments don't generate run-time or compile-time errors/warnings.Anonymous
November 03, 2010
It was quite new entity to me and also to few of my friends. I am looking for your new posts on this subject.Anonymous
November 03, 2010
nice........but I think contracts are reducing just the length of the code..Anonymous
November 06, 2010
Thanks all for the comments. From the looks of it, I was not able to give a good and detailed example of what code contracts can do. Once I find some time, I will definitely post a new blog entry around Static Code Analysis – thanks to jonathancd for pointing this out. With static code analysis, I will try to show how you can eliminate some validation errors at compile time.Anonymous
November 12, 2010
@Luis de Santiago - Not true. Code contracts are part of the framework - System.Diagnostics.Contracts It's the static analysis tools you can't use from Express.