Recently, I was involved in a discussion with a colleague of mine that was focused around TDD – Test-Driven Development.
During the discussion he mentioned that he personally finds the process of coding up the method first and test later to be easier, natural and more efficient. Writing the test-first just seems more difficult to do and less efficient. He then went on to state his reasons:
He said, and I agree with him here, it’s probably easier and feels natural because that’s the way he has always programmed. Create functionality and then test that functionality. TDD flips that around and as result you have to “re-learn” development. Something he wouldn’t mind doing, expect that…
In his opinion, TDD is a slower way to code. Here is his reasoning: A great majority of the time, you’re going to change the code that you wrote to begin with – you will rename the class or method, move things around, change the number of parameters or throw away the first attempt and start again. If you were to write the tests first then those tests would have to change as well! As a result, you’re increasing the amount of effort involved. It’s much faster to just write the test after the code has been finalized.
Until a year ago, those were my thoughts exactly. Then one day (well, probably more like over a period of several months, several books and several articles) I finally found the missing piece to the puzzle. The piece that made TDD possible for me without causing me spend countless hours making significant changes to my test cases because I would keep making significant changes to my code-base. I realized what TDD actually states. Which is: Do NOT write a single piece of production-code before first writing a test for it. And there it is, the missing piece to the puzzle – production-code!
Ah ha, I said! I finally get it! In other words, if you’re unsure how about the solution is going to look like or work – write non-production code first to work out ideas, fill-in the gaps in requirements, get your questions answered, and get a feel for what the overall solution will look like. Then and only then are you ready to write production-code!
Here is the process I now follow during the development:
1. Write a spike or POC code to “brainstorm” what the solution might look like. Sometimes I spend quite a bit of time here. Since in the brainstorming process you’ll find out gaps in requirments or will have to go research the third-party product that you’re planning use.
2. Once you’ve got a good grip on what the overall solution might look like and how it’s going to work, I throw away the spike (or at least put it out of sight).
3. I then write a failing test case.
4. Write code to make it pass.
5. Back to Step 1 if I am unclear on what the next piece of functionality entails; otherwise, Back to Step 3.
So I mentioned that to him and he sort of agreed but not really. He was sort of on the fence. After further discussion we hit upon another point on why to follow TDD that really hit home for him. Here is the example I gave him:
Consider the following: You’ve got X number of test cases in place for a piece of existing functionality. All of the tests pass and everything is working just fine. Then you get a change request. You make the change and then run all the tests. They all pass. Are you done? It’s a little difficult to say, isn’t it? Somewhat open to interpretation. I’ve come across developers who think that they are done at this point because they didn’t break any existing tests. But they forgot to ask – have I added a test for the new change that I made?
On the other hand, if we were to first write a failing test for the change request then there would be no debate on whether or not a test is needed. This where TDD really shines and ensures that we’ve got tests for all of the functionality. When pressure creeps in, and this is especially true for change requests, then the discipline to add tests after the fact even when all of the existing tests are passing becomes very hard to follow-through on.
Sorry for the long-winded ranting. Hopefully you got something out of it.



This is a good point – especially the last example. However, I see very important aspects of TDD even during the initial development. Especially, putting yourself in a user position of your own code by writing your test first, and preventing speculatively overcomplicating your design…
Nice post, Nazir, thank you.
TDD is a methodological smell.
What you’re describing in your post is the normal way of writing code for a reason: writing all code (not just “production” code) is faster when you write the code, run it to see that it works and then – only then – write the tests.
Writing tests for code when you’re not sure that the code works is a bit silly: if it doesn’t work, then you’ve to change both code and tests.
Writing tests for code that works when you run it at least gives you a little more confidence that you haven’t wasted your time writing both code and tests.
There are those who say that TDD is about design, not tests; but that changes absolutely nothing. If you write tests first, this will ensure that the code you write is testable; nothing else. If it doesn’t give you the desired result, then you’ve got tests and testable code that you’ve to delete: you waste precisely the same about of time to deleting tested wrong code as untest wrong code. The only difference is that with TDD, you’ve also wasted your time writing useless tests.
That TDD is a methogological smell is shown by the amount of people who move from writing code first, to writing tests first, and then back to writing code first.
TDD just shows that you’ve not matured yet.
@Bob:
Thanks for your comment! I have no choice but to offer a counter-argument:
“That TDD is a methogological smell is shown by the amount of people who move from writing code first, to writing tests first, and then back to writing code first.”
Do you have some data to back that up or is that just your personal belief?
Here are some links that show TDD adoption rate and it’s prevalence over the years:
http://www.agiledata.org/essays/tdd.html
http://c2.com/cgi/wiki?TenYearsOfTestDrivenDevelopment
http://codemanship.co.uk/parlezuml/blog/?postid=1066 – This link doesn’t contain any numbers but it is rather interesting because it talks about developer maturity – something you mentioned in your comment.
As pointed out in the links above, TDD has a been around for quite some time now and has been advocated by software experts like Ward Cunningham, Kent Beck, Martin Fowler, Robert Martin…I could go on. Stating that following TDD is a sign of an immature developer is…well, it’s a quite a statement! You may want to think it over again.
You see, here is the issue with the “just write the code, run it and see if it works” approach. The approach works fine when you’re writing something small – like a program that prints out a triangle. You simply look at the output and you can tell whether or not your program works. Things are not quite so simple when you’re dealing with an application of a sufficient amount of complexity that is built by a team of developers. Without tests you’ll have no way of knowing whether your code broke something else or whether the existing code was written the way it is written for a reason and if your change re-introduced a bug that was fixed earlier.
Or you look at a piece of code written by another developer and think “Hmm…that doesn’t look right. I wonder if it accounts for all the scenarios.”. No way to know expect to run the code and see it! Except that manual testing takes forever and requires a lot of initial setup because you have run the entire application. And you find yourself saying “Oh I wish I could just test this functionality in isolation!” You could if you had written unit-tests! And if you had then you could even add more unit-tests to the existing suite. And the next time another developer looks at the code and has the same question – well they can simply open up the unit-tests and see which scenarios are being tested! But, alas, you don’t have unit tests and now you’re stuck with having to setup initial data, configure third-party settings that your application interfaces with, bring up the application, go the specific area that you want to test, test it, and check the results. Rinse and repeat for the second scenario. Come back to it a few months later and rinse and repeat again. I know I am exaggerating a little – but just a little! This is actually something that developers that don’t have unit and integration tests for their applications have to do day-in/day-out. Compare this to a suite of automated tests that tell within minutes, if not seconds, whether you’ve broken something or discovered a bug and you just might start to see the benefits of TDD!
To sum up, TDD is more than just testing. It is about maintainability. It is about preserving/improving code quality. It is about documentation – documentation that is written in code and passes and hence it doesn’t lie and is forced to always stay current. It can even be used as a metric because you can’t improve what you can’t measure.
Hope that helps!