TDD: Good Idea... or Great Idea?!

I originally posted this on my team's blog, but once again I'm cross-posting it here as well due to its relevance.

I bet that if you ask programming job applicants what their thoughts on automated testing are, the vast majority will say it's a good thing. Yet, like most of the development shops I've worked for over the years, we aren't always afforded the time to write automated tests. Most of the time, we only have ourselves to blame for this: Who creates the project estimate? Who creates the project plan? We do! So we should plan additional time for them... But I will admit that while I personally have written tests for some of my personal and professional projects, they are few enough and far enough between that testing still isn't quite second nature for me; and I probably spend more time writing my tests and mocks than someone who does 100% Test Driven Development.

I know you already believe in automated testing, but I'll continue just in case there's a non-believer reading over your shoulder. TDD slows you down (less when you're an experienced, disciplined TDD'er)... there's no doubt. Writing tests is almost as counter-productive for the initial development period of the application as checking your Facebook page, your Twitter feed, and your G+ stream, before taking a long lunch. Even for that parenthetical TDD Ninja. Where TDD saves you mountains of time is in refactoring.

Refactoring

A significant number of refactorings are fairly simple; limited to one or two files and maybe a couple of dozen lines of code changed. But we've all been here: What about that change that you were expecting dreading the client would request, that takes you two days to complete, and touches dozens of files, and hundreds of lines of code? Sure... you know that what you just spent two days agonizing over works pretty well. But did you break anything?

If you have tests, you just push a button, go get some coffee, and come back to find out what, if anything broke. Effectively it costs you zero time, and you can either publish your flawless refactored code or, perhaps a touch more realistically, get to work fixing the bits that you broke.

Without tests? Best case? You spend a few hours poking around, trying to remember all of the things this app does, seeing if it still does them correctly. If you're lucky, it's only been a year since you last thought about this application. You might find some or most of the bugs you've introduced, but the more code you've changed, the more likely it is you'll miss something.

Case in Point

I just finished writing some mocks that the tests for the authentication and registration module use to verify different response scenarios from the remote authentication and permissions API without actually interacting with the remote API. I realized pretty early in the process of coding the module that it would need to use a façade to make the mocking easier, and this was something we had done with another module that used the same remote API -- but unfortunately we were a little short-sighted and that façade was specific to the module that was using it, not the API it was wrapping. Since my new functionality was somewhat complex, I decided to take on the short-term technical debt of simply creating another module-specific façade, and get it working, so that my coworkers weren't waiting on me for too long. After finishing the functionality and the tests passed, I knew had two jobs to tackle:

  • Add in the mock so that the remote API was not a dependency for the tests
  • Refactor the new façade I created for my module and the other module-specific façade into one API-wrapper façade

The change spanned 8 files and affected hundreds of lines of code. And when I was done, luckily, only one test was now failing. Instead of turning more of my hair gray and wondering how much code is broken that I don't know about, I can say with near certainty none is. I love TDD.

My new Rule of Thumb

Of course TDD (and automated testing in general) is a great thing to have for your average project; I don't think anyone would argue that point. But a lesson I've learned this month is that automated testing is particularly necessary when writing an application that uses ORM. Time and time again I've made what seems to be a tiny, innocuous change to my ORM configuration, and all of a sudden I've got 6, or 8, or 11 failing tests. Entirely my fault, of course; but the point is that what seems like a trivial change to ORM configuration can have nuanced effects on lots of existing code.

So I've got a new rule of thumb: Don't write an ORM-backed application without automated tests.

in Best Practices | Hibernate Posted 2011-08-22 03:03

0 responses:

Leave a comment:

Leave this field empty: