Live data from Hacker News

Why TDD isn't crap

hillelwayne.com

151–160 of 171 posts

Re: Why TDD isn't crap

#151

Earlier quoted context omitted.

> we can classify the integer into three states: less than zero, zero, greater than zero Err, not quite. We're running on computers, remember. A comprehensive unit test that doesn't go through every possible integer input should still include: maximum and minimum integer values for that size maximum and minimum expected inputs 0, 1, -1 So, there's 7 test cases for a single integral input. And since you bring up banki…

If you mean "nobody would write 49 tests for a function when they could get away with writing one test and have it show up as 100% code coverage because people are lazy bastards" then I agree, and that's the problem: cargo culting the metrics. Look we have 100% code coverage! We are awesome! If you mean, "no look seriously, you'd need 49 tests for every method because you're a bank", well then, no, you actually need…

> some are subsets of the others

In a purely mathematical sense, yes, this is true. But with computers those subsets matter. For example, I wouldn't drop the "max expected" for the "maxint" test; an overflow exception or implicit type change in the case of the latter shouldn't be tolerated for the former.

> That means that your method is too complex.

Would you consider the Python `requests` library's `get` method to be too complex? It has 10 parameters to it: 4 strings, 4 dictionaries, 1 file-like object, and 1 tuple/AuthHandler option.

If you conservatively say there are 5 test cases which should be tested for each parameter (a very low count, especially with strings and dicts), there's approximately 1,125 test cases that should be explored.

Not quite a trillion, but it's still a lot.

Re: Why TDD isn't crap

#152
post #35
post #8

Like the author, I subscribe to the less strict view that TDD isn't necessarily about writing the test first, but rather about having test play some part in how the code takes shape. Unlike the author, I absolutely believe that tests are about design. More specifically, they're about identifying coupling so that you can reduce it. The function being "awkward" to use is part of it, but code which is hard to test is al…

"having test play some part in how the code takes shape" That is exactly the point why I don't like TDD. I mean, there are enough constraints that shape the code, why should something artificial like tests shape it too? With mocking and everything you end up writing code for tests and not code for your problems.

I'm not hearing anything negative here. Why is any of this innately bad?

Tests shaping your code is bad, because? Because you already have "enough constraints"? Sorry, I don't get it.

Re: Why TDD isn't crap

#153

I expect the reason TDD is so controversial on here is people can't see the long term benefits of tests, and instead only think in the short term. But in the commercial world, code you write can potentially have a lifespan of 30+ years. In this case, making a choice to write tests is the difference between writing a maintainable component in the future vs writing a soul-destroying 'legacy system'. If you agree tests…

This whole thread is a response to: https://news.ycombinator.com/item?id=15591190 Your points are directly addressed in the pdf. One of his general points being, in practice, the tests become the legacy system instead. And I'd add to that. Given that you've at minimum doubled the code (and doubled the bugs), it seems like a really bad long-term trade off. Also DI does not reduce coupling. I've seen plenty of code wit…

> Given that you've at minimum doubled the code (and doubled the bugs), it seems like a really bad long-term trade off.

I'd say you've at maximum doubled the code. The test ensures you write only what you need to get the test pass. Without them, devs get distracted and wander until the feature works. Usually distracting themselves with tons of YAGNI violations along the way. In my experience, untested code bases have a ton of unnecessary code.

I don't understand how it would double the bugs. The article has references saying it reduces them. But, even thinking about it, I don't see why you'd say that.

Re: Why TDD isn't crap

#154

Earlier quoted context omitted.

If you mean "nobody would write 49 tests for a function when they could get away with writing one test and have it show up as 100% code coverage because people are lazy bastards" then I agree, and that's the problem: cargo culting the metrics. Look we have 100% code coverage! We are awesome! If you mean, "no look seriously, you'd need 49 tests for every method because you're a bank", well then, no, you actually need…

> some are subsets of the others In a purely mathematical sense, yes, this is true. But with computers those subsets matter. For example, I wouldn't drop the "max expected" for the "maxint" test; an overflow exception or implicit type change in the case of the latter shouldn't be tolerated for the former. > That means that your method is too complex. Would you consider the Python `requests` library's `get` method to…

Without getting into the pros and cons of python (which will likely get me downvoted to oblivion), 'get' is an example of what I would call a coordination method.

I coach my teams to think of two kinds of methods: methods that do data processing, and methods that coordinate. To test a coordination method, you don't need to care about the value of the things it has to deal with. Maybe you care the they are not null, if your language has nulls. But other than that, what you are testing is that if your method A is supposed to pass arguments 1 thru 5 to method B, and 4 thru 10 to method C, then that's what you test. You don't need to test that argument 1 is a positive integer. The test for method B will do that, if it needs to. And finally you might test that if we expect the result of method B to be passed to method C, the test for our method A would do that using a mock B. Again, what mock B returned could be any object: we only care that it got passed to C.

So it looks like its 1,125, but its actually three.

If we have classes that are SOLID, then we tend to see the processing methods and the coordination methods end up in different classes. sessions.py isn't a great example of SOLID, and I would have a hard time writing tests for it. It is certainly not the kind of code you get if it was written with TDD.

Re: Why TDD isn't crap

#155
post #6

TDD isn't bad at all for a mature product where you have clear requirements for additional feature development and granular developer tasks. I've just seen a lot of it where a product is still in broad strokes development and developers get stuck between whether having tests written based on early assumptions are correct and the code should conform to those, or whether new ways of thinking that invalidates the early…

Tests allow you to easily refactor implementation and allow you to add features without worrying as much about breaking the existing interface. However, they're terrible if you want to refactor your design and correct problems with the interface itself. Tests freeze the interface. This is really good for whole classes of problems but terrible for other classes of problems. The debate is going to continue endlessly as…

That is why I almost exclusively tests against external interfaces, since those should be frozen anyway (so others can depend on it). If the system is a web service that means the HTTP API, if it is a JS library it is the public API etc. And conversely almost no tests against internal interfaces, since internals don't matter and should be free to change.

Re: Why TDD isn't crap

#156
post #101

I guess TDD can be great for parsers.

In the classical way of setting up the parser, passing some example input and then asserting some things about the output? It's good for covering basic features/usecases. Since setup is always the same, it should be written as a list of input/expectation pairs (data driven). But coverage is typically limited by the effort needed to write the assertions - which grows in parallel with the input complexity.

If one also writes a serializer, then one can additionally test for any input the property: `serialize(parse(input)) === input`. This means adding a new test is just dropping in more example inputs (say from bug reports).

Now one can go further, and define a set of mutation operators that can act on input to produce a new valid input. Reorder tokens, change data at leaves, delete and insert new data, etc. Now one can generate arbitrary amounts of new test cases based on existing input examples.

Other mutation operations can be designed to generate invalid inputs, which should always give an error (never crash, halt or unexpected exception).

Re: Why TDD isn't crap

#157

Earlier quoted context omitted.

Further agreement. I haven't looked at a textbook on programming recently, but I'm worried that the standard is still to actively teach new developers to program this way, even though we've _known_ for decades that towering piles of subclasses invariably collapse under their own weight. That said, I still wouldn't lay this tendency for damaged design at the feet of static typing in general. Not when some of the most…

I don't blame statically typed languages. But, yeah, they are a bit more unforgiving if you need to refactor your way out of that mess is all.

Static languages make refactoring easier, not harder. The more information you have at compile time, the more automated tooling can do for you.

Re: Why TDD isn't crap

#158
post #78

I have been attempting at TDD on and off for about 3 years. It never really took off for me. I would spend most of the time writing the tests, then implementing the code, then only to find out that a lot of my tests don't make sense, or are overthoughts that don't really add business nor technical value. However, I think I reached my sweet spot just weeks ago. Here is my optimum workflow now: 1) Write test cases (the…

I've been trying to get into TDD myself for years. I've read the 2 most suggested books and another book that had "testing" in it. But I still came back with issues. I don't program Java, so I don't understand some of this code, so I can't just convert it over to the languages I know. The examples were of basic stuff like "Lets make something that adds two numbers", "Here's a basic mock, lets not worry about DB queries", etc... It really didn't teach me how to think in TDD, it wasn't specific for the languages I program in, nor did it touch on things like "real time data" coming from a stream source, which I think is "How to think in TDD and how to program to fit it."

Re: Why TDD isn't crap

#159
post #8

Like the author, I subscribe to the less strict view that TDD isn't necessarily about writing the test first, but rather about having test play some part in how the code takes shape. Unlike the author, I absolutely believe that tests are about design. More specifically, they're about identifying coupling so that you can reduce it. The function being "awkward" to use is part of it, but code which is hard to test is al…

I think TDD (or rather, unit tests): 1) ... over-emphasise the importance of reduced coupling, and can actually increase the chances of integration failures. Why? Because components are tested in isolation rather than together, but are still considered "tested" - especially when using stubs and mocks. I've seldom seen mocking used well, it almost always over-specifies implementations. 2) ... increase the tested "surf…

I worked at a place recently where all of these factors, but especially (3) turned out to be a huge cost for an ostensibly simple service that it severely hampered any further development. Since it was a hard TDD shop, any discussion of cutting out all the intermediate layering was completely off the table. Internal structure was easily 75% of the size of the project.

After all, a lot of effort had gone into building all of the internal mocks, and while many of the early design decisions enshrined in the tests were quite dubious, to revisit those assumptions would have been backsliding. Even though there were no users to speak of yet, the existing tests had to pass.

And of course because of (1), the product didn't actually work because there were no integration tests at all. Because all of the unit tests passed, the ongoing assumption was that the platform was basically sound.

The most charitable thing I can say about TDD given that context is that it might be valuable, but isn't sufficient.

Re: Why TDD isn't crap

#160

Earlier quoted context omitted.

I don't blame statically typed languages. But, yeah, they are a bit more unforgiving if you need to refactor your way out of that mess is all.

Static languages make refactoring easier, not harder. The more information you have at compile time, the more automated tooling can do for you.

The more compile time information you have, the greater coupling you have as well. Make User subclass Entity for polymorphism reasons and now taking a User parameter makes your business logic depend explicitly on your ORM.
Post reply on HN