lunedì 14 febbraio 2011

Why I like TDD. And I don't use it.

The first time I really understood the meaning of Test First Development (TFD) was like some kind or revelation.
I was already using automated testing, but most of the times the tests were written after the code. The few times I tried to write tests first, well, the result was not so brilliant. A lot of wasted time for some bad testing code. But still I wanted to to understand all the hype around TFD.
So, I continued to try it in some form, and continued to read a lot of technical books and articles about testing.

And I still remember that I was on the train back form work, reading some technical book (I don't remeber exactly, but it was not a book about testing, maybe about Tapestry or Hibernate or some other framework), when I read something that helped me to understand it. Like often happens in those 'bang' moments, after you don't remember exactly what happened (and I don't remember exaclty what I've read), you just understand that you know something more. And I mean, you really 'know', fully understand something.

Anyway, back to the topic...
What I understood was that with test last you are testing what your code does: that the code does what you want it to do correctly. With test first, you are testing that the code that you are going to write does exactly what it's required to do. It's a small but significant difference.
With test last development, you are testing only that your code behaves like you want, but not like the specification wants. And since you already have written the code, sometimes you don't notice that what you code does is NOT exactly what it should do. You know, after you write something it's like a newborn child. And every baby is good to his mam.

But, again, I don't want to explain in details what TFD is. I'm sure that you will find someone on Google (or Bing if you prefer) better than me in explaining that.
I just wanted to say that in that moment I understood the benefits of writing test first. And for some time I tried to do it.
But then I realized that most of the time this wonderful technique cannot be used.

And the reason is simple.
WIth TFD you write tests first to test that your code does what it should do according to the specifications.
But most of the time you don't know it exactly before writing the code, as specifications are just some dim lights far away. The customer doesn't know exactly what he wants, and if he knows, he will surely change his mind soon after the first test.
It's always happened in the projects I've worked, even in the most structured one. And I've worked in a lot of projects in the last years, with teams ranging from 1 (only me) to 30 people.

You end up with some sort of 'waste time to understand specs and write test-waste time to code and understand that maybe you didn't understand the specs so well-change the test and the code-hope that who has to decide (maybe you) really decided this time-change it again-start form the beginning' cycle.

It's not bad, after all everyone says that you have to write and then refactor your code. Good, I like to refactor. But if you refactor just because you didn't know exactly what to do in the first place, and you have to refactor the tests too for that reason, then writing the tests is a waste of time.
You end up to some point whan you have not enough time to refacor the code AND the tests. So you start leaving the tests behind. Maybe you comment them, or just remove some assertions. Or simply delete some of them because the code under test is not there anymore. Anyway, at the end they are not perfectly in sync with the code they should test.

Am I saying that tests are just a waste of time ? Absolutely not. I write as much tests as I can. But not in the early stage of the development.

So, what is my current process these days ?
First I write the code, without any test, according to what was my understanding of the specs. Then, when I have to change it or rewrite it (and I always have to do it in early stages), i don't have to refactor some old and outdated tests. I don't write any test, unless I have to refactor some piece of code that seems quite stable. Are there any bugs ? Probably, but I don't care too much. When some functionality is quite stable and confirmed then I write the most complete test suite that is worth for that code. And not more.

So, just to end up, what I'm saying is that TFD, or even too extensive TLD, for my experience are not to be used in the first stages of a project, when the main architecture and specifications are not clear. You waste a lot of time in writing test code to test functionality that will not see the production stage.

I know this is not probably teh best way to go, but often we have limited resources, and like Bruce Springsteen said:

'Between our dreams and actions lies this world'

1 commento:

twingocerise ha detto...

I agree with you. TDD can be time wasting. I think the big thing about TDD is : make sure you know what you want to do before even start. This is a very good way of making sure you understood. Though, real life may be a bitch as you said. Projects may not have the budget for loads of refactoring and unit test rewriting. So, as usual, matching the environment is always a good way to do things : things are pretty clear and you know what to do ? -> TDD --- if you're still in the POC phase you may bypass tests for business related reasons. Dogmatism kills software development projects and even companies ! I've seen software developers refusing to work if they were not given the time for extensive unit testing. Fair play, they were given the time but by the time they finished their work, key clients moved away to competitors products and the company was left with almost no business, ended up being sold for peanuts.
If you distribute a large product designed to stay for a while, yeah, you NEED to bullet proof every line of code cause people would move away if it was broken. Still, loads of projects can handle some level of brokenness for the sake of time to market. It's all a matter of matching user expectations in terms of pricing, features, quality. Levels to be adjusted on every project. Many developers should get a bit more business-aware...