views:

169

answers:

10

Hello!

I know that TDD helps a lot and I like this method of development when you first create a test and then implement the functionality. It is very clear and correct way.

But due to some flavour of my projects it often happens that when I start to develop some module I know very little about what I want and how it will look at the end. The requirements appear as I develop, there may be 2 or 3 iterations when I delete all or part of the old code and write new.

I see two problems: 1. I want to see the result as soon as possible to understand are my ideas right or wrong. Unit tests slow down this process. So it often happens that I write unit tests after the code is finished what is known to be a bad pattern. 2. If I first write the tests I need to rewrite not only the code twice or more times but also the tests. It takes much time.

Could someone please tell me how can TDD be applied in such situation?

Thanks in advance!

+9  A: 

I want to see the result as soon as possible to understand are my ideas right or wrong. Unit tests slow down this process.

I disagree. Unit tests and TDD can often speed up getting results because they force you to concentrate on the results rather than implementing tons of code that you might never need. It also allows you to run the different parts of your code as you write them so you can constantly see what results you are getting, rather than having to wait until your entire program is finished.

Mark Byers
+3  A: 

TDD helps you to express the intent of your code. This means that writing the test, you have to say what you expect from your code. How your expectations are fulfilled is then secondary (this is the implementation). Ask yourself the question: "What is more important, the implementation, or what the provided functionality is?" If it is the implementation, then you don't have to write the tests. If it is the functionality provided then writing the tests first will help you with this.

Another valuable thing is that by TDD, you will not implement functionality that will not be needed. You only write code that needs to satisfy the intent. This is also called YAGNI (You aint gonna need it).

lewap
+6  A: 

I find that TDD works particularly well in this kind of situation; in fact, I would say that having unclear and/or changing requirements is actually very common.

I find that the best uses of TDD is ensuring that your code is doing what you expect it to do. When you're writing any code, you should know what you want it to do, whether the requirements are clear or not. The strength of TDD here is that if there is a change in the requirements, you can simply change one or more of your unit tests to reflect the changed requirements, and then update your code while being sure that you're not breaking other (unchanged) functionality.

I think that one thing that trips up a lot of people with TDD is the assumption that all tests need to be written ahead of time. I think it's more effective to use the rule of thumb that you never write any implementation code while all of your tests are passing; this simply ensures that all code is covered, while also ensuring that you're checking that all code does what you want it to do without worrying about writing all your tests up front.

gab
A: 

In this early prototype-phase I find it to be enough to write testable code. That is, when you write your code, think of how to make it possible to test, but for now, focus on the code itself and not the tests.

You should have the tests in place when you commit something though.

Christian
TDD is a practice that enables you to flesh out the requirements. By focussing on the tests you develop testable code that implements the features you require.
Seb Rose
A: 

Here's a blog post I found potent in explaining the use of TDD on a very iterative design process scale: http://blog.extracheese.org/2009/11/how%5Fi%5Fstarted%5Ftdd.html.

djc
+1  A: 

Using TDD could actually make you write code faster - not being able to write a test for a specific scenario could mean that there is an issue in the requirements.
When you TDD you should find these problematic places faster instead of after writing 80% of your code.

There are a few things you can do to make your tests more resistant to change:

  1. You should try to reuse code inside your tests in a form of factory methods that creates your test objects along with verify methods that checks the test result. This way if some major behavior change occurs in your code you have less code to change in your test.

  2. Use IoC container instead of passing arguments to your main classes - again if the method signature changes you do not need to change all of your tests.

  3. Make your unit tests short and Isolated - each test should check only one aspect of your code and use Mocking/Isolation framework to make the test independent of external objects.

  4. Test and write code for only the required feature (YAGNI). Try to ask yourself what value my customer will receive from the code I'm writing. Don't create overcomplicated architecture instead create the needed functionality piece by piece while refactoring your code as you go.

Dror Helper
+2  A: 

There's no getting away from it - if you're measuring how long it takes to code just by how long it takes you to write classes, etc, then it'll take longer with TDD. If you're experienced it'll add about 15%, if you're new it'll take at least 60% longer if not more.

BUT, overall you'll be quicker. Why?

  • by writing a test first you're specifying what you want and delivering just that and nothing more - hence saving time writing unused code
  • without tests, you might think that the results are so obvious that what you've done is correct - when it isn't. Tests demonstrate that what you've done is correct.
  • you will get faster feedback from automated tests than by doing manual testing
  • with manual testing the time taken to test everything as your application grows increases rapidly - which means you'll stop doing it
  • with manual tests it's easy to make mistakes and 'see' something passing when it isn't, this is especially true if you're running them again and again and again
  • (good) unit tests give you a second client to your code which often highlights design problems that you might miss otherwise

Add all this up and if you measure from inception to delivery and TDD is much, much faster - you get fewer defects, you're taking fewer risks, you progress at a steady rate (which makes estimation easier) and the list goes on.

TDD will make you faster, no question, but it isn't easy and you should allow yourself some space to learn and not get disheartened if initially it seems slower.

Finally you should look at some techniques from BDD to enhance what you're doing with TDD. Begin with the feature you want to implement and drive down into the code from there by pulling out stories and then scenarios. Concentrate on implementing your solution scenario by scenario in thin vertical slices. Doing this will help clarify the requirements.

FinnNk
+2  A: 

IMHO, your main problem is when you have to delete some code. This is waste and this is what shall be addressed first.

Perhaps you could prototype, or utilize "spike solutions" to validate the requirements and your ideas then apply TDD on the real code, once the requirements are stable.

The risk is to apply this and to have to ship the prototype.

Also you could test-drive the "sunny path" first and only implement the remaining such as error handling ... after the requirements have been pinned down. However the second phase of the implementation will be less motivating.

What development process are you using ? It sounds agile as you're having iterations, but not in an environment that fully supports it.

philippe
+1 for mentioning spikes - that was my first thought as well.
TrueWill
I love deleting code. It means I've simplified the code I'm working on.
kyoryu
A: 

Joshua Block commented on something similar in the book "Coders at work". His advice was to write examples of how the API would be used (about a page in length). Then think about the examples and the API a lot and refactor the API. Then write the specification and the unit tests. Be prepared, however, to refactor the API and rewrite the spec as you implement the API.

Steve Emmerson
A: 

TDD will, for just about anybody, slow down initial development. So, if initial development speed is 10 on a 1-10 scale, with TDD you might get around an 8 if you're proficient.

It's the development after that point that gets interesting. As projects get larger, development efficiency typically drops - often to 3 on the same scale. With TDD, it's very possible to still stay in the 7-8 range.

Look up "technical debt" for a good read. As far as I'm concerned, any code without unit tests is effectively technical debt.

kyoryu