Sunday, July 22, 2007

My Journey to Behaviour Driven Development

So, I have busy the last couple of weeks hacking away at a pretty large model. It is the primary model used for the entire Time Keeping module in my application, and as such, it needs to contain some significant domain logic.

Initially, in the spirit of having proper testing, I was attempting to use Test::Unit as my testing framework. However, having experienced unit testing in Java, in particular a continuous testing plugin that monitors your project in real-time and indicates failing tests almost immediately, I was compelled to search for the same type of responsive environment while developing in Rails.

The first stop on my journey towards continuous testing took me to the Autotest plugin. This plugin was quite useful in that it monitored your source files, and on each save, it ran the tests (be they functional, unit or otherwise) that may possibly have been affected by your recent changes. And to some extent, this worked... after a few seconds of saving a file, the corresponding tests would run, showing the results in the Test::Unit GUI provided in the RadRails IDE.

Those few seconds of waiting bothered me though. Because of that wait, my development process just felt slower. I felt more anxiety to write a series of tests, rather than one at a time since I could spread that time delay over a larger chunk of development effort. but, it felt 'wrong' to rush ahead too far, since the spirit of unit testing, and specifically Test Driven Development, is to write a test, watch it fail, write just enough to make it pass, and repeat. Writing too many tests at once seemed to go against the spirit.

And so, I began another search... this time to find a way to speed up the time it took for Test::Unit to do its thing. And then I ran across RSpec. In my search, this RSpec project kept coming up...

So, I looked at RSpec... and cringed. I did not want to learn a whole new DSL... a whole new syntax... I just wanted to make my tests run faster. But every search for faster testing seemed to always throw this RSpec system in my face.

Finally, I had enough. I re-directed my research to RSpec, and the accompanying Behaviour Driven Development (aka BDD). I can't say that first (or second or even third) impressions left much of a mark, except for the fact that persons mentioned that the RSpec runner launched faster than Test::Unit.

So, I took the dive, and began using RSpec. And as I got more and more comfortable, I have realised that it has totally changed the way I think about my problems. I am not trying to be dramatic for the sake of drama. But my statement still holds... RSpec changed how I thought about my programming problems.

Typically, when thinking about a problem, I would think about the solution. I would envision how the code for a particular method would work, and then mentally test my proposed solution to see how it stood up. If satisfied, i would begin implementing that solution in code... filling in the blanks that my mind couldn't see. If I weren't satisfied, I would adjust my solution, and 're-test it' again. That was my essential programming technique for small-scale problem-solving.

Analysing my thinking process now though, I realise that now, my first step is to think about the specification of how the method would work. When thinking about the problem, I think of how that method should respond in various solutions. Although I do sometimes think about the actual solution, my focus while thinking is now almost totally on specifying how the solution should work in given scenarios.

The funny thing is that, with proper specifications, the solution, i.e. the internal code of the method, usually becomes obvious.

In other words, the general flow moves away from me trying to come up with tests to verify that some piece of code I am considering towards trying to put into words what that code should do, and then writing the code to comply with those specs.

The funny thing is, the outward difference between BDD and TDD is really non-existent beyond the syntax. However, I realise that BDD, by changing the language that is used, drives you more quickly to the aim of the game.... to develop an executable set of specifications for your code, which also serves as a low-level regression test suite.


PS. I still find that RSpec takes too long to respond to file changes when using the Autotest plugin. However, because of the difference in focus, I tend to write a series of specifications for a small aspect of functionality, and use the resulting error messages to guide me in developing the solution code.

I still would like to find a way to increase the responsiveness of the Autotest... but that's a problem for another day

No comments: