BDD, the A-Ha Moment

I’ve been professionally writing software for almost six years now, aware that testing was something that ought to be done as part of one’s job, but it was only in the past couple of weeks that I really had a solid moment really bringing home to me why Behaviour Driven Development really works.

After a sharp awakening that I just wasn’t doing my job properly (I had checked in some code that only sort-of worked, and had no automated tests verifying to what extent it was broken), I was picking up a new task.  This piece of work was something I had done before.  Not something like it, this exact thing, in a quick hack demonstration model that we threw away, with this being one of the changes we decided to keep.  I knew what to do – I had to delete a bunch of code and it would still work.  I was removing a decision from the user which wasn’t necessary with the improved workflow of the new version.

Partly because I wanted to improve my work ethic to what constitutes basic professionalism in my team, but mainly I was a little angry with myself and exasperated with the person who had shown me in stark reality how I was falling short of my job description.  He is the Tech Lead on the project, and I decided to challenge him – I didn’t know how I could possibly test for a lack of a user interaction without some horribly farcical test.  So I asked his advice on how one might go about TDD’ing a removal of code.  To his credit, after a couple of minutes’ thought, he came back to me and said that the user interaction missing wasn’t something we should be testing, but the decision was still being made – in code.  He and I both knew that our previous version was a race to get something out the door and we had fallen into some of the classic traps, dumping logic directly in with the UI code in the name of speed.  UI code is notorious for wanting to do extra things, like starting an event loop, which is not conducive to automated testing.  We therefore did not have such things around this particular logic.

The Tech Lead said that the best thing to do was to wrap some tests around the logic that would remain; we were removing one of the four possible outcomes and the other three still needed to work.  Then, while we were looking at the code to see how to get started, it quickly became obvious that without the decision dialog in the way, we were free to move this logic to a more appropriate layer.  But where exactly?

I started writing some tests to see that this decision would be made and found it much more difficult than it should have been.  This made me revisit the decision of where I thought it should end up and moved my testing to a different layer.  This too was a dead end.  I think it was only three, but it might have been more attempts at fitting it at the right level.  Still, these were two minute forays at most.  Each test setup showing very quickly the problems at each layer and they were all completely revertable because I hadn’t changed any real code yet!  Then I found it.  The layer at which it all fitted.  Writing the tests became easy and I could do it piece-meal as I slowly removed unwanted code and then moved the method to its rightful position.

I already knew the code worked – we had manually tested it quite thoroughly, so actually asserting correctness wasn’t even at the top of my list of objectives for writing a test.  Although I wasn’t conscious of it at the time, I was writing the test purely so it would guide my design.  This is why the title of the post says BDD, but I referred to TDD earlier.  BDD is the aim to remove the conscious thought of testing for correctness and moving towards asserting that the functionality exists.  In short, it’s a good way of doing TDD properly.

In the end, I spent around an hour in a single session doing something quite straight-forward, which would have taken a similar amount of time had I not let the testing guide my design.  Except that I left the code in a better state, architecturally and didn’t revisit it because I missed something with my human-based testing.

I mention this as my a-ha moment, because it really solidified for me what BDD was all about.  It’s not about having those green ticks appear on your screen, it’s about really becoming the first client of the service you’re writing.  The practice run before unleashing it on real code.  And subsequently I have found the mental battle to test-drive my design (was that pun also intended by the creators of TDD?) has completely melted away.

 

Advertisement

TDD – a better option for developers with ADD

So I’m back on the unit testing kick again.  In my defense, I do spend an awful lot of time thinking about them – either feeling guilty about not writing them, or thinking about them as I code them, then (optimistically making it sound like I write tests first) or thinking about the testability of a particular piece of code as I write it.  They are dear to my heart, in a strange kind of way.  Part of me loathes them – being a pale approximations of actual applications behaviour,  and the rest of me has only ever found them useful.  Either proving my code, having decisions I (or those before me) have made confirmed to be conscious or driving my design.  And that’s what I want to talk about.  Test Driven Development.

I’m fairly convinced that most people don’t have a firm grip on what Test Driven Development is.  Before we begin properly, I’d like to mention that I have actually read the book by Kent Beck.  Including the code examples!

Now that my credentials are clearly proven and sufficient, I’d like to start by saying that test-first and test-driven development are not the same thing. That’s where most people get it wrong. Both are Good Things, but I favour test-driven development for a couple of significant reasons.

Read more of this post