Archive for September, 2010

Always write tests

Thursday, September 2nd, 2010

One of the things that stands out about Ruby and Rails developers is that the vast majority obsess over “behaviour-driven-development” (or its similar predecessor “test-driven-development”).

At first glance, this allows a suite of automated tests to be run against your code – the idea being that you have proof that your system does what it is supposed to. Bugs are caught early and, most importantly, a new feature cannot break existing features without you knowing about it.

But there is a much bigger advantage to behaviour-driven-development.

The very act of writing your tests before writing your code clarifies what you are trying to achieve and results in designs and code that are actually simpler – and hence easier to maintain.

I was reminded of this when trying to build a data importer. My colleague wrote a huge piece of code that seemed to work at first. But upon further investigation, it appeared to get some internal references wrong – and as the import took an hour to run, debugging became a pain.

So I started over. I wrote out a series of names for my specification: it should import a single product, it should import all variations of that product, it should import the images for a product, it should update an existing product.

These bullet points are a simple description for what it was supposed to achieve.

I then implemented the first bullet point in code – I took a copy of the import file, stripped out most of the data till I found a relevant piece, loaded that and then called the importer. My test just checked the results and ensured that the results were what was expected. The first run failed – because I didn’t have any code in my importer. But I implemented the simple “import a product” case and the test passed. Then I implemented the second bullet point in code. The first test passed, the second failed. I added the code to get the new test to pass – two passing tests and a very simple piece of code for the importer. Continue till all the tests were implemented – fantastic. The importer worked. But the most important thing – because it was built incrementally, it was simple. Even better, if it did start getting messy I could rewrite and rearrange the code to simplify it – and still be sure it was working as the tests proved it.

Writing the tests does not take much time – in fact it saves time as you have to explain to yourself what you are doing before you begin. But even more importantly, it results in clean, simple code. Which saves even more time (and money) in the long run, as that becomes cheaper to maintain.