Introduction
Recently I try to develop a verification framework to reduce the bug in system. And I come to Design by Contract(DbC).
The idea of DbC is indeed great! But, there are still no workable practise now. So I work out one.
Updated 2009-12-02 200400: Many people still don't know what I want to say.. So I refactoring the article.
Background
Design by Contract was first introducted by Bertrand Meyer. You can visit the homepage: Design by Contract, EIFFEL. the guy also develop the Eiffel for DbC.
In dotnet, we also have some talent work on DbC, for example:
Spec#,LinFu. But all of them just try to deveop a new language(spec#), or use AOP(LinFu), or use Attribute(Microsoft...en.). What's the result? Still in the mess.
Why Design by Contract cannot be the main stream in OO, in XP? Because all of them walk to the wrong direction. So... Please take a look on my job.
Using the code
In Design by contract, when we write a method in class, we assume the user should meet the Constraints of the method, then the method would return the committed result. This is DbC. Like the follow code:
public class Log
{
public void Info(string message)
{
}
}
When I want to call Log.Info, the message must be NOT NULL, otherwise, the function would not assume to return the correct result.
Previously, We would try to check the message in Info.
public class Log
{
public void Info(string message)
{
if(string.IsNullorEmpty(message))
throw new Exception("missing message.");
}
}
This is called: Defence Programming. However, if the case become complicated, we would find thousands of defence codes in our business logic. THIS IS REALLY SAD!!!
Updated 2009-12-02:What's happen in .net framework 4.0? take a look at:
microsoft .net 4.0 design by contract
public class Log
{
public void Info(string message)
{
CodeContract.Requires(null != message);
}
}
Now, take a break, and think it twice. Is there any changes to the previous code? Maybe microsoft would said, It is design by contract, when complie the code, we would get the warning...blablabla..
PLEASE STOP LYING TO YOURSELF. If it is really what you think, why not use it everwhere? (Because sometimes we are already sure that the code is correct.) So why there are still many bugs? (Well.. Some mistakes cannot be caught by DbC.) Ok.. Please stop giving any excuse. I tell you the truth.
The ability of computer language is limited, but the requirement of human being is complicated. Microsoft have develop a great tool call .net, and the language call c#. It can meet most of the human requirements, and translate the requirements into machine code. But in design by contract, it is another story.
If we follow the traditional way, whatever kind of technique we use, we would find that the time we spend on writing CONTRACT is as much as we spend on BUSINESS LOGIC. Finally, half of the code is contract. SO that's the reason why we do not accept DbC.
To judge the input parameter is not null, it is very simple. But, if we pass a object? if the object contains another object? If... So, if we still want to write down the contract as computer language(c#/java/ whatever), we are just wasting our time. We need another idea.
Design by Contract do not support Defence Programming.
Unfortunately, even Microsoft still work on Defence Programming.. Please see the Spec#.... SO I try to walk into another way.
First, I set a Constraint on Log.Info
public class Log
{
[Contract.Constraint("message is not null")]
public void Info(string message)
{
}
}
In the code above, I actually do nothing but set a attribute on the method.
Then, I try to call the method, Log.Info, like follow:
public class TestCase
{
public void call001()
{
string message = "hello world";
Log log = new Log();
log.Info(message);
}
}
It work. Right? Of course. So is there something to do with Design by Contract? Be patient, we still do not verify the contract.
public class TestCase
{
public void test001()
{
MethodInfo method = typeof(TestCase).GetMethod("call001");
Console.WriteLine("check the call001 can be approved by contract.");
Console.WriteLine("approval result = :" + Contract.Approval(method));
foreach (IConstraint cons in Contract.GetOpenConstraints(method))
{
Console.WriteLine("the constraint of \"" + cons.ConstraintName + "\" is not committed.");
}
}
public void call001()
{
string message = "hello world";
Log log = new Log();
log.Info(message);
}
}
In Testcase.test001, I use 'Contract.Approval' to verify the method call001. and get the result:
check the call001 can be approved by contract.
approval result = :False
the constraint of "message is not null" is not committed.
It means, the constraint of Log.Info is not committed in call001, so call001 is not a valid method. Now you can feel something about Design by contract.
What to do next? READ THE CONTRACT, and FOLLOWING THE CONTRACT. for example above, we are definitely sure message is not null, then go no next example:
public class TestCase
{
public void test002()
{
MethodInfo method = typeof(TestCase).GetMethod("call002");
Console.WriteLine("check the call002 can be approved by contract.");
Console.WriteLine("approval result = :" + Contract.Approval(method));
foreach (IConstraint cons in Contract.GetOpenConstraints(method))
{
Console.WriteLine("the constraint of \"" + cons.ConstraintName + "\" is not committed.");
}
}
[Contract.Commitment("input of log is not null")]
public void call002()
{
string message = "hello world";
Log log = new Log();
log.Info(message);
}
}
In this case, call002 call the Log.Info, but I set a Contract.Commitment on call002. It is committed that input of log is not null. So When I run test002, I got:
check the call002 can be approved by contract.
approval result = :True
YES!GREAT! PASS! It is what I need! So, now you can understand what I mean.
So.. aha..yes, I do not use machine to verify the constraint. But, instead, I apply Design by Contract on CODING, on 'DESIGN'. This is what I want, and I believe, THIS IS design by contact.
Summary
When problem comes, find the simplest solution. It is the best solution. Design by Contract is not a new Language, not the coding, not some around our code. Design by Contract is a Practise, just like TestDriven.
I believe Design by Contract would become something in XP, and become the friend of TestDriven.
Update 2009-12-02:
Man, we are living by creating, not by copy/paste, not by downloading. Design by contract is a practise. Not a new language, or some attribute/ or AOP.
If some day in future, when we write down a method name: call001(), it use the method in microsoft .net framework 12.0, the method is Log.info
public void call001()
{
string message = "hello world";
Log log = new Log();
log.Info(message);
}
and after complieing the code, VS2020 show me the warning that log.Info have the contract = 'message is not null' that we need to commit, then you would finally understand my work.
Well, typing every single word from my mind is very tired. Hope someone in future can use JUMP THINKING to read my article.