Feed on
Posts
Comments

Test-first or test-driven driven development (TDD) is an approach to software development where you write the tests before you write the program. You write a program to pass the test, extend the test or add further tests and then extend the functionality of the program to pass these tests. You build up a set of tests over time that you can run automatically every time you make program changes. The aim is to ensure that, at all times, the program is operational and passes the all tests. You refactor your program periodically to improve its structure and make it easier to read and change.

It is claimed that test-first development improves test coverage and makes it much easier to change a program without adversely affecting existing functionality. The tests serve as the program specification so you have a detailed but abstract description of what the program should do.

I deliberately decided to experiment with test-first development a few months ago. As a programming pensioner, the programs I am writing are my own personal projects rather than projects for a client with a specification  so what I have to say here may only apply in situations where there’s no hard and fast program specification.

At first, I found the approach to be helpful. But as I started implementing a GUI, the tests got harder to write and I didn’t think that the time spent on writing these tests was worthwhile. So, I became less rigid (impure, perhaps) in my approach, so that I didn’t have automated tests for everything and sometimes implemented things before writing tests.

But, I’m not giving up on TDD because of the (well-known) difficulties in writing automated tests for GUIs. I’m giving up because I think it encourages conservatism in programming, it encourages you to make design decisions that can be tested rather than the right decisions for the program users, it makes you focus on detail rather than structure and it doesn’t work very well for a major class of program problems – those caused by unexpected data.

  • Because you want to ensure that you always pass the majority of tests, you tend to think about this when you change and extend the program. You therefore are more reluctant to make large-scale changes that will lead to the failure of lots of tests. Psychologically, you become conservative to avoid breaking lots of tests.
  • It is easier to test some program designs than others. Sometimes, the best design is one that’s hard to test so you are more reluctant to take this approach because you know that you’ll spend a lot more time designing and writing tests (which I, for one, quite a boring thing to do)
  • The most serious problem for me is that it encourages a focus on sorting out detail to pass tests rather than looking at the program as a whole. I started programming at a time where computer time was limited and you had to spend time looking at and thinking about the program as a whole. I think this leads to more elegant and better structured programs. But, with TDD, you dive into the detail in different parts of the program and rarely step back and look at the big picture.
  • In my experience, lots of program failures arise because the data being processed is not what’s expected by the programmer. It’s really hard to write ‘bad data’ tests that accurately reflect the real bad data you will have to process because you have to be a domain expert to understand the data. The ‘purist’ approach here, of course, is that you design data validation checks so that you never have to process bad data. But the reality is that it’s often hard to specify what ‘correct data’ means and sometimes you have to simply process the data you’ve got rather than the data that you’d like to have.

So , I’m going back to writing code first, then the tests.   I’ll continue to test automatically wherever it makes sense to do so, but I won’t spend ridiculous amounts of time writing tests when I can read the code and clearly understand what it does. Think-first rather than test-first is the way to go.

PS. I’m sure that TDD purists would say that I’m not doing it right so I’m not getting the real benefits of TDD. Maybe they are right. But I have never found zealots to be very convincing.

61 Responses to “Giving up on test-first development”

  1. Luca Molteni says:

    Can you give us some concrete example of

    “Sometimes, the best design is one that’s hard to test”

    Thanks

  2. Jack Hughes says:

    GUIs can be very difficult to test at the best of times. You don’t mention what you’re using to construct the GUI. If it is something like WinForms then you will find it very, very difficult to test. If you are using something like WPF on the other hand you will find matters much easier from a test perspective, especially if you are using a MVVM toolkit like Caliburn Micro or MVVM Light.

    • seboeh says:

      That is the problem.
      You write: using somthing like WPF on the other hand… will find matters (of TDD) much easier.
      You mean, there are special techniques to be used for Testing.
      That is the sad, but true truth. You need special technique for TDD. And as soon as you use them, you lost the focus on production your Software. Now you have only an focus on Testing. And not on the question, if Windows::Forms could be helpful.

  3. I couldn’t agree more. Thinking about the program as a whole is the only way to improve the system as a whole. It is how you determine that some parts will require re-factoring. Adding TDD in the mix requires to think about granular testing, as part of the design. You start making decisions about testing instead of the program design as you mention.

    In my personal experience, programming is a craft. The design is rarely clear when you start. It is during development that the design becomes clear. Classes and functions are partially working with missing arguments, members, methods and even functionality. You work on a part a bit, jump to another, and come back later. Having to write tests and make them evolve over time for every function increases the time of development significantly. It is much more efficient to advance your development, then pause, write unit tests where you see it makes sense, then continue. Doing this iteratively as to avoid writing all tests all at the end.

    Thanks for writing this. Great to reflect on testing strategies as a whole.

    Martin Drapeau

    • I totally disagree. TDD is a fine means to drive your design. A very nice introduction to this would be ‘Growing Object-Oriented Software, Guided by Tests’ by Steve Freeman and Nat Pryce. Even with TDD it still is Think First.

  4. Dexter Barnes says:

    Hi!

    I liked your article! I’m currently working on a project that’s based on TDD and definitely feel some of your pain, but I would like to say,though, that I think ultimately it has been a good process for me. I think one of the major things that I have to keep in my head and might cover a couple of your points is the “Red, Green, Refactor” mantra, and its the refactor part that sometimes gets lost. This is the part that allows you to look at your program as a whole, rather than the detail, and the tests that you’ve written when focusing on the detail allows this to happen with ease.
    The other thing that you mentioned about tests effecting the way you write production code can be both good and bad from my experience. When I find that I can change the structure of code to make testing easier, it usually makes my code easier to read/follow but if I find that I am adding code just to make a test pass, even though I know it already works, then I need to look at how i’m testing it. Both things can lead to either better code or better tests.

    Having said this, there have been times where a relatively small change in code has been overshadowed by length of time needed to update or write tests. It feels like the value can be lost.

    In the end we have a project in its second year with a test suit of ~6k tests ranging from unit/integration to feature tests which gives us massive confidence when coming to updating or adding features.

    Sorry about the the lengthy reply!

  5. goob says:

    I’d like to make a minor pedantic point, that “Test first” and “Test driven” development are two different things. When the tests “drive” development, you write one test, then as many lines of code it takes to make the test pass.

    But writing tests “first” simply means that you’ve taken the product owners requirements and turned them into a technical specification of sorts. How you go about making that happen could involve lots of buggering around and unclean code.

    The way I see it, TDD is just a stricter form of TFD. Obviously you can’t do TDD without a test first. But you can write tests first, but then go off on your merry way until they pass.

    I find writing tests first usually helps me refine what the actual requirement is, especially when it’s not clear at the outset.

    Sticking to strict TDD will, as you say, lead to missing the bigger picture.

  6. Tomek says:

    TDD is quite complex topic and you guessed it. I am not a zealot and I also don’t test everything. I saw the value of TDD after I read this article: http://blog.testdouble.com/posts/2014-01-25-the-failures-of-intro-to-tdd.html It is about mistakes in teaching TDD. Give TDD another try after you read it 🙂
    Zealots usually follow their religion, because they see something beneficial. This article showed me for the first time what it really was (HOW can TDD improve the design) and why I haven’t seen expected results from the start.
    Testing GUIs is especially hard and it requires great framework to make it easy. The best approach I have found was in Elm programming language. The approach is close to reactjs, but better 🙂 I am not aware of such good solutions outside of browser though :/

    • Ashok Bakthavathsalam says:

      Thanks for sharing the link to the article. Any pointers on how one should go about learning about Elm, including suggested reading/online material.

  7. Marcus Nielsen says:

    My biggest issue is the cost of refactoring. As long as the project is in an unstable phase, I’d much rather do tests when I need to formulate a specification.

    So I go into brainstorm mode; write some code, refactor it a couple of times, then when it looks good enough I create a test file and write a specification with the whole of the code in mind.

    I start with a failing test: `assert.strictEquals(actualValue, null)`, then I adjust it to a test that should pass: `assert.strictEquals(actualValue, {name: ‘a’})`. If it passes, cool. If it doesn’t, I fix the code.

    For me, the biggest issues lie in creating a good code structure. Immutable structures, injected dependencies, no side effects, isolated components/modlets.
    The problem I want to solve is: is this code easy to create/read/update/delete? Since it is a compromise between those four, I have issues formulating tests for it.

    I think the “red light, green light”-part holds up. It’s just that I start with refactoring many times before I reach stable enough code to bother with tests for.

  8. Andirk says:

    Your argument is wholly about the difficulty of testing complicated components of your program, especially the things you add on later. I agree it’s difficult, but the point of TDD is that if you cannot prove that a component is working, then you are absent of coverage on said component. Have your TDD cover the Acceptance Criteria, and forego coverage on the less vital parts. I think that is still TDD, albeit not 100%.

  9. You might enjoy reading Growing Object Oriented Software Guided By Tests (http://amzn.to/1Umaqru). One of the things I’ve taken away from it is the approach of writing the test you want to read (sometimes in the form of empty methods), then filling in the details. I find that approach allows me to think about the big picture, the user, and where I want the software to go first and use testing to drive toward that vision. Letting go of some attachment to keeping tests passing all the time also allows me to make big changes without being stuck in the framework of existing tests. Happy to hear you’re experimenting!

  10. lil.pipsqueak says:

    I’ve been using TDD in the workplace for the last several years. Based on your reasons for not using it, I’d say you’re “doing it right” according to a TDD purist, but as with everything in life, moderation is the key. TDD is only a tool, and each tool has an optimal time to use it. Trying to use it for everything is a trap I’ve seen a lot of people fall into.

  11. […] Because you want to ensure that you always pass the majority of tests, you tend to think about this when you change and extend the program. You therefore are more reluctant to make large-scale changes that will lead to the failure of lots of tests. Psychologically, you become conservative to avoid breaking lots of tests. It is easier to test some program designs than others. Sometimes, the best design is one that’s hard to test so you are more reluctant to take this approach because you know that you’ll spend a lot more time designing and writing tests (which I, for one, quite a boring thing to do) The most serious problem for me is that it encourages a focus on sorting out detail to pass tests rather than looking at the program as a whole. I started programming at a time where computer time was limited and you had to spend time looking at and thinking about the program as a whole. I think this leads to more elegant and better structured programs. But, with TDD, you dive into the detail in different parts of the program and rarely step back and look at the big picture. In my experience, lots of program failures arise because the data being processed is not what’s expected by the programmer. It’s really hard to write ‘bad data’ tests that accurately reflect the real bad data you will have to process because you have to be a domain expert to understand the data. The ‘purist’ approach here, of course, is that you design data validation checks so that you never have to process bad data. But the reality is that it’s often hard to specify what ‘correct data’ means and sometimes you have to simply process the data you’ve got rather than the data that you’d like to have. (Source) […]

  12. Vlad says:

    You wrote: “Because you want to ensure that you always pass the majority of tests, you tend to think about this when you change and extend the program. You therefore are more reluctant to make large-scale changes that will lead to the failure of lots of tests.”

    If your refactoring of code forces you change tests then you are testing the implementation instead of the intention and this is definitely not helpful. The tests that fail after your refactoring (or design changes) should show you that you have changed the functionality of your system. Your system now behaves in a different way. If you intended this, then the tests must be rewritten. If you wanted to keep the functionality, then you messed up.

    In TDD you should be testing only the outer shell of your system under test. The true power of these tests is to let you experiment with any internal design you want, while making sure that your functionality does not change.

    Then, again, if you do not like it – fair enough. We do not all have to agree.

  13. Roland Smith says:

    As a (mechanical) engineer who writes programs to help me get things done, I also find TDD limited. (My programs mostly tend to be command-line utilities. They’re easier to write than GUI programs and easier to automate.)

    In Python which is my go-to language for most stuff these days I use the “nose” testing framework. But the only things that are easy to test are pure functions, and classes.

    And what exactly should one test? Valid input to check that a function produces the correct output is obvious. How many different combinations should one try? And also all possible invalid inputs to check if the function handles that properly?

    On occasion TDD has helped me find bugs. But the effort expended is indeed quite large compared to the result.

    For command-line utilities it is much easier to assemble a collection of input files and expected output. This has the advantage of testing the whole program in one go instead of piece-by-piece. If this testing reveals a bug, then I start sprinkling print statements in strategic places to see where it goes pear-shaped.

    A technique that I do find quite useful when starting a new program or module is to write the README first. This makes me think about what the program or module should do and how it go about it. Programs or modules should be easy for humans to use.

  14. Elijah says:

    Two comments:
    1. Perhaps you would find zealots more convincing if you stopped labeling them “zealots” and start listening to what they’re saying.
    2. Your first bullet point exposes the fact that you are, in fact, doing it wrong. If you follow the red-green-refactor cycle, you want your tests to fail when you change code. The ways that the tests fail can give you useful information.

  15. Srinivas Dhanraj says:

    “Because you want to ensure that you always pass the majority of tests, you tend to think about this when you change and extend the program. You therefore are more reluctant to make large-scale changes that will lead to the failure of lots of tests.”

    I would not agree this point. When you are making large scale changes, you would not make them in one go. You would make one change and see if you effected the existing functionality. In fact I found it was easy to make changes when the test coverage was better. I would not have to worry if there are places unknown to me where I am breaking the functionality. I can make my changes, run tests, and if some of the existing functionality breaks, then I would modify my change.

    TDD is especially useful in enterprise software where multiple teams and team members are using common code. It is very useful in infrastructure code so that you test all the scenarios. And also when a change is introduced, the tests verify if the code effects existing use cases.

  16. […] It worries me that the tech industry is driven by such intense manias, which have cost me several jo… For a long time you were not allowed to question Object Oriented Programming. I still go to job interviews and I’m asked the basics of Object Oriented Programming, and it is clear I have to say nice things about Object Oriented Programming or I won’t get the job. Thankfully none of these people ever check Wikipedia, where I am cited as a critic. […]

  17. keripix says:

    Hi, thanks for the interesting article.
    For the problems that you’ve faced, I suggest that you read Uncle Bob’s article on Domain Discontinuity (http://blog.8thlight.com/uncle-bob/2014/01/27/TheChickenOrTheRoad.html) where he talks how TDD relates to system architecture.

    Here’s a quote that I think is very interesting:
    “This discontinuity means that, although we can use TDD to help us with the design of the problem domain, we cannot use it to help us with the architecture. TDD can’t even be begun until we know the shape of the system that is to be created.”

    This article has opened my eyes on the workflow needed to help drive TDD.

  18. Antero Kärki says:

    I can not agree with the idea that TDD somehow stops you from thinking of the system holistically.

    Uncle Bob Martin is only one good example of a TDD advocate who can do both.

    With TDD you are right in that you don’t want a bunch of tests failing simultaneously, but for me that doesn’t translate to not being able to do the refactorings you want. It may mean you have to take smaller steps to get there. Some tests may even be obsolete after a refactoring and should be allowed to change as well when necessary.

  19. I am what you’d probably call a TDD zealot. I advocate for TDD the vast majority of the time, but you should know: Most TDD zealots don’t use it 100% of the time. We can’t. Sometimes we need to experiment, to spike a solution, or sometimes we need to bash our head into the wall until we find a crack (first pass at integrations often).

    I don’t think a TDD zealot will always use TDD, but I think she or he will always put the functionality and maintainability of the application over our personal opinions. What’s the best design? I’d love some super-SOLID, open-closed, pluggable, business-mirroring app… but maybe my app just needs to send an email? What’s good enough to pass to the next developer? I don’t know… but I know the bare minimum is a way for that dev to verify that what I wrote still works.

    Can you get that attitude going test-after? Perhaps, but I doubt it. Programming can be very personal and very creative, and developers that drop their guard can very quickly find themselves in trouble. I believe that we need something pushing back against that danger… a force that checks ourselves and reminds us to put the job first.

    One more thing – the problems you detail in your post here (esp. the supposed TDD focus on detail too early, and the focus on passing tests) show a lack of understanding of the practice of TDD. Which is fine! How else could you know, you just started It!? When I faced the TDD issues you are facing, I fixed them by applying a TDD attitude to the question of TDD! First, I checked myself and what put aside what I thought software dev should be. My failing test was my failures – the ones you don’t speak of here but I know you have because you’re human. I needed to overcome the fact that I’m one bit-flip from costing my customers money, and my test-after tests only seemed to cover it all. So how did I make this test pass? Well, I’m still making it pass, but I’ll tell you this much: I didn’t put myself first and blame the process for not matching my imagination.

  20. Kevin Taylor says:

    >> I deliberately decided to experiment with test-first development a few months ago.

    Ok, that says it all. Do TDD for a year, preferably while pairing with someone who knows what they are doing, and then you might be qualified to write an informed critique of TDD.

    • G Schultz says:

      Not all of us have the luxury of using a technique for a year in situations where the outcome doesn’t matter, before we can speak up. We have to employ our professional judgment after researching/reading/experimenting. (And because software is such a subjective craft, we cannot simply trust that the majority consensus will apply to each of us individually.)

  21. […] of the Week:  Giving up on TDD by Uncle Bob.  Apparently a guy named Ian Sommerville “gave up” on TDD, and Uncle Bob refutes his argument. Uncle Bob doesn’t pull his punches.  Good […]

  22. Adrian Thompson Phillips says:

    This post sums up my experience with TDD. I’ve worked with the zealots and they are truly zealots blindly spending all day testing one thing and then refusing to refactor drastically because they’re have to ditch several hundred tests. I’m now a Test During Development developer.

    • Kevin Roche says:

      TDDers are Test DURING Development developers as well. The “zealots” you describe are not doing TDD; in fact, if they refuse to refactor they’re not doing software development.

      Practically everything in this article is wrong and based on a misunderstanding of TDD and an apparent unwillingness to learn – worrying stance for a professor (former or not) to take.

  23. A disappointing post. You tried a new technique for a short time on a home project, apparently without help from anyone experienced (correct me if I’m wrong), and now it obviously doesn’t work. I can imagine writing an equivalent post for Golf. I won’t go over the various misconceptions in the detail, because others already have.

    It took me significant amounts of time, in the right environment, to understand every technique I’ve acquired over the years: functional, Objects, and even Structured Programming.

    Perhaps this is the moment to cite Peter Norvig’s “Learn to program in 10 years”?

  24. […] you read Ian Sommerville’s recent blog about […]

  25. Hi!

    IMHO you are in the initial phases of the Testing discipline, and that’s a good sign. As a testing beginner, I’ve had to do some of the things you mention in the article, like “first developing the feature, then testing it”, or “covering with tests only the features that won’t make it too complicated”. I think these are just the first steps and it is just a question of time to become an expert, and be able to do proper TDD. In my opinion, you shouldn’t give up yet, keep on improving and you’ll end mastering TDD 🙂

  26. I think it is indeed a fair point.

    Maybe for home projects it makes no sense to be so rigid about TDD.

    What’s disappointing to me about this post is the way he generalizes it, TDD has helped me to write more robust code at work, even though I’m not applying it to my home/small projects in a so rigid way or, sometimes, at all, when the project grows or I have some fellow writing code and pull requesting to it, chances are I will need to start writing those tests I missed.

    I believe the thing about writing tests is not to write them first or last, is just write them and have the discipline to maintain them and be strict about the amount of code coverage you want for a certain project. Write them first has obvious benefits, but it’s a technique that might not work for everybody or for every project. In my experience, there are sometimes some time constraints which forces you to implement fast and then test only the critical bits. I’ve work only for startups and internet companies, so, it’s a very fast paced/marketing-focused environment, so, sometimes you acquire huge amounts of technical debt (specially on startups on its early stages) for the sake of releasing and gather data to evaluate possible pivots, Software Engineering is not only about programming, designing and testing, also making the right choices when it comes to the right tool, the right methodology and the right techniques for a given project or situation.

    Maybe Mr. Sommerville needs to try TDD on a larger scale project to really get to see the benefits…

  27. ChrisW says:

    If you’re working on the JVM, you might want to look at the excellent tools available for testing with Scala:

    http://www.scalatest.org

    Because Scala interoperates easily with Java, you can write your app in Java and your tests in Scala. And because the testing libraries are pretty straightforward you don’t need to learn much Scala to get started. But you’ll find you need to write a lot less code to implement your test in Scala.

    Also, ScalaCheck https://www.scalacheck.org/documentation.html allows you to generate data and execute tests for dealing with your problem of unanticipated data values. This will generate test cases for things we often forget to test e.g. weird strings, edge cases like max/min int values, and so on.

    There’s a nice 15 minute video intro to Scala testing here:

    https://www.lightbend.com/resources/video/scala-testing

  28. Andrew Eddie says:

    Ian, I’d be more than happy to go through your code with you and collaborate with you with the goal of hopefully designing code that is easier to test. Without providing examples of what you did, it’s hard to comment about where you went wrong.

    To me “hard to test code” is high-interest technical debt. It doesn’t matter whether you are writing tests first or writing tests last – if it’s hard to test your design is wrong. There is no way to sugar coat it and I’m looking at myself as much as anyone else.

    That said, just because you successfully wrote a mammoth test for that hard-to-test code doesn’t mean you got it write either. It just means you succeeded in writing a very smelly test for very smelly code (spent a day last week refactoring such a beastie of mine – what was I thinking at the time?).

  29. V says:

    “It’s really hard to write ‘bad data’ tests that accurately reflect the real bad data you will have to process because you have to be a domain expert”

    As you know brakes are controlled by software in modern cars. Let’s imagine you had a crash and it turns out it was caused by software bug. Would you accept “I’m not a domain expert” defense from the guy that left the bug? What if someone died in the crash?

  30. Kata says:

    >I deliberately decided to experiment with test-first development a few months ago.
    Hmm, that means when you wrote about TDD in your book “Software engineering (9th Edition) 2011” you had not experimented with the practice?

    • pete says:

      Very good point Kata!
      That was my first thought when I found out that Ian wrote many books on software.
      I immediately went to see whether he wrote anything about TDD and I was very surprised that he did in his primary book!
      How could you be teaching about TDD to others not even trying it, it is so easy to give it a try, it doesn’t require any costs!
      I’m very curious what exactly is the content of this TDD chapter, but I’m not going to spend money on your book cause for me you’ve just lost credibility 🙁
      Also from an author of a book I’d expect a more in depth criticism.
      All this only makes me continue to value practitioners like Uncle Bob so much more!

      • admin says:

        My book makes no attempt to teach TDD but simply introduces it as a method of testing. I don’t discuss my own views on this (or on anything else in the book). As I make clear in my post, TDD did not work for me – which doesn’t mean that it won’t work in other circumstances or for other types of problem (I was developing an application with lots of visualisation).

        Blogs are not academic papers and anecdotal experience is not a way of doing in depth criticism. There have been few comparitive studies of TDD with other approaches and these are what are needed for in-depth criticism.

  31. Lord John Whorfin says:

    The trick is that it works great if you use it smartly. When it comes to GUIs, TDD is a losing battle, which is why you want to have a clear separation between the code that actually does the work and the UI code.
    GUI aside, if you have a hard time writing tests and they break all the time, it’s usually because you write code that is too complex. Your classes should have clear states, simple methods that perform a simple task, and you should be able to test them with mock objects. We’re talking unit testing here, not integration testing. Each class you’re writing should stand on its own and be testable on its own.

    I’m wondering if you’re not getting burned out just because you’re trying to write tests for the GUI, though. I’d love to be proven wrong, but in my opinion and experience, that’s a complete waste of time.

  32. Steve Naidamast says:

    Like the author, I have been in the profession for many years and spent about 12 years working on mainframes where it appears that the author also spent his early years based on his comments.

    I never completely understood the TDD paradigm because I have spent most of my years writing database intensive applications whereby you know right away if a function is working or not based on the data being returned. Thus, TDD in this case has proven to be redundant and\or useless as a result.

    As it regards an interface, testing it is also fairly obvious since that is the actual, functioning part of the application that you can see and observe. If you have set up the corresponding processes correctly you will know quite quickly as well if a part of the interface is not working. So again, I find TDD to be either redundant and\or useless.

    Thus TDD, appears to have some benefit when implementing algorithms that incorporate complex logic such as a calculation. These types of methods are rather hard to observe as to whether they are returning the correct data so TDD would have a purpose in these situations.

    Overall, TDD is merely a replacement for standardized, traditional unit testing, which developers years ago and still today can be performed as accurately as with a TDD implementation. So it becomes a matter of preference in some senses as to which approach a person may find more useful.

    For myself, I find TDD simply another paradigm that many thought would be “cool” to implement and would make them better developers. It doesn’t. TDD developers can implement as many poorly written tests as those who do a poor job of traditional testing. It is matter of the quality one brings to the effort not how it is done. And this my biggest problem with TDD as it is promoted as “the right way” to build an application correctly. It is not. The right way to build an application is by using legible, clean coding practices no matter the style while having a good understanding of what it is that is attempting to be accomplished.

    Before TDD came along, many of us did just fine without it and produced high quality applications. After TDD there are as many people still producing bad applications as we produced without it as well as there are those who have produced good applications of similar quality as non-TDD created ones.

    TDD is simply a development paradigm. It is neither a correct or an incorrect one to use. For those who use it well, it works. However, when one has done quality, traditional testing with success, using TDD will seem only like more work, which in the end it is… But so is traditional testing. Either way our applications have to be tested properly for the implementation of our intended quality…

  33. Pablito says:

    TDD is a religion, and like all religions, it collapses under any real scrutiny.

    • Lord John Whorfin says:

      No. TDD is not a religion, although it may be sold as such by people who do not understand it.
      If you think about it for all of five minutes, it’s obvious that TDD is great and works. Why?
      1) it forces you to simplify your code. I often see methods over a thousand lines long. Needless to say, it is impossible to write tests for this!
      2) it gives you confidence that your code works as expected

      And you’re absolutely wrong when you compare it to “traditional testing”. It has nothing to do with traditional testing! The best example I can think of is if you have any kind of algorithm in your code. That is the perfect candidate for TDD! First, come up with a set of sample data and the expected results; write the test, write the code, and if anybody ever touches your algorithm and messes it up, the tests will fail and catch the problem.

      I guess the real problem is when people turn it into a religion, like you said. Doing TDD with UI code is just not a efficient use of time. But I find that intelligent use of TDD is excellent not just for the confidence it gives in the code, but also because in order to write easily testable code, one has to write inherently better, more maintainable code. Many years ago when I was introduced to Agile and TDD I must admit I was dragged into it kicking and screaming; but I was lucky enough to be trained by very smart people who showed me all the benefits of that approach.
      At this point, continuous integration and TDD are just plain common sense to me, and I think it’s impossible to be competitive without it.

      • admin says:

        Just a quick comment. Any testing (whether used as part of TDD or anything else) only gives the tester confidence that the code does what they think it should. That’s part of the general problem with testing – people write code to pass tests (their interpretation of the specification) and equate this with ‘correctness’. TDD, in my opinion, exacerbates this because of its emphasis on testing but its a general problem.

        TDD may well force code simplification but its hardly the only way to do this. Code reviews can be equally successful in achieving this.

        • Rodrigo Marcushi says:

          Couldn’t agree more. I’m fond of testing myself, TDD is too disciplined in the wrong direction.

          • Lord John Whorfin says:

            TDD is a tool, not scientology. You use it any way you want, and as much or as little as you want. There are automatic generators that take care of trivial cases like getters and setters. You may elect to only write tests for important business logic in your core app. The coverage is up to you! But if many people work on the same code, I found that tests are often an excellent supplement to the copious documentation that programmers always write.

        • Christoph says:

          I think what you are describing is the difference between “code that is right” and the “right code”. TDD is a cool way to ensure that your code is right. But it isn’t the tool of choice when it comes to ensuring that you have the right code. There is a great article about this issue in the FitNesse user guide, I also did find the book “Specification by Example” by Gojko Adjic a real game changer for someone like me who was being too focused on getting the code right by TDD and completely to getting the right code :).

          Here’s the article: http://www.fitnesse.org/FitNesse.UserGuide.AcceptanceTests

        • Lord John Whorfin says:

          You know, if the programmer can’t write a decent test and has no idea what the code is supposed to be doing, he probably shouldn’t be a programmer in the first place. TDD will not turn a bad programmer into a good one, it’s just a tool that makes good programmers more productive.
          TDD doesn’t force anything on you; but it’s easy to do if you make small single task methods and focused modular classes, and it’s impossible to do if your code is complex, so you just don’t write that way. You’re suggesting that code reviewing badly written code is just as good, and I have to question your obsessive rejection of TDD. It’s a great tool when used intelligently, and there’s certainly enough literature and success stories on the topic to illustrate the shortsightedness of your position. I would posit that you do not really understand what TDD is all about, and if you’ve done it before… You’ve done it wrong.
          I hope you don’t think I mean to insult you. I was in your shoes about 10 years ago when the company I worked for hired tons of consultants to teach us the errors of our ways. I started to smugly dismiss them because how could these cocky consultants teach me anything of value, I had successfully shipped many commercial products and didn’t need their help.
          Turns out, they had very valuable tools to offer. Agile, continuous integration, TDD, all this shit looks like it’s out of a cult, but when it’s done right, it just saves you a ton of time, and increases tremendously the quality and reusability of your code.
          On the other hand, I will agree that it’s painful and counter-productive to deal with zealots of the process. Sorry you’re likely to have had a bad experience with it, but I hope you give it a second chance. The upfront cost is a little higher, but by the time you get to the end of the project and bugs start cropping up, on a non-agile, non-TDD project every time you fix a bug you introduce 5 new ones. On a decent TDD project, you rarely find bugs late in the game, and when you do they’re easy to fix, so the end of the project rarely involves the all-nighters old school programmers are so familiar with.

          Cheers.

  34. Bob Stine says:

    Nice essay, excellent points!

    Unit tests are great, but TDD zealotry substitutes slogans for thought.

  35. TDD is hard, it really is. It’s easy to learn (slap a few attributes on some classes and methods and call an assert method) but hard to master (as you discovered). Ultimately I found it to be worthwhile, and it helped me tremendously to get some serious training for it. Teaching myself TDD was unsatisfactory, but attending Roy Osherove’s TDD Master Class helped me no end.

    TDD is a tool, and as with any tool you will only get the most benefit if you use it in a situation that caters to the strength of the tool. I find that using TDD when I don’t know the shape of the API I need to be very wasteful. I’m happy that I learned another tool that helps me define the shape of the API I need: Behaviour Driven Development (BDD). I use BDD to (among others) define the shape of the API that I need to cover the users’ requirements, and then I use TDD to implement that API.

    I explain that in a bit more detail in my blog post “Giving up on TDD? And what about BDD?” at http://blog.picklespro.com/2016/03/22/giving-up-on-tdd-and-what-about-bdd.html

  36. Monica says:

    I’m disappointed by Uncle Bob’s response.

    A better response would have been ‘Sorry it didn’t work out for you Ian. But if you ever fancy giving it a try again, do have a look at these open source code bases, all developed using TDD, all of superb design: linkA, linkB, linkC, linkD, linkE, … linkZ, linkA1, linkA2 …’

    Where is all this great TDD code?

    Really does the TDD community expect us to devote ’40 hours per week for a few months’ on a technique without showing us well-designed source code?

    Does TDD not work for open source software? And if not, why not?

    • Dave says:

      Why are you disappointed. Ian stated the facts. And so did Uncle Bob. What’s the big deal?

      • Monica says:

        Hi Dave,
        I suppose I’m disappointed because my expectations were too high. I was hoping Uncle Bob would provide a wealth of good non-trivial TDD source code to help Ian see the concrete benefits of TDD.

    • Dave says:

      And you’re clearly not understanding TDD itself..hence your questions above.

      • Monica says:

        Hi again Dave,
        I couldn’t agree more: I don’t understand TDD. Seeing thousands of lines of high-quality code produced using TDD, however, would greatly entice me (and, no doubt, others) to try harder.

  37. […] My blog post the other day about giving up on test-first development attracted a lot of attention, not least from ‘Uncle Bob’ Martin, an agile pioneer who wrote an entertaining riposte to my comments on his ‘Clean Code’ blog. He correctly made the point that my experience of TDD is limited and that some of the problems that I encountered were typical of those starting out in TDD. […]

    • Dave says:

      I really respect that you were open to listening to experienced TDD’ists and realized this. Most devs just dog it and leave and they never realize that the problems they had were either they didn’t stick with it long enough and have the drive to learn now to do it right, AND they hit routine beginner issues so that left a bad taste in their mouth.

      We’re all in this together, to help each other learn. I’ve met fellow co-workers who said the same thing, they got “burned by TDD”. But in their case it’s the same thing. They didn’t practice it long enough, not enough hours, and they always hit the same beginner brick walls which is coupling your tests to your prod code, a design issue, not a TDD cycle issue or TDD principal issue itself.

      Please keep working on it, and also, read up on some of the greats out there who talk about this such as Ian Cooper

  38. […] Ce que Uncle Bob a eu comme réponse au sujet d’un billet suggérant d’abandonner le TDD pour ses applications. […]

  39. […] response to Uncle Bob’s Giving Up on TDD?  (itself  a response to Ian Sommerville’s blog). In his article Itamar proposes an approach to software development that he calls “Spaghetti […]

  40. Augustin says:

    Interesting points of view over a well established approach …
    TDD, as already pointed above, is not for everyone in the same way Agile is not for everyone or Waterfall is not for everyone or driving is not for everyone etc.
    During the last two decades I noticed a tendency in programming:
    we tend to chose the easiest path and that mindset might cause us to ignore possible brilliant solutions to complex problems!
    In the same way, TDD requires a particular mindset, otherwise it doesn’t work.
    TDD is – again, as mentioned above – not making one a better programmer: it makes one more efficient IF one is already a skilled programmer!
    And TDD is not a ‘silver bullet’ for any type of programming.
    In the old days, when we were first writing our code on paper and feeding them to machines only after the ‘proof of concept’, we were not able to test in interactive ways our code. Now, things are different and writing the test first is significantly reducing the time allocated to development if done accurately.
    To end, I would advise Ian Sommerville to take a different approach:
    pair-programming with an experienced TDD practitioner! [Perhaps Robert C. Martin? :)]
    If that doesn’t work then, well, it doesn’t work and that’s that …
    Good luck!

    • admin says:

      I worked in the ‘old days’ when there was no interactive testing. I’m not convinced at all that TDD reduces development time – I think that it is automated testing that makes the difference and you can do this however you test a program. Since I stopped using TDD, I have found that my development time is reduced as I think more and catch more bugs before execution.

Leave a Reply