11 ms·
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 co
by hacker_9 9y ago
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 are a good idea, but think TDD is too extreme, consider that TDD simply makes sure you write testable code from the outset. When you have a test wrapping a method, and need to add a dependency, you actually decide to use DI (Dependency Injection) because otherwise your current tests will break / become integration tests. TDD makes you think upfront about about things like mocking, separation of concerns, etc.
When you have the mindset that you will absolutely 100% write tests at some point anyway, TDD is actually a faster and more fun way to develop than bolting on tests afterwards.
- miketery 9y ago> you actually decide to use DI Whats DI?
- wahnfrieden 9y agoDependency injection
- Clubber 9y agoI forgot who said it but it goes something like, "any code without unit tests is legacy code."
- zaphar 9y agoWhich by definition means your tests are legacy code. It's turtles all the way down. For what it's worth I do think Unit Tests provide value.
- chewbacha 9y agoThe code is the “test” for your tests ;)
- michaelmrose 9y agoThe code and the test are probably to some degree based on the same logical construct. If that logical construct is malformed your tests may pass and your code might not work. Regardless if your code works your tests could still fail, likewise your code could not work and your tests pass so since the tests and code may vary independently if either is buggy I don't see how this can possibly be true.
- chewbacha 9y agoIf the logical construct is flawed, no amount of tests will ever catch it, only user testing would. The point I’m trying to make is that the verification of correctness is bidirectional. If I’m writing tests around existing code, I rely on the code to test my expectations. If I’m writing new code, I write tests to assert my new assumptions. All automated tests do are assert that I’ve written the same logic twice. Writing it a third time will also decrease the likelihood of transcription error again, but at diminished returns.
- Ajedi32 9y agoNah, the code tests the tests just as the tests test the code. If you expect your tests to pass and they don't, something's wrong. (Either with the code, or with the tests.) Same goes for when you expect the tests to fail and they don't.
- the_af 9y agoThe code is definitely NOT the test of the tests. It may seem that way because (sometimes) when the code breaks (e.g. fails to run at all), the tests also break. But consider this: what if your tests are poorly written and fail to detect bugs? What if they fail because the test code is buggy? Failing to detect bugs is a bug (undesirable behavior/output) of test code. There are some techniques to address this, for example mutation testing ( https://en.wikipedia.org/wiki/Mutation_testing https://en.wikipedia.org/wiki/Mutation_testing ), which effectively become some part of "the tests of the tests". The take away: no, the code is not enough. You need to test your tests.
- humanrebar 9y agoI've heard it attributed to Michael Feathers.
- jeremy_wiebe 9y agoI believe that was Michael Feathers in Working Effectively with Legacy Code
- mattmanser 9y agoThis whole thread is a response to: https://news.ycombinator.com/item?id=15591190 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 with DI that's just injecting like 30 things, which is obviously therefore coupled. It just makes it really obvious, but DI itself has massive downsides. If you've ever worked with bad programmers and seen it in the wild now, I'm sure we can agree DI and TDD doesn't stop bad programmers writing bad code. In fact, all it seems to do is make even more of a mess. Not only do you have to pick apart the bad code, you have to start dealing with carefully moving methods to the right places because DI can make it hard to figure out what's being used where, and then on top of that tests break all over the place because they're entirely dependant on the implementation instead of the functionality.
- hacker_9 9y agoWhat exactly is your experience working in a commercial environment? When the updates you ship can affect tens of thousands of customers? In these situations, 'Sods Law' often comes to mind - "what can happen, will happen". If you have a defect in your untested code, you can absolutely bet it will come out at the most painful time possible in front of all your clients. Being blamed for that kind of stuff is a stressful way to live your life, much nicer to have tests shout at you instead. * and to reply to your edit: of course tests break when you change the code they are testing! But after reviewing the broken tests, you see the intent and re-adjust the test. But what often happens, is you realise you didn't fully understand the code previously, and actually after reading the test you need to undo your refactoring as it didn't make sense in the first place.
- ozim 9y agoPick the tool for the job, if your experience is with things that last 5+ years then ok. I work on a system which is 5 years old and all things from 5 years ago are not relevant. Actually I am working on it only for 3 years now but we pretty much each year rebuild whole thing. With minor things going in and out. Of course we spend a lot of money on automated tests but those tests had to be thrown away because of amount of changes in the system.
- 0xcde4c3db 9y agoThere are undoubtedly multiple reasons. One reason is that there are domains where the hard problems are integration problems. If the point of your program is to poke/sample some physical object, talk to another opaque chassis/address space, execute realtime tasks (which in practice often includes UI/UX concerns), etc., then extensive integration testing is absolutely vital. If you focus on some other testing discipline and try to de-emphasize integration, there is a considerable risk of fooling yourself about whether your program actually does what it says on the tin.
- hacker_9 9y agoYeah I didn't mean integration tests were bad, just that you don't want to turn your unit tests into them unintentionally. Following the TDD mantra, you should absolutely have a failing integration test before writing integration code.
- DougWebb 9y agoThe code you write can also potentially have a lifespan of 3 months, and it can be hard to predict which it's going to be. I feel that TDD is an attempt to impose engineering discipline onto something which is still largely at the craftsman stage. As an engineer I like the idea of pushing the field forward, but I don't think software development tools are ready yet to make TDD and the like broadly accepted practice. That means you need to decide case-by-case if they make sense.
- hacker_9 9y agoTests define intent. Usually when you craft something, you have an idea of what you want going in. You may even draw it, and in the case of construction projects, fully 3d render it. Tests are the programmer equivalent, they define a contract you expect from your functions, which can then help you shape the function itself.
- crdoconnor 9y ago>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. There's a number of reasons why you could try TDD and get frustrated with it because it ends up sucking for you: * You're using unit tests where integration tests would be more appropriate. * Your integration tests would take longer to build than the thing you're building itself because you have to set up some sort of elaborate mocking. * Time is of the essence but quality isn't / your code will be run a limited number of times.