Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The big tdd misunderstanding is to believe that it provides good test coverage.

TDD is about designing how a module is going to be used before actually implementing it.

It’s about considering the API as a product, rather than a side effect of the implementation.

It’s about putting oneself in the user’s shoes, instead of making it as easy as possible for the implementer.

Test coverage depends on the implementation, so you can’t design tests that will ensure 100% test coverage before implementing the stuff.



> TDD is about designing how a module is going to be used before actually implementing it.

This. Basically, TDD is exactly the same as BDD, only with a developer-oriented (as opposed to product-oriented), traditional assertion syntax.


BDD is more about having conversations about behavior with stakeholders using examples.

If it's translated into tests it becomes ATDD. These make excellent tests which catch bugs and provide a safety harness for refactoring. It is the sole place where "TDD" actually shines.

Lower level TDD that isnt about that at all are where all the problems are (including, frequently, driving poor design).


> driving poor design

Would you care to expand on that?

Let's say you are doing a classicist style TDD, where you try to mock at the highest level you can (files, network, UI) and then just exercise all the classes in between until you reach your target piece of code.

Can you give me examples of TDD producing a bad design?

I can see how a mockist approach, where you mock everything for each function you test, can be detrimental very quickly. But I have the feeling I'm mastering the classicist approach, and I don't see how tests can negatively impact design.


See "Test Induced Design Damage" by David Heinemeier Hanson.


This second definition was retroactively added once it became clear that TDD’s not good at testing. Unfortunately it’s even worse at designing since it’s only capable of “designing” how something may be tested and used without addressing any e.g. non-functional requirements, data structures or algorithms.

There’s tension between testability and good design (encapsulation, achieving more through abstraction, hiding/reducing complexity, usability, etc). Starting the design process from API or method calls makes no sense at all unless one wanted to reanimate a failed testing method.


I would call code coverage "good" when I trust that:

- When I change the logic of a statement somewhere in the code, at least one test will fail in the suite.

A high % in a test report may give an indication but is far from giving me confidence. Having good code coverage means that, once you are back to green, and you have done to test code what will keep or improve your code coverage confidence, you can send the PR being tranquil that you didn't break anything else.


> The big tdd misunderstanding is to believe that it provides good test coverage.

Have you considered that, because TDD is a design practice (a 'meta-design') for writing code, there is no "one correct" interpretation, or misunderstanding, just different understandings? Yes, the people might be misusing it as per your understanding of it, but you are not the center of the universe here.

You are correct that "it's about X", the people who are misusing it are also correct about their interpretation of it. Fundamentally, all TDD is the 5 steps of "writing a test first, and writing code that makes that test pass", along with some mentions of other meta-design approaches like KISS, etc.

The way someone understands a meta-design is driven by a lot of factors, the way someone uses a meta-design is subject to the cultural context in the place you use it, the design restrictions and constraints of your tooling, the meta-design constraints of what practices management is willing for you to devote time to, etc.

So fundamentally, you cannot create a design practice (or meta-design) that is applicable to all scenarios and circumstances. TDD will be outright inappropriate for some situations. This is exactly what "design patterns" are about, finding similar or identical ways of designing code, categorizing them, and figuring out what circumstances they do and don't work in. Now, I guess we need "design practices patterns", so we as an industry can move on to figuring out what practices are fit for certain scenarios, and what scenarios they are unfit for.

Ultimately, anything less than the understanding that "context is king" is likely to lead to people just going around in circles and talking past each other.


Have not read the article yet but I guess it can be solved using incremental tests. First we write the tests for the core features of the API then while implementing it to pass the tests, we'll find that there arw some edge cases that we have not consider, so we write tests for them. In addition tests framework like jest provides good API around the coverages.


I would like to see how to design a 3D rendering engine or distributed transactions infrastructure with TDD.



I had one interview a few years ago when I had to solve FizzBuzz in a TDD way; I realised quite quickly that to solve the problem as described with TDD resulted in a more complicated solution, including things like changing the API to allow me to inject a "printer" so that the test could pass a double instead.

Still a very easy problem, but the irony of TDD making FizzBuzz harder made me smile.


> including things like changing the API to allow me to inject a "printer" so that the test could pass a double instead.

In what language? Isn't the basic case of fizzbuzz a procedure/function that takes a number and returns a string (if you are strongly typed, not able/willing to return a complex type)?

Printing and reading input would be side-effects, surely? (so you plug the input to your fizzbuzz, and the output to a stream, maybe via a formater?)


The only formulation for FizzBuzz that I've seen 'in the wild' is "Write a program that prints XYZ (to standard out)"


I don't think treating it as two subproblems: generate a sequence xyz, print the sequence to standard out - is terrible over-engineering - especially if it enables simpler tests?

Ed: or in the case of fizz-buzz; a function to transform a number (returns "<number>", "fizz", "buzz" or "fizz-buzz"), a function that maps a sequence (eg 1..100) via fizbuzz(), and then a function that prints such a sequence.


As in dagw's reply. The question as posed to me has always asked to write code that prints to stdout.


TDD expands to Test Driven Design for me rather than test driven development.

I have found TDD to be an extremely useful tool in cases where I was not sure about the design but knew what the requirements were.


As a corollarly, it often results in mostly functional code that is easy to test without any mocks, so good coverage usually happens "by accident" (not really).


i think you may have suddenly helped me to finally grasp the true essence and nature of tdd. woah this makes so much more sense


> TDD is about designing how a module is going to be used before actually implementing it.

My problem with this is that Tests != Design.

I hear this all the time "Oh, TDD isn't about having 100% coverage it's just making sure developers think about what they make before they make it"

If your developers don't think before they build, fire them

Tests aren't design.

Tests also aren't documentation, which is the other thing I hear a lot.


Code is the canonical source of truth.

Tests are executable examples of code under use in different scenarios, usually showing both input and output.

Textual documentation is an attempt to extract the most useful bits of the first two into a more manageable form, and potentially explain the reasons for said code's existence if it's not obvious. It will always go out of sync with code in small ways that will bite you, unless you've got executable documentation like some OpenAPI implementations or the venerable "doctests" in Python.

All of them are ways to learn about the API, or iow, "documentation".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: