Is TDD Dead
We answer questions from our viewers: what open-source examples of TDD exist, what changes would make us change our use of TDD, and how well it works for inexperienced developers. We finish by summing up our view of the health of TDD.
I begin by saying we'll structure this hangout by picking and answering some questions submitted by viewers. David starts by picking a question from Mike Harris, who asks for examples of open-source projects that have used TDD and either got test-induced design damage or used TDD well. David responds by saying there aren't good examples and this is one of the problems of debates like this. We don't have good application examples in general, because open-source contributors often work on private applications and open-source common frameworks and libraries. As a result we go into these discussions with different contexts, which often makes it look like there is more disagreement than there really is. People come together when you have real code rather than philosophical principles. The code examples we have are minor examples rather than things people are actually working on, so you have to understand people via presentations - which is why he used Jim Weirich's example for design damage. For good rails code he suggests Rails books that show standard testing approaches.
I comment that it takes lots of effort to understand real code. I do some some digging into our code bases but it takes a lot of time, and even then it's not the same understanding as you get by working with the team. Kent says that JUnit is an example of a project that used TDD strictly and turned out well. But it isn't a good example for this discussion because it has clear interfaces that make a sweet spot for TDD. We are talking here about different kinds of applications. If someone has a good example, they should write it up.
David says my comments illustrate that we can't treat programming as a science - we can't evaluate techniques objectively. This doesn't mean it isn't worth debating. We can't get a definitive answer, it's your job to figure out what makes sense. Kent agrees we can't replicate experiments, but says we still can look at things personally with a scientific mindset. We can try things out empirically for ourselves, but you can't get universal answers.
Kent picks the next question (asked by Graham Lee): what could change about the way we write software to make TDD redundent or obsolete for Kent and Martin and what could change about how TDD is performed to make it useful for David? Kent replied by saying his RIP TDD post points out his postion (if rather sarcastically). TDD solves several problems, starting with confidence. TDD also allows him to break problems down piecemeal, tackling specific cases without having to solve the general case all at once. He's not prepared to give up on TDD just because it's hard.
I say that for me it's not about changes that would make TDD obsolete, rather the applicability of TDD in different contexts. I've experienced following TDD in a mechanical way with a calm "rapid unhurriedness" where I've blundered into good designs. Most of my programming these days is my website toolchain and while I do piecemeal progress, and have a good regression test suite - I don't find TDD applicable. But when I built the infodeck code, there was a lot of application behavior where TDD was effective. "Some contexts are very suitable for TDD, some contexts less so". And people bring their personality into that context.
David said his experience was similar. His introduction to testing was through TDD, he liked it and tried to apply it to everything but slowly realized that lots of areas in an MVC web application didn't feel good for TDD. This doesn't mean TDD isn't effective for some situations, just that those cases are a small percentage of his work. But abandoning TDD doesn't mean he wants to give up self-testing code - that's always been the value of TDD to him.
I say that this is exactly how someone should take on TDD (or any technique). Try it out, overuse it, settle into a mode that works for you. Then also look a bit deeper: "tdd is gateway drug to self-testing code". Kent said he didn't mind where people end up with their workflow having done this kind of process. His experience of using TDD differs to David's. He finds there are moments in development where something is hard and he gets an idea of an object with a certain protocol that simplifies things. TDD gives him a mechanism to quickly get feedback on such an idea, trying and example usage of the API and implementing it. He also finds cases where TDD doesn't fit. He then finds command-R is a good way of getting feedback, but he's hoping for the moment when he can see the simplifying object and try it out with TDD.
I pick the next question (from Tudor Pavel): how does TDD work with less experienced developers. I reply by saying that TDD forces people to do small pieces and helps them separate interface from implementation. It doesn't guarantee great results, because you can't do good design without experience. When less experienced people do TDD they typically don't refactor enough, leading to sub-optimal designs. You can't compare an inexperienced developer's output to an experienced developer's output, you have to compare it to what that indexperienced developer would have done without tdd. Although we can't measure this, it does seem to be advantageous, and creates a self-testing code base which is easier to improve later through refactoring. So TDD gives you a good start point.
David said that was the value he got from TDD. He started with TDD and found it was great training wheels, however he felt the discussion didn't move on enough since. He's skeptical when people say you must give simple, direct, bombastic advice to new people otherwise they won't do it. That shows a lack of confidence in what you're teaching. I agreed with that dislike for dogmatic statements. I get suspicious if I can't find arguments against something I'm describing. One twist, however, is that we do have to keep repeating introductory stuff for new people: some people resist repeating the basics.
David thinks this is why we're having this conversation now. As people describe TDD they add their own spin to the basics, after ten years of this you end up a long way down the road from where you started, and not in a good place. You need to hit the reset button, an approach that's crude but effective. When he says TDD is dead, he's referring to this current mutation - we have to get back to first principles. Kent said his gut reaction to David's original keynote was at that level. Programmers will often do the same thing many times, make things too complicated, and stick with dysfunctional systems at work. He's happy to reboot to first principles, but doesn't want to lose the evolution of people's expectations about programming in the last ten years. You should be able to feel confident, point to progress, have productive technical collaborations. He feels he can be his whole self at work now in a way that he couldn't be when he started his career.
David thinks that several things came together at the same time : TDD, XP, and Ruby. People laughed at the notion that programming should be fun, but he wanted to continue with that notion in developing Rails. Now he thinks that the Ruby world takes that happiness for granted - these things have won - as has agile. I disagree that agile has won - the label has won, but many people say they do agile but don't really. This is typical for things like this, a process I call semantic diffusion. The big win is that now we are able to do agile openly at clients. David observes this reboot problem with other things - after ten years you get lots of cruft. He used the example of Pinkberry which started with just two flavors, but then got a complicated range of flavors just like other ice-creams - "most people can't leave good ideas the fuck alone." TDD and Agile are very broad tents now. People who say they are doing agile do opposite things. Kent says that he hasn't seen the things with TDD that David has. He always applies TDD from first principles in his work.
Kent appreciates that David has brought attention to TDD acquiring some barnacles and needs some scraping. David said he's seen similar issues with Rails. He uses Rails in its basic form and is shocked by some Rails usage he's seen. Kent remembers the first OOPSLA when XP got attention, Jim Rumbaugh said you won't recognize what happens to XP in ten years and he was right. I said that this is what success looks like, the alternative is that things don't take off. It's always hard to tell if something bad happens due to something inherent in a technique or due to misuse of a technique. All we can do is keep repeating the basics and the good lessons. David agreed: "you either die a hero or become the villan." Ruby was a reboot of good ideas about programming. Functional Programming is another reboot. These reboots are healthy. He's impressed by how long Rails and TDD have lasted. Before Rails he worked with PHP. You can write good code with PHP if you use it well, he feels that other languages do a better job of encouraging good usage. He things that using TDD well in an MVC web app is harder than writing clean PHP.
Kent hasn't found that - any time he can break off a piece of a problem into a useful abstraction he can use TDD. He wants to explore other avenues to these big goals of bringing his whole self to programming. He will continue to explore this with experiments: doing it too much, not enough, finding the golidlocks zone, and understanding why. He comes out firmly contradicting David: TDD isn't dead, but is glad David set fire to it so it could come out like a phoenix.
David said he started this discussion because people wouldn't talk about cases where TDD wasn't effective. They weren't feeling good or confident, but were told they must use TDD. He wants to open the sphere of acceptable reactions so we can discuss when TDD is and isn't appropriate. Lots of people on the internet talk about how good TDD is, but people were afraid to say it wasn't working for them. For David the baby is self-testing code, we don't want to lose that when questioning TDD.
I concluded by saying that (as I suspected before we started) there is lots we agree on. We all value self-testing code a lot, we all agree TDD is valuable in some contexts, we might disagree on how many contexts (although it's hard to really tell). Everything still boils down to the point that if you're involved in software development you have to be thoughtful about it, you have to build up what practices work for you and your team, you can't take any technique blindly. You need to try it, use it, overuse it, and find what works for you and your team. We're not in a codified science, so we have to work with our own experience.