4 ms·
> This is the trap I always fall into when I try TDD. In order to add or change a feature, you now have to write the code twice: Once to implement the change, a
by thomascgalvin 7y ago
> This is the trap I always fall into when I try TDD. In order to add or change a feature, you now have to write the code twice: Once to implement the change, and once to re-implement the change to assert that it does what it's supposed to.
I think you have that backwards.
In TDD, the test is basically an assertive statement: when this test passes, the functionality is working as intended. You then write the implementation code, and when the tests pass, you're done.
This gives you two things: one, a sense of certainty that your code is meeting the requirements, and two, it bounds your work, preventing you from writing code that you don't need to make the test pass.
Now let's say we're changing a feature. Maybe if a user tried to add an out-of-stock item to their cart, the UI currently displays an error message, but now we want to add a note indicating when the item is expected back in stock.
We'd just go into the test for that error message, and add statements that look for this new `div`. We would probably have to add a few cases (for example, when we have an estimated data, when we don't have an estimate, and when we've been told the product won't be restocked), but we aren't fundamentally altering the test code.
These tests will initially fail, because there's no `div` with an `id` of `restock-message` or whatever. But one by one we can knock them out, adding messages for known or estimated restock dates, unknown restock dates, and permanently out-of-stock items.
> And no safety has been added, because the logic itself can still be flawed.
That's true, but that would also be true if you were hand-testing. You can't verify functionality you don't understand, but you can't write functionality you don't understand, either.
TDD, and testing in general, isn't a magic bullet that solves all of your problems; at some point, you still have to be smart enough to write the code. But testing is still a necessary tool in the developer's toolbox, because without it, you simply cannot know that your code is doing what you think it's doing. And since you're going to be testing anyway, why not have the machine do as much of the heavy lifting for you as possible?
- jniedrauer 7y ago> Now let's say we're changing a feature. This is where TDD really falls apart for me. It's pretty rare, at least in the code I work on, that you add a single little bit of functionality that fits cleanly into an existing TDD function. It's much more common that entire structures changes, and the TDD tests are no longer relevant and have to be completely rewritten from scratch. So again, you're effectively just implementing the logic twice. Where you actually need it (during a refactor), it provides no safety because it just gets completely rewritten every time.
- eyelidlessness 7y agoI think this is a sign that you are not designing maintainable systems in the first place. I work on reasonably complex systems where significant changes to a feature do not tend to cause huge structural changes like you describe, and where the vast majority of tests tend to remain unchanged and help detect regressions. It is entirely possible, with the right design. And in my experience, developing a comfort with TDD will help promote that kind of design. (Edit: I want to clarify that this is not meant in any kind of a judgmental way about your work or your talents, I'm sincerely trying to help identify issues so that you can hopefully become more productive and more confident in the work you produce.)