Design by contract
Thursday, December 6th, 2007Well, just wanted to point out the existence of it but there is no need rewrite a perfectly written post so read it, NOW!
Well, just wanted to point out the existence of it but there is no need rewrite a perfectly written post so read it, NOW!
This post is based on this post, which is a great post in my opinion and since it already exists I didn’t see the need to rewrite the post so I suggest you go read it first.
The stuff that I am going to add are few observations I have and small implementation enhancement that I think helps the implementation to be even more intuitive.
First, a small overview.
Say you have a class User who has a name, country of residence and a birth date.
It makes sense that you have something like:
if (user.CountryOfResidence == Country.Chad || user.CountryOfResidence == Country.Sudan) { // Do something… }
This code performs some special logic for a user that is coming from Africa and from a country that exists in our system. There is a good chance that code such as this condition is duplicated in a UI page and in a business logic service and maybe in some more places throughout the application. The problems with this are:
Unless the developer who wrote the code added documentation that states it checks that a user came from Africa, we can only guess what it means. It might just be a list of countries for all we know… You might say that it can be placed in a local private method like
if (IsUserFromAfrica(user)) { // Do something }
so now it describes what it means but this still doesn’t solve the code duplication problem. What if now Angola is supported as an African country as well? You will still have to go and change all the occurrences of the condition whether it is inline or wrapped in a method.
By using the Specification Pattern the code will be transformed to this:
if (new UserFromAfricaSpecification().IsSatisfiedBy(user)) { // Do something… }
Where UserFromAfricaSpecification is implemented like this:
public class UserFromAfricaSpecification : Specification<User> { public override bool IsSatisfiedBy(User obj) { return obj.CountryOfResidence == Country.Chad || obj.CountryOfResidence == Country.Sudan; } }
The base class Specification
By working with specifications like that, we get documented, reusable and independently testable "libraries" of specifications.
Since conditions usually are business rules, which are always difficult to maintain and manage, the specification pattern comes very handy and this is the one thing I like the most about it.
As I wrote before, this post shows how the code is built. The code sample attached to my post is almost identical to the code there. The difference is mostly in one detail - specification composition can be performed using the & and | operators, and the ! operator is also available. This means that you can write a specification like this:
if ((new UserOlderThanSpecification(18) & (!new UserFromAfricaSpecification())).IsSatisfiedBy(user)) { // Do something… }
Another use of the specification pattern is to define what we are looking for. The signature of the IsSatisfiedBy method matches the Predicate delegate signature and therefore can be used by the ForEach method of Array or List<> when looking for, say, a user who satisfies a certain condition:
List<User> africanUsers = allUsers.FindAll( new UserFromAfricaSpecification().IsSatisfiedBy);
where allUsers is of type List
What I still don’t like about the current implementation is the fact the the new keyword is used to instantiate a specification instance. I have few ideas about that so expect a follow-up.
The example code for this post is here.
This post is based on two facts about C#:
1) An operator is a method. It is a static method that receives 1 or 2 parameters, depends on the operator and returns a value.
2) The return value can be anything you want it to be. Usually the operator == returns a boolean, but it can return any other data type.
The example I will show is about searching for a value in a generic list.
The .net generic list has a method called FindIndex with the following signature:
public int FindIndex(Predicatematch);
Predicate
int indexOfUserToLookFor = usersList.FindIndex(delegate(User u) { return u.FirstName == userToLookFor.FirstName && u.LastName == userToLookFor.LastName; });
where usersList is defined as List
int indexOfUserToLookFor = usersList.FindIndex(Where.User == userToLookFor);
would be much nicer and certainly more readable.
In order to enable such syntax, the two fact about operator overloading mentioned above come to play. The code:
public class UserQuery { public static Predicate<User> operator == (UserQuery ignored, User other) { return new Predicate<User>(delegate(User u) { return u.FirstName == other.FirstName && u.LastName == other.LastName; }); } … }
does the trick. What this code means, is that when the operator == is used for object of type UserQuery (left hand side) and User (right hand side), return a Predicate
The Where in the phrase ‘Where.User == userToLookFor’ is just for nicer syntax. It is implemented simply as:
public static class Where { public static UserQuery User { get { return new User.UserQuery(); } } }
This post was inspired by the code generated using the NHibernate Query Generator which uses this technic extensively. For an example of code by the NQG look here.
The complete code example for this post can be downloaded here