I hate it as a design technique. It encourages you to write code you don't understand just so that it passes the tests.
For example. You want a function to test if a number is prime. You write the test: 4 is not prime, 5 is prime, 6 is not, 7 is prime, 8 and 9 are not. Now you write a function: n is prime if it is odd. Fails the tests: because it tells you that 9 is prime. You "fix" the code by checking that the number is not dividable by 3, it passes the tests, done.
Instead of writing code to solve a problem, you write tests to model the problem then you write code to pass the tests, there is an extra level of indirection and something may get lost along the way.
The only significant advantage of TDD I can think of is that you can't "forget" to write tests.
In fact, you are almost doing TDD, but missing the final step: Refactor Mercilessly
http://c2.com/xp/RefactorMercilessly.html
TDD directly helps you with interface design, that is how the pieces fit together. It helps you indirectly with the design of your implementations, because it enables this merciless refactoring.
"you write tests to model the problem then you write code to pass the tests"
Exactly! And once you have the code that passes the tests, and have written enough of it to have somewhat decent coverage for the problem-space, you can then refactor the implementation.
That is where you can go wild with your ideas, because you are only making changes to code that is already working and protected by a test-suite.
For example. You want a function to test if a number is prime. You write the test: 4 is not prime, 5 is prime, 6 is not, 7 is prime, 8 and 9 are not. Now you write a function: n is prime if it is odd. Fails the tests: because it tells you that 9 is prime. You "fix" the code by checking that the number is not dividable by 3, it passes the tests, done.
Instead of writing code to solve a problem, you write tests to model the problem then you write code to pass the tests, there is an extra level of indirection and something may get lost along the way.
The only significant advantage of TDD I can think of is that you can't "forget" to write tests.