Tuesday, April 17, 2007

Coding Nirvana

Today I experienced the perfection of coding, and I never want to go back to the old hacking method! My FilePath library is nearly ready for release, but just before it went out I got a bug report.

The FilePath library is based on the idea that all functions must satisfy a list of properties, which are documented in the interface. I use QuickCheck to automatically test that these properties hold. This leads to the great situation where there are only two classes of bug:
  • A property is wrong
  • A property is missing
The bug report I received was of the second kind - a property was missing. The next step is to decide if this property should hold or not, and in this case the reporter was perfectly right, this property should hold. Next step is to decide if a more general version of this property should hold - and in discussion with the reporter a more generalised version was formulated. By working at the level of properties the code is no longer the hard part, and while collaborative coding on a single function isn't that useful, collaborative property discussion works really well.

Once the properties have been decided upon, and having left a night to see if anyone had any other thoughts on the properties, the coding can begin. This then makes the process of coding much less hacky, and much more precise:

  1. Write out the properties
  2. Write out code to implement them
  3. If the tests fail, you have a counter example - go back to 2
  4. Done

By the time you get to 4, the code meets the properties. You have already done 1000's of tests (more than 10,000 in FilePath) and can have a fairly strong degree of confidence in the work you have produced. The bug reporter has already agreed with the changes you've made, even before you've made them.

I have never done a library before so focused on properties, but it has had amazing advantages. The advantage of having correct and reliable code may be obvious - but in practice the amount of confidence in the code surprised me. By far the bigger benefit has been collaboration - the very high declarative nature of properties makes them something well suited to "group thought".


Gregor Purdy said...

I followed the link to the FilePath docs. Question: when you say

dropExtension :: FilePath -> FilePath

  Remove last extension, and any . following it.

    dropExtension x == fst (splitExtension x)

shouldn't that be:

dropExtension :: FilePath -> FilePath

  Remove last extension, and the "." preceding it.

    dropExtension x == fst (splitExtension x)

based on the definition of spitExtension?

Neil Mitchell said...

Good catch Gregor! I've updated the documentation, it was just a verbal typo that is beyond the range of QuickCheck

Anonymous said...

This is a well-known (but sadly underused) practice typically referred to as "design by contract". It is a very powerful way to control the quality of a system when quality can be easily expressed in terms of invariants and conditional properties, as you describe.

Unfortunately, it's not really Nirvana - the next cycle of reincarnation involves a project where the quality constraints cannot be fully expressed as a contract ;-)