The TDD Divide: Everyone is Right

I’ve been enjoying the back and forth regarding the Death of TDD on the interwebs. The intellectual volleying between “legalists” like Robert C. Martin (Uncle Bob) and “pragmatists” like David Heinemeier Hansson (DHH) is nothing short of fascinating. I have a tremendous amount of respect for both these gentlemen for different reasons, and I can see wisdom in each of their views.

DHH argues that an excessive fixation on unit testing has added indirection, abstraction, and conceptual overhead.

Don’t pervert your architecture in order to prematurely optimize for the performance characteristics of the mid-nineties. Embrace the awesome power of modern computers, and revel in the clarity of a code base unharmed by test-induced design damage.

Unit testing indeed isn’t free and, as DHH argues, provides questionable benefit to offset this cost. Yet he’s fixated on test speed being the reason that we code to an interface. I agree that fast integration tests that hit the database are much more practical in the age of SSDs and fast processors. However, speed isn’t the only reason coding to an interface has merit.

We also code to an interface so that:

  1. We can easily switch out the implementation behind the scenes
  2. We can agree on the interface and have two separate teams handle each side of the interaction independently and concurrently.
  3. We can abstract away an ugly DB schema or unreliable third party.
  4. We can write tests first and use them to help drive the design. Uncle Bob and Kent Beck see this as a core benefit. DHH sees this as test induced design damage.

I again see the wisdom of both sides. TDD has been shown to reduce bugs and improve design. Yet every abstraction has a cost and must be justified. The T in TDD is *more code*. Be pragmatic. The fact is, in many kinds of software, occasional bugs are an acceptable risk. When they occur, fix it and move on.

Uncle Bob is fixated on craftsmanship, perfection, and centralized control. His brand is cleanliness and professionalism. The idea that the era of unit testing could feasibly be replaced by automated integration testing is unsurprisingly viewed as illogical heresy to existing thought leaders in the space.

“It is difficult to get a man to understand something, when his salary depends on his not understanding it.” – Upton Sinclair

Of course, this quote cuts both ways. Some have accused DHH of declaring TDD dead merely because unit testing is hard to do in the very framework he created: Rails.

Bottom line

One important thing to keep in mind: Uncle Bob sells consulting. DHH sells software. It’s a common divide. Software “coaches” like Uncle Bob believe strongly in TDD and software craftsmanship because that’s their business. Software salespeople like Joel Spolsky, Jeff Atwood, and DHH believe in pragmatism and “good enough” because their goal isn’t perfection. It’s profit. So if you want to build the most beautiful, reliable, scalable software, listen to the consultant. If you want to build a profitable product, listen to the salespeople too.

The world is a messy place. Deadlines loom, team skills vary widely, and the impact of bugs varies greatly by industry. Ultimately, we write software to make money and solve problems. Tests are a tool that help us do both. Consider the context to determine which testing style fits for your project.

Uncle Bob is right. Quality matters. Separation of concerns and unit testing help assure the utmost quality, speed, and flexibility.

DHH is right. Sometimes the cost of unit tests exceed their benefit. Some of the benefit of automated testing can be achieved through automated integration testing instead.

My take: Search for the wisdom in both of these viewpoints so you can determine where unit testing has merit on your project.

What’s your take? Chime in via the comments below or on Reddit Programming. Like this article? Submit it to Hacker News

12 replies on “The TDD Divide: Everyone is Right”

  1. Cory,

    I don’t think you’re fairly presenting the “TDD” side. You’re hijacking the TDD advocate’s “it depends on the context” position, portraying the TDD advocate’s position as some extreme TDD-or-bust… but it’s not. Read what the “thought leaders” are actually saying about TDD, read what TDD’ers say and look at how we test… it’s not the extremist position you make it out to be.

    I’ll give you a personal anecdote: Recently, I was tasked to build a prototype of a new app. I decided to use Ruby/Rails for the backend, and I TDD’d every line of code of the backend. I chose Angular for the frontend, but… darn it, I don’t know how to TDD Angular code well. So I didn’t, and I did my best without tests. The prototype worked, and now we’re going to make it a real app. And as I’m working on this application, I *will* become better at TDD.

    Is this an example of Cory’s “context” position, where I correctly determined when not to use TDD? At a superficial level, yes… but here’s where things break down. My ignorance and inexperience meant that the best I could offer at the time was no TDD, but I will not accept my current situation as being acceptable in the long-term. My position is, “I can’t TDD, but I will learn.” The DHH position is “I can’t TDD, and that’s ok.”

    This is where I think you might, in action, fall in the DHH camp. From what I’ve seen in this post and our discussions on Twitter, I think your “it depends” position is just as extremist as DHH. All of us treat TDD as an option we may or may-not take when we code… but when you don’t, it’s not because you can’t or TDD isn’t an objective fit. It depends on *you* and your personal feelings towards it. Compare that to this… a few months from now, I’ll be TDD’ing Angular… will you? 🙂

    1. I disagree that DHH position is “I can’t TDD, and that’s ok.”. I’d summarize his position as “I’ve done TDD and found the cost exceeds the benefit for me when coding in Ruby with Rails…and here’s why…”.

      It’s interesting you mention TDD and Angular. We’re at the same place there. I enjoy TDD in C#, but I’ve admittedly never done TDD in JS. I’ve done automated post development integration testing instead. Angular is the first client-side framework I’ve used that feels really friendly to unit testing, so I’m looking forward to doing more TDD in JS.

      Thanks for the comment!

      1. Ahh… I don’t see the facts behind your DHH summary. I haven’t seen him claim to have done a lot of TDD, and I haven’t seen the TDD in his code or Rails, either. And when he blasts TDD, it’s not within the context of Rails, it’s *everywhere.* Again, I think the way you’re portraying these two sides is a little skewed.

        Gary Bernhardt wrote a great response to DHH here, in which he also brings up that DHH does not have in-depth TDD knowledge:

        If a developer dedicated him or herself to TDD for years… or months… or even weeks… how can he or she know all of its flaws and whether it should be used? I’ve been doing TDD for a few years now and I’m still learning about it… so how could someone with no practical experience know how bad it is?

        1. From “When I first discovered TDD, it was like a courteous invitation to a better world of writing software….I’d try test-first for a few weeks, only to drop it again when it started hurting my designs…”

          He’s done TDD. Whether it’s enough to meet your bar is subjective.

          And yes, I really enjoyed Gary’s post. A lot of great points about the weaker ends of DHH’s arguments.

          I continue to see the wisdom on both sides of this fence. TDD is a useful practice. But I’m no more religious about it than I am religious about Object oriented programming, relational databases, pair programming, daily standups, etc. They’re all useful practices in certain contexts.

          1. It’s not my bar — it’s an acknowledgment that humans must experience a fact before they know it.

            Replace TDD with C#. If I said to any .Net developer, “Oh, C# stinks, I used it for a little bit here or there, and I didn’t like it, it’s dead” you wouldn’t think: “Oh, that Darren chap has an informed view of C#, maybe there’s some truth to his issues with C#.” No, you’d probably think, “Darren’s entitled to his opinion, but it’s not an informed one.”

            TDD isn’t something you can pick up for a few days — it takes a lot of work and time. That’s a huge point in Bernhardt’s post that you like: He *knows* TDD, he’s done it for years, and people like him are more qualified to answer questions about TDD and its value than someone at the level of DHH. If Bernhardt is sitting on a side of a fence, it’s on the side of fact, experience, and everything else that constitutes human knowledge.

            Fences, religion… its just… words like that make it seem that you’re being very dismissive of a lot of smart, experienced people. They’re not blind, they’re able to see facts and make reasonable conclusions. It’s like you’re pushing them to the “extremes” and positioning yourself in the middle, the one who’s able to stick his head out from the fray and say, “You know what, you all make good points.” It’s ok to have strong opinions. 🙂 And with that, I’ll stop bugging you, have a good day!

  2. Great article! The point about perfection and “some sw can afford bugs” is spot on! Personally, I think this is unfortunate (as I tend to the perfection banner), but there’s no point in fighting facts. If you are in one of those cases, where they “want” bugs, when you take too long, even without bugs, you just took too long, and that’s all that matter.

  3. Great article. Everyone is right sums it up so well. There have been some great arguments on both sides recently that help people understand both the benefits and potential drawbacks on using test driven development. Striking exactly the right balance between quality and velocity will always be tricky and to some extent a matter of opinion. I will update my Is TDD dead post with a link here.

  4. Hello,

    I have some observations to make about your post and some points of DHH.

    First, and may be the more important, to criticize something, I think it is good to have enough experience in the subject. In the case of TDD IMO some weeks is not enough (it seems to be the DHH case). And I am speaking as one who saw this in practice in my company. Sometimes one see the value of TDD in the first day, but in general, at least here in my job, our experience was that it takes at least three months to people start to see the value of TDD. It is a average value. Some takes more time. So we talked to people to try at least in one project before give up. I remember one come and talk with me and say: “men I confess to you when I started with TDD I thought ‘what shit is it? No way to work! Now I can´t see myself programming without it'”.

    Second, your affirmation that both are right because one is a consultant and wants a perfect system, and the other is pragmatic and just want a system that works for me is not fair. With this statement your are almost saying that the second is the right one.How many of us are consultants and how many of us are just developers? Who does not what a system that works as fast as possible with the minimum work? When a novice see a statement like this what you think they will think? Of course the pragmatic view. When you say that uncle Bob is correct because he is a consultant and has to sell the ideal world and, of course, we do not live in an ideal world, the message, for me at least, is to see what he says but not take much account.

    Other message that I see in this pragmatism is that the practices like TDD was born in theory, in a lab, or some PhD thesis. It just the contrary, it was born in the trenches by programmers and is used today in real projects. A better explanation about this “pragmatism” can be found here but I will quote an excerpt:

    Sometimes calling attacks on techniques and methods “pragmatism” betrays a belief that techniques and methods are born in a lab, in an ivory tower, by theorists who have never written a line of code, but who have some theory they’re trying to push on the working class so that they personally can become rich.

    That’s an interesting theory. It is just entirely wrong. The XP practices came from an actual project, where some of the finest programmers in the world were engaged to produce a real product. They were not in an academic environment far detached from reality, nor were they in a low-pressure greenfield. They had real work to do and getting it done was not optional.

    So I don´t agree with your conclusion that Uncle Bob is selling the ideal world and he is right because he is a consultant. I think he is selling what he thinks is good to most of software development. That practices are easy? No. You may encounter resistance do apply it? Yes. For example, the first project here with ATTD and TDD we suffered a big pressure from higher managers to drop all the tests because they think the tests are slowing down the development. And, in the beginning, it was true. But we had a great belief that the TDD practice (Acceptance and unit TDD) will save our skins when future changes was required. We stay with TDD and it saved us many times. And you could say that was not TDD. It was the resulting automated suite of tests. And this suite could be created with or without TDD. And I will say you that it was TDD because:
    – the unit tests created helped us to build a design that was easy to change after;
    – other project tried TLD (test last development) and they had problems because: – the design was not always testable and they say that do not have time to change to be testable;- as the tests are created after, was more easy to upper management to drop them. “The code is ready? Put in production.” In our case, when the code is ready the test code is also ready because it was done first.

    What I see a lot in software development is people worried about the speed in which they can develop and forget about the maintainability. They forget that in the vast majority of cases, the time a system is under a maintenance phase is much greater than the development phase. So, in general, I favor practices that improve the work in the maintenance phase than the development phase. If I have to drop the speed of development in favor of maintenance, I will do that. And I think what Uncle Bob is selling and others “consultants” is selling is just ways to improve the quality of resulting code. Despite this talk about the drop of speed in favor of quality, many believes, I also, that the focus in quality will speed up development in the long run. Particularly about TDD, I think it improves my speed of development.

    Other areas of knowledge has it quality guidelines: medicine, accounting, engineering… For example, correct me if I am wrong, all accounting has to use the double-entry bookkeeping system. It is a minimal quality guideline that all counters has to respect. Uncle Bob believes (and so do I) that TDD is one practice that would be part to the quality guidelines of software development. If it is true is other thing. The future will say. But, I completely disagree that he is defending TDD because he is a consultant and live in an ideal world. I don´t live in and ideal world and we practice TDD in our job.

    My main language is not English so sorry if some part of my text seems to be offensive or is not very clear.


    1. Thanks for the comment Josue. I am merely pointing out that the views on both sides have merit. If you watched the “Is TDD Dead” Hangout yesterday, I think that was clear. Even Kent Beck and Martin Fowler acknowledged that they often don’t do TDD and consider the context. I really appreciated Kent’s post on StackOverflow:

      I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence (I suspect this level of confidence is high compared to industry standards, but that could just be hubris). If I don’t typically make a kind of mistake (like setting the wrong variables in a constructor), I don’t test for it. I do tend to make sense of test errors, so I’m extra careful when I have logic with complicated conditionals. When coding on a team, I modify my strategy to carefully test code that we, collectively, tend to get wrong.

  5. Well written unit and integration tests lead to maintainable code. The larger the team, the greater the churn, and the more critical the application, the more important tests become.

    Writing a small app or script that is not mission critical? Fine, do away with test-first development. But the larger the team or the more complex the project, the more valuable test-first development becomes.

Comments are closed.