yield thought

it's not as hard as you think

TDD without the T

with 40 comments

While discussing our natural tendency to spend too much time and effort refactoring code, Jul (aka -jul-) raised an interesting point:

This is why I think TDD is good. According to the rules, you should not write a single line of code before having a failing test, but you should not write more than one failing test. Then write some code which makes the test pass, but then, start over (eg. don’t write code).

If you follow this cycle, you won’t code l’art pour l’art.

Haha.

Odds are you’ll end up writing tests l’art pour l’art.
— Jul, commenting on 7 Reasons To Hate Your Code

Note for those coming from digg: “l’art pour l’art” can be translated as “just for the sake of it”. Much love, my friends.

When I discovered TDD back in 2003 it came like a breath of fresh mountain air sweeping through the midst of my abstraction-freak analysis paralysis. At last I could code relaxed again, without trying to over-engineer every single feature. It set me free.

Years later I couldn’t help noticing I was writing more test code than program code and that I’d stopped working on side projects, because every time I started I thought:

Ok, I’ll hack out a prototype for this cool little game in no time. So, well, I guess I’d best start by writing a few tests for the core mechanics. Right, time to get my framework out. And… uh… ugh, maybe I’ll go watch some Buffy instead.

Writing tests turned me off the whole enterprise so much that eventually I decided I’d just write without them. And nothing awful happened! In fact, it was as much a breath of fresh air as I’d first felt when I started. What gives?

It wasn’t until reading Jul’s comment yesterday that I realized why this was: I hadn’t stopped doing TDD, I’d just stopped doing the T part.

Essentially, the core of many test-driven development processes looks something like this:

  1. Make a list of features and prioritize them
  2. Pick the most important or fundamental feature
  3. Write test cases for it and implement just enough code to make them pass
  4. Repeat form step 2 until you’ve got something useful

I hadn’t stopped doing this, I’d just skipped the “write test cases” part. Writing just enough code to implement the tests you would have written turns out to work just as well!

Let me be clear – I both like and appreciate unit tests. There are many places in which I still use and rely on them. You’d be crazy to skip the unit tests when you’re writing a complicated translation function, or implementing a novel data-analysis algorithm. However, it was still an eye-opener for me to realize that there are places in which they’re a waste of time. Shock! Call Kent Beck! No, it’s true. Albert Einstein backs me up:

Make things as simple as possible, but not simpler
— Albert Einstein (somewhat paraphrased)

Thanks, Al. In this case, testing your accessors and adding half a dozen interface patterns just to support a burgeoning test suite isn’t as simple as possible. Writing no tests at all for your parsing code is too simple. Finding the perfect level of minimalism between code, tests and bugs is difficult, but liberating.

The truth is, doing TDD for all those years changed my programming style, moulded it into a new, more efficient form that stays efficient even when I stop writing tests for everything. I guess this is common; maybe you should try abandoning your test-first framework for your next side-project and see how it works out for you.

TDD without the T: you may find it surprisingly refreshing.

Note: Yield Thought has moved to http://yieldthought.com – check there for the latest posts!

Written by coderoom

April 27, 2010 at 7:15 am

Posted in Programming

Tagged with , ,

40 Responses

Subscribe to comments with RSS.

  1. You know, the more I read your blog the more I realize we’re both at the same stage of our coding careers.

    I’ve gone through the same thing and arrived at the same conclusion.

    TheSandyWalsh

    April 27, 2010 at 12:37 pm

  2. I think the key is to always know beforehand how you could test the code, whether or not you actually write any tests. And I also believe that running the code can count as TDD. In other words, if you know how you’re going to run the code, and you can get the code to run correctly, then you’re basically doing TDD, just without unit tests.

    Jacob

    April 27, 2010 at 3:14 pm

  3. I believe I understand what you are talking about here. I would like to emphasize something you wrote:

    “The truth is, doing TDD for all those years changed my programming style, moulded it into a new, more efficient form that stays efficient even when I stop writing tests for everything.”

    With new programmers, I have found that if they are not testing everything, they don’t have an understanding of how hard their code can be to use and change over time – since it’s development was not driven by tests.

    Having been trained to write everything with a test first, 10 years later, I believe I can write code as you describe. Yet I must also say:

    * Writing tests has never blocked me from building open source software – small or large.
    * Confidence IS lost, whether a little or a lot, when whole features have no automated tests. I feel the productivity gain you speak of by not always writing a test, but I have also been a little less confident that everything is working as it once was.
    * This philosophy/discovery seems to depend quite heavily on having exclusive authority over the code, whereas we sometimes must work with less experienced TDD programmers.

    I like “Make things as simple as possible, but not simpler”. Having written my ‘must say’, I think now how I’ve come to the conclusion, “Write tests when you sense any fear, or the code doesn’t work as expected, or when you are in the debugger of a running application.”

    Thanks for the post.

    Adam Williams

    April 28, 2010 at 11:42 am

    • This is a great piece of advice about how to decide when you should work test-first and when not. You should write it up in a blog post before I do, and when you do send me a link 😉

      coderoom

      April 28, 2010 at 11:51 am

  4. Wow. I totally agree with you. Your thoughts here affirm my thoughts over the past year on this subject. Tests are good – but they are not the holy grail and are always prone to failure. They add an additional level of confidence only.

    tsells

    April 28, 2010 at 1:00 pm

  5. Erm… I think you’re going to have to think of a new name for it though. After all “Driven Development” doesn’t really make much sense. 🙂

    Jason Baker

    April 28, 2010 at 1:22 pm

  6. I wrote about something similar a while ago: “Things I learnt by not writing tests”

    http://rfw.posterous.com/things-I-learnt-by-not-writing-tests

    Rob

    April 28, 2010 at 1:31 pm

    • Hey, yeah – I must’ve missed it when it was on HN. Funny how these common experiences (judging by the comments on both posts so far) start to bubble up into blog posts in a similar timespan. I guess in a year or so it’ll just be something everybody always knew.

      coderoom

      April 28, 2010 at 1:56 pm

  7. I feel kinda similar. I now start by writing the interfaces or public methods of classes first, just so I can quantify what responsibilities the class I’m writing should have.

    That said recently I refactored a huge chunk of code that I’ve been working on for years, and I really wouldn’t have been happy doing that if I didn’t have some serious unit test coverage.

    Tom

    April 28, 2010 at 1:46 pm

  8. Well said.

    If you’re working on a side project you’re free to skip the “T” out of “TDD”. If you wrote bad code, you’re the only one who suffer. If your refactoring effort leads to more bugs because there’s no unit-test, still, you will suffer alone. Nobody else will be pissed off.

    When it comes to professional work and the task is not prototyping, we cannot leave the “T” out of “TDD”. There’s always that one programmer that would write extra code, extra features, extra layers, extra mayo or whatnot.

    Ted

    April 28, 2010 at 2:18 pm

  9. Thank you. Thank you! I came to this realization in the middle of a project in which I challenged myself to employ TDD the entire life of the project. The T isn’t necessary for everyone — like Ted said, some people *need* it or they will run amok. But for others, it simply gets in our way and we’re better off without it.

    Sherrod

    April 28, 2010 at 2:26 pm

  10. I totally agree. Do this very often. Whenever I do it, it’s called a “spike”.

    Of course, whenever I write a spike I refuse to distribute it or put it into production. If I need to distribute the code or put it into wider use I scrap the spike and do the work TDD. A funny thing is that the TDD’d code is always noticeably different than the spiked code.

    As someone else pointed out (directly or indirectly), the “T” in TDD gives at least two solid benefits:

    * refactoring is possible, even aggressive, far-reaching refactoring
    * other people can work on your code — the code acts as not just documentation, but a safety net for them as well as they add new features without necessarily understanding 100% of the system

    This is presuming that “DD” code is identical with “TDD” code, which my limited experience has shown to be unlikely, at least from where I sit.

    Rick

    April 28, 2010 at 2:49 pm

  11. Hello there. Im a first time caller.

    Firstly, let me say I totally dig the name of your blog “Yield Thought” is awesome.

    But it gets me thinking about what the T in TDD is giving you as you code. Think “Yield Feedback”. If you cut the T from TDD, but are still getting the feedback you need, then all well and good.

    For me the dev cycle needs to be pumping back a rich stream of feedback at me that I can feed off of to grow my code. The T in TDD does that in a real dumbed down way. Its trivial to run, and if I pick up the code a year later I can interpret the feedback again quickly.

    So drop the T by all means if it works for you, but there is probably something else in there that is giving you the feedback that is sustaining you. Wheter that will tick all the boxes for you (and anyone else who happens along) over the life of the code will be the ongoing question.

    Ross Duncan

    April 28, 2010 at 2:49 pm

  12. […] full post on Hacker News If you enjoyed this article, please consider sharing it! Tagged with: Better • […]

  13. An argument for tests. In a team (>3 developers) on a project that will have a lifespan (1+ years) where the cast of characters will change over time, tests provide continuity. The tests specify how functionality is meant to behave. Changes to code can be made with reduced worry about breaking existing functionality. When you’re working in this kind of environment, you need to expand your horizon beyond your code and consider the needs of the team and the organization.

    andy

    April 28, 2010 at 2:57 pm

  14. perhaps it’s not about removing “T” but adding the word “selective” in front of the acronym 😉

    does self-explanatory classes that has nothing more than accessors or wrappers to business objects warrant unit tests?

    mykol

    April 28, 2010 at 3:06 pm

  15. It really doesn’t make sense for me . In a development process, you will have to test what you are doing anyway, even if you’ll use manual tests. In automated way, you’ll not need to repeat manually all of your tests.

    Cheers,

    Emerson

    Emerson Macedo

    April 28, 2010 at 3:12 pm

  16. Funny thing, Kent Beck just twitted a link to this post a couple hours ago.

    Ariel

    April 28, 2010 at 5:09 pm

    • I know! Kent Beck read my little TDD post – how cool is that? I guess someone took ‘Call Kent Beck!’ really literally…

      coderoom

      April 28, 2010 at 5:17 pm

  17. This is the ‘end state’ that I’ve (almost always) advocated for TDD to skeptics.

    I’ll say something like: “You need to *start* by always writing the tests firsts. Yes, it’ll seem silly and tedious. No, you won’t necessarily do it forever. But you need to *do* it in order to train yourself to design testable code, ’cause what you’re doing now isn’t working.”

    SJS

    April 28, 2010 at 5:36 pm

  18. Design by Contract probably gets your there faster than TDD

    mempko

    April 28, 2010 at 5:41 pm

  19. I think the problem you’re getting at is that unit tests are simply too low level. You might find a better experience by writing integration and functional tests based on specs in lieu of unit tests. This enables you to get the benefits of writing tests first and without the frustration you describe.

    This approach has other advantages that I touch on here (http://binstock.blogspot.com/2009/11/limitations-of-tdd.html).

    So, I think it’s not the T in TDD, but the implicit U (as in Unit) that silently precedes the T that causes the trouble.

    Andrew Binstock

    April 28, 2010 at 6:08 pm

  20. Even if you adopt a coding style where you don’t write tests most of the time, tests are still very useful for preventing regressions. Whenever you discover a bug, it’s probably worth your time to code up a test case for it so that you never re-introduce it. I like making new mistakes instead of making old ones again.

    Ryan

    April 28, 2010 at 6:58 pm

  21. What you say makes a great deal of sense to me. Which is hardly surprising given that, by coincidence, I’ve recently been saying rather similar things. If you’re interested, see “Testing is not a substitute for thinking (binary search part 3)” at http://reprog.wordpress.com/2010/04/23/testing-is-not-a-substitute-for-thinking-binary-search-part-3/

    Mike Taylor

    April 28, 2010 at 9:10 pm

    • Yeah, Rob wrote something similar a while back too: http://rfw.posterous.com/things-I-learnt-by-not-writing-tests – it must be something in the air this season…

      I saw part 1 of your series when it was on HN – writing a binary search in python without testing it is still on my list of things to do when I’m bored. I don’t know why, but I find the giant sushi pictures between your paragraphs kind of disturbing…

      coderoom

      April 29, 2010 at 7:13 am

  22. […] TDD, Test Driven Development, Without the “T”? You may enjoy it! (via Yield Thought) […]

  23. I understand that your experience allows you to drive design and code without writing tests. It can work fine when you work on your own, but do you think this approach can scale when working in a team with many developers?
    With this approach you are left without anti-regression tests and the confidence in code can be lost. As long as writing new code using this approach can have advantages, maintaining code without tests can become risky and require more analysis before every change.

    Bartosz Blimke

    April 28, 2010 at 10:30 pm

  24. […] TDD without the T While discussing our natural tendency to spend too much time and effort refactoring code, Jul (aka -jul-) raised an […] […]

  25. You made me remember of “The Secret”. They say that you don’t have to actually do. It’s enough to visualize.

    http://www.law-of-attraction-guide.com/visualization.html

    Adolfo Neto

    April 29, 2010 at 12:15 am

  26. Ummm…. no, thanks. (hands the crack pipe back)

    I work on too many distributed teams with stakeholders (particularly developers) of widely varying experience and outlook. We’ve all been through too many projects where honoured-mainly-in-the-breach testing has led to Spectacularly Bad Outcomes™. TDD-based process and mentoring via “distant pair” programming has helped several now-quite-good developers improve their Craft in far less time and angst as would likely be accomplished otherwise.

    I went through a phase like you’re describing about 2-3 years after I started doing rapid iterative development (what TDD was called in the decade before Kent Beck, at Motorola, JSC and elsewhere). All it took was one seriously blown schedule — off by about 60% on a five man-year project — to have a rethink. Our “what went wrong?” exploration identified *over two dozen* instances where, had we followed our “traditional” write-tests-first process, we would have eliminated *all* identified technical failures. And that was with a group of fairly uniformly mid-career developers all grouped together on one floor of one building and a VERY collegial culture; if the assume-we-wrote-the-tests-but-we-really-didn’t metaphor were going to work anywhere, by rights it should have worked there.

    As it was, our program manager gave our tech lead a small sign in a beautiful wooden frame: “ASSUME is a contraction. It expands to ‘make an ASS out of U and ME.”

    The six projects I completed with that team after this incident, using our RQID process (proto-Agile) as intended, were all delivered on time, under budget, to enthusiastic user response. We learned our lesson.

    Jeff Dickey

    April 29, 2010 at 3:54 am

  27. […] TDD, Test Dri­ven Devel­op­ment, With­out the “T”? You may enjoy it! (via Yield Thought) […]

  28. […] TDD, Test Driven Development, Without the “T”? You may enjoy it! (via Yield Thought) […]

  29. Nice post!

    (without reading the mass of comments ;-))

    But I think you meant: “without automated tests”. I doubt you didn’t run your program to verify that it does what it should. Because this is also TDD … with the advantage/drawback of not having persistent/automated tests.

    karussell

    April 29, 2010 at 12:37 pm

    • This is NOT Test Driven Development if you are not writing test before your code and only enough code to make your tests pass. But I also hope that no one would be stupid enough to release completely untested software.

      I don’t think that growing past the rigid steps of TDD is a natural stage in a developers career. I am part of a new generation of developers who begun their careers using TDD practices, and to be honest, I wouldn’t want to work with someone who consciously choose to write code before testing it.

      If this is what you want to do on your own time for your own, 1-man projects then all the power to ya. If you are working in a collaborative environment where your software will be supported over a long time and maintained by someone most likely not yourself, then you better be writing tests before any lines of code.

      The other step I see a lot of people in this thread forgetting is the refactor step of the “Red, green, refactor” steps in TDD. How can you safely refactor with confidence that you aren’t breaking functionality when there are no regression tests? Sure you can manually test everything at the end of a project and start doing other waterfall development practices too but I prefer to stick to my Agile + XP methods which have already proven to be more effective.

      I am not about to write a blog post saying that I am ditching pair programming because explaining everything to my pair takes more time. I recognize it’s draw backs but I am well aware of the consequences of the alternatives. It appears not everyone is aware of the consequences of writing untested code.

      Jesse Webb

      April 29, 2010 at 2:56 pm

  30. It would have been better to just say that you were too lazy to write your tests.

    Bruno Pedroso

    April 29, 2010 at 9:30 pm

  31. Overly writing test hurts. I understand that. However, the solution for this is not to stop writing tests, but start writing tests *because* the client needs it.

    In my case BDD is the tool which keeps me on track.

    -jul-

    April 30, 2010 at 12:50 pm

  32. […] An example of a specific methodology would be Test Driven Development (TDD).  There are many people in the agile community that swear by this concept.  There are just as many that do not believe in it.  I am somewhere in the middle.  I believe testing your code at the unit level is imperative.  Having a high level of test coverage on your code is not a bad thing.  However – we do live in a world where in the end you have to deliver software.  There is a delicate balance between writing production code and test code.  Writing tests for the sake of writing tests however seems wasteful.    A good article on this concept can be found here.  […]

  33. […] TDD, Test Driven Development, Without the “T”? You may enjoy it! (via Yield Thought) […]

  34. […] I noticed it but I couldn’t put words on it untill guess who twitted about about a blog article: “TDD without the T“. […]


Leave a comment