Design by Contract with Microsoft .Net Code Contract
I have done some talks on different events and summits about Defensive Programming and Design by Contract, last time was at Cornerstone’s Developer Summit 2010. Next time will be at SweNug (Sweden .Net User Group). I decided to write a blog post about of some stuffs I was talking about.
Users are a terrible thing! Protect your self from them
”Human users have a gift for doing the worst possible thing at the worst possible time.” – Michael T. Nygard, Release It!
The kind of users Michael T. Nygard are talking about is the users of a system. We also have users that uses our code, the users I’m going to focus on is the users of our code. Me and you and another developers.
“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” – Martin Fowler
Good programmers also writes code that humans know how to use, good programmers also make sure software behave in a predictable manner despise inputs or user actions.
Design by Contract
Design by Contract (DbC) is a way for us to make a contract
between us (the code writer) and the users of our code. It’s
about “If you give me this, I promise to give you this”.
It’s not about business validations, that is something
completely different that should be part of the domain
model. DbC is to make sure the users of our code uses it in
a correct way, and that we can rely on the contract and
write code in a way where we know that the users will follow
the contract. It will make it much easier for us to write
code with a contract specified. Something like the following
code is something we may see often:
public void DoSomething(Object value) { value.DoIKnowThatICanDoThis(); }
Where “value” can be uses directly or passed to other methods and later be used. What some of us can easily forget here is that the “value” can be “null”. We will probably not passing a null value, but someone else that uses our code maybe will do it. I think most of you (including me) have passed “null” into a method because you don’t know if the argument need to be specified to a valid value etc. I bet most of you also have got the “Null reference exception”. Sometimes this “Null reference exception” can be hard and take time to fix, because we need to search among our code to see where the “null” value was passed in etc. Wouldn’t it be much better if we can as early as possible specify that the value can’t not be null, so the users of our code also know it when the users starts to use our code, and before run time execution of the code? This is where DbC comes into the picture. We can use DbC to specify what we need, and by doing so we can rely on the contract when we write our code. So the code above can actually use the DoIKnowThatICanDoThis() method on the value object without being worried that the “value” can be null. The contract between the users of the code and us writing the code, says that the “value” can’t be null.
Pre- and Postconditions
When working with DbC we are specifying pre- and
postconditions.
Precondition
is a condition that should be met before a query or command
is executed. An example of a precondition is: “The Value
argument of the method can’t be null”, and we make sure the
“value” isn’t null before the method is called.
Postcondition
is a condition that should be met when a command or query is
completed, a postcondition will make sure the result is
correct. An example of a postconditon is “The method will
return a list with at least 1 item”.
Commands an Quires
When using DbC, we need to know what a Command and a
Query is, because some principles that can be good to follow
are based on commands and queries. A Command is something
that will not return anything, like the SQL’s CREATE, UPDATE
and DELETE.
There are two kinds of Commands when using DbC, the Creation
commands (for example a Constructor), and Others. Others can
for example be a Command to add a value to a list, remove or
update a value etc.
//Creation commands public Stack(int size) //Other commands public void Push(object value); public void Remove();
A Query, is something that will return something, for example an Attribute, Property or a Function, like the SQL’s SELECT.
There are two kinds of Queries, the Basic Queries (Quires
that aren’t based on another queries), and the Derived
Queries, queries that is based on another queries. Here is
an example of queries of a Stack:
//Basic Queries public int Count; public object this[int index] { get; } //Derived Queries //Is related to Count Query public bool IsEmpty() { return Count == 0; }
To understand about some principles that are good to follow when using DbC, we need to know about the Commands and different Queries.
The 6 Principles
When working with DbC, it’s advisable to follow some
principles to make it easier to define and use contracts.
The following DbC principles are:
- Separate commands and queries.
- Separate basic queries from derived queries.
- For each derived query, write a postcondition that specifies what result will be returned, in terms of one or more basic queries.
- For each command, write a postcondition that specifies the value of every basic query.
- For every query and command, decide on a suitable precondition.
- Write invariants to define unchanging properties of objects.
Before I will write about each of them I want you to
now that I’m going to use .Net 4.0 Code Contract. I will in
the rest of the post uses a simple
Stack
(Yes I know, .Net already have a Stack class) to give you
the basic understanding about using DbC. A Stack is a data
structure where the last item in, will be the first item
out. Here is a basic implementation of a Stack where not
contract is specified yet:
public class Stack { private object[] _array; //Basic Queries public uint Count; public object this[uint index] { get { return _array[index]; } set { _array[index] = value; } } //Derived Queries //Is related to Count Query public bool IsEmpty() { return Count == 0; } //Is related to Count and this[] Query public object Top() { return this[Count]; } //Creation commands public Stack(uint size) { Count = 0; _array = new object[size]; } //Other commands public void Push(object value) { this[++Count] = value; } public void Remove() { this[Count] = null; Count--; } }
Note: The Stack is implemented in a way to demonstrate the use of Code Contract in a simple way, the implementation may not look like how you would implement it, so don’t think this is the perfect Stack implementation, only used for demonstration.
Before I will go deeper into the principles I will simply mention how we can use the .Net Code Contract.
I mention before about pre- and postcondition, is about
“Require” something and to “Ensure” something. When using
Code Contract, we will use a static class called “Contract”
and is located in he “System.Diagnostics.Contracts”
namespace. The contract must be specified at the top or our
member statement block. To specify a precondition with Code
Contract we uses the Contract.Requires method, and to
specify a postcondition, we uses the Contract.Ensure method.
Here is an example where both a pre- and postcondition are
used:
public object Top() { Contract.Requires(Count > 0, "Stack is empty"); Contract.Ensures(Contract.Result<object>() == this[Count]); return this[Count]; }
The contract above requires that the Count is greater than 0, if not we can’t get the item at the Top of a Stack. We also Ensures that the results (By using the Contract.Result method, we can specify a postcondition that will check if the value returned from a method is correct) of the Top query is equal to this[Count].
1. Separate Commands and Queries
When working with DbC, it’s important to
separate Command and Quires. A method should either be a command that performs an
Action, or returning information to the caller, not both. By
asking a question the answer shouldn’t be changed. The
following is an example of a Command and a Query of a Stack:
public void Push(object value) public object Top()
The Push is a command and will not return anything, just add a value to the Stack, the Top is a query to get the item at the top of the stack.
2. Separate basic queries from derived queries
There are two different kinds of queries, the basic
queries that doesn’t rely on another queries, and derived
queries that uses a basic query. The “Separate basic queries
from derived queries” principle is about about that derived
queries can be specified in terms of basic queries. So this
principles is more about recognizing that a query is a
derived query or a basic query. It will then make is much
easier to follow the other principles. The following code
shows a basic query and a derived query:
//Basic Queries public uint Count; //Derived Queries //Is related to Count Query public bool IsEmpty() { return Count == 0; }
We can see that IsEmpty will use the Count query, and that makes the IsEmpty a Derived query.
3. For each derived query, write a postcondition that specifies what result will be returned, in terms of one or more basic queries.
When the derived query is recognize we can follow the 3ed
principle. For each derived query, we can create a
postcondition that specifies what result our derived query
will return in terms of one or more basic queries. Remember
that DbC is about contracts between the users of the code
and us writing the code. So we can’t use demand that the
users will pass in a valid value, we must also ensure that
we will give the users what the users wants, when the user
is following our contract. The IsEmpty query of the Stack
will use a Count query and that will make the IsEmpty a
Derived query, so we should now write a postcondition that
specified what results will be returned, in terms of using a
basic query and in this case the Count query,
//Basic Queries public uint Count; //Derived Queries public bool IsEmpty() { Contract.Ensures(Contract.Result<bool>() == (Count == 0)); return Count == 0; }
The Contract.Ensures is used to create a postcondition. The
above code will make sure that the results of the IsEmpty
(by using the Contract.Result to get the result of the
IsEmpty method) is correct, that will say that the IsEmpty
will be either true or false based on Count is equal to 0 or
not. The postcondition are using a basic query, so the
IsEmpty is now following the 3ed principle. We also have
another Derived Query, the Top query, it will also need a
postcondition and it uses all basic queries. The Result of
the Top method must be the same value as the this[] query
returns.
//Basic Queries public uint Count; public object this[uint index] { get { return _array[index]; } set { _array[index] = value; } } //Derived Queries //Is related to Count and this[] Query public object Top() { Contract.Ensures(Contract.Result<object>() == this[Count]); return this[Count]; }
4. For each command, write a postcondition that specifies the value of every basic query.
For each command we will create a postconditon that specifies the value of basic queries. If we look at the Stack implementation we will have three Commands, one Creation command, the Constructor, and two others commands, Push and Remove. Those commands need a postcondition and they should include basic query to follow the 4th principle.
//Creation commands public Stack(uint size) {
Contract.Ensures(Count == 0); Count = 0; _array = new object[size]; } //Other commands public void Push(object value) { Contract.Ensures(Count == Contract.OldValue<uint>(Count) + 1); Contract.Ensures(this[Count] == value); this[++Count] = value; } public void Remove() { Contract.Ensures(Count == Contract.OldValue<uint>(Count) - 1); this[Count] = null; Count--; }
As you can see the Create command will Ensures that Count will be 0 when the Stack is created, when a Stack is created there shouldn’t be any items in the stack. The Push command will take a value and put it into the Stack, when an item is pushed into the Stack, the Count need to be increased to know the number of items added to the Stack, and we must also make sure the item is really added to the Stack. The postconditon of the Push method will make sure the that old value of the Count (by using the Contract.OldValue we can get the value a Query has before the method is called) plus 1 will be equal to the Count query, this is the way we can ensure that the Push will increase the Count with one. We also make sure the this[] query will now contain the item we pushed into the Stack. The Remove method must make sure the Count is decreased by one when the top item is removed from the Stack. The Commands is now following the 4th principle, where each command now have a postcondition that used the value of basic queries.
Note: The principle says every basic Query, the Remove only used one Query the Count, it’s because this command can’t use the this[] query because an item is removed, so the only way to make sure an item is removed is to just use the Count query, so the Remove will still follow the principle.
5. For every query and command, decide on a suitable precondition.
We have now focused only on postcondition, now time for some
preconditons. The 5th principle is about deciding a suitable
preconditon for every query and command. If we starts to
look at one of our basic queries (will not go through all
Queries and commands here, just some of them) the this[]
query, we can’t pass an index that is lower then 1 (.Net
arrays and list are zero based, but not the stack in this
blog post ;)) and the index can’t be lesser than the number
of items in the stack. So here we will need a preconditon.
public object this[uint index] { get { Contract.Requires(index >= 1); Contract.Requires(index <= Count); return _array[index]; } }
Think about the Contract as an documentation about how to use the code in a correct way, so if the contract could be specified elsewhere (not part of the method body), we could simply write “return _array[index]” and there is no need to check if index is greater or lesser than Count, because that is specified in a “contract”. The implementation of Code Contract, requires that the contract is specified in the code. As a developer I would rather have this contract elsewhere (Like Spec#) or implemented in a way Eiffel uses it as part of the language.
Now when we have looked at one Query, we can also look at
one command, the Remove command (You can see the whole
implementation of the Stack at the end of this blog post,
where precondition is added to more queries and commands
then what I’m going to show in this section). We can only
Remove an item if the Count is greater than 0. So we can
write a precondition that will require that Count must be
greater than 0.
public void Remove() { Contract.Requires(Count > 0); Contract.Ensures(Count == Contract.OldValue<uint>(Count) - 1); this[Count] = null; Count--; }
6. Write invariants to define unchanging properties of objects.
The last principle is about making sure the object are feeling great! This is done by using invariants. When using Code Contract we can specify invariants by adding a method with the attribute ContractInvariantMethod, the method must be private or public and can only contains calls to Contract.Invariant. To make sure the Stack feels great, the Stack must have 0 or more items, the Count can’t never be a negative value to make sure each command and queries can be used of the Stack. Here is our invariant for the Stack object:
[ContractInvariantMethod] private void ObjectInvariant() { Contract.Invariant(Count >= 0); }
Note: The ObjectInvariant method will be called every time after a Query or Commands is called.
Here is the full example using Code Contract:
public class Stack { private object[] _array; //Basic Queries public uint Count; public object this[uint index] { get { Contract.Requires(index >= 1); Contract.Requires(index <= Count);
return _array[index]; } set { Contract.Requires(index >= 1); Contract.Requires(index <= Count); _array[index] = value; } } //Derived Queries //Is related to Count Query public bool IsEmpty() { Contract.Ensures(Contract.Result<bool>() == (Count == 0)); return Count == 0; } //Is related to Count and this[] Query public object Top() { Contract.Requires(Count > 0, "Stack is empty"); Contract.Ensures(Contract.Result<object>() == this[Count]); return this[Count]; } //Creation commands
public Stack(uint size) { Contract.Requires(size > 0); Contract.Ensures(Count == 0); Count = 0; _array = new object[size]; } //Other commands public void Push(object value) { Contract.Requires(value != null); Contract.Ensures(Count == Contract.OldValue<uint>(Count) + 1); Contract.Ensures(this[Count] == value); this[++Count] = value; } public void Remove() { Contract.Requires(Count > 0); Contract.Ensures(Count == Contract.OldValue<uint>(Count) - 1); this[Count] = null; Count--; } [ContractInvariantMethod] private void ObjectInvariant() { Contract.Invariant(Count >= 0); } }
Summary
By using Design By Contract we can make sure the users
are using our code in a correct way, and we must also make
sure the users will get the expected results when they uses
our code. This can be done by specifying contracts. To make
it easy to use Design By Contract, some principles may be
good to follow like the separation of commands an queries.
With .Net 4.0 we can use the Code Contract feature to
specify contracts.