I've previously discussed the benefits of the under-appreciated technique Design by Contract. I've found a(nother) great spot where it's usefulness shines while using MonoRail's SmartDispatcherController. This convenient controller performs automatic parameter binding between a form and its controller. For example, suppose you're adding a new Customer to your application via a web form; when you submit the form, it'll automatically collate the field inputs into a Customer instance and pass it as a single object to the method handling the submission. SmartDispatcherController uses reflection to determine which field values should be bound to which controller-method parameters. This goes back to the wise (and convenient) idea of coding to convention over configuration.
One drawback to convention over configuration within SmartDispatcherController, and in other convention over configuration scenarios, is that if a parameter is mis-named in a method, then a default value of null (or a primitive's default value) will be passed to it. The following code demonstrates...
Within my Brail view:
${HtmlHelper.LinkTo(
'Delete Something',
'ManageSomethings', 'Delete', item.Id)}
Within my ManageSomethings SmartDispatcherController:
public void Delete(int somethingId) {
Something.Find(somethingId).Delete();
...
}
There's a subtle problem in the above code. An HtmlHelper.LinkTo will pass an object id with a parameter name of "id" but I've told my method to expect a parameter of "somethingId." Since there's a mismatch, somethingId will always be 0.
Don't get me wrong, I understand that this is trivial to fix and will be trivial to discover...the first time. There are many occasions when you're fiddling with parameters or form inputs and a simple mismatch may be introduced. If not discovered immediately, subtle bugs such as this can become real headaches to pin down and lead to middle-of-the-night "holy shnikies, my site's acting weird" phone calls. That's where Design-by-Contract (DbC) comes into play. (If you haven't been introduced to it, please read my previous post on the subject.)
With a DbC framework, you can enforce this convention over configuration by adding pre-conditions to methods which will be automatically bound. (In my opinion, every non-private method throughout your code that accepts parameters should be using DbC to protect themselves...but I digress.) The previous code, now with the DbC pre-condition, looks as follows:
public void Delete(int id) {
Check.Require(id > 0, "id must be > 0");
Something.Find(id).Delete();
...
}
You'll notice that DbC helped me to see the errors of my way, prompting me to change "somethingId" to "id," accordingly. Little checks like this, all over your code, take almost no time to write but can save loads of time banging your head against a wall. As we continue moving towards more dynamic languages, techniques such as Design-by-Contract become more and more critical for building stable, maintainable applications.
Billy McCafferty
Posted
10-04-2007 4:32 PM
by
Billy McCafferty