TLD = Running around in circles!
January 11, 2022
Blog > Development, Quality, TDD | Valentina Cupać
TLD = Running around in circles!
TLD provides longer feedback loops, you have more rework.
TDD provides shorter feedback loops, you can work in a linear way.
Let’s compare TDD & TLD:
– TDD: I start off with writing the requirement in an executable form (the test). I might discover that the requirement is unclear because I can’t write the test! That’s ok, I’ll stop there, need to get the requirement clarified. Then I proceed to write the test, and as I’m writing the test, I’m modeling the contract for the code, to make sure it’s consumer-friendly. Then, I then run it to see it fail, so that I can be sure that the test is falsifiable. (If the test doesn’t fail, it could be due to incorrectly writing the test, or perhaps the functionality already exists, or I didn’t reproduce the bug which I’m trying to fix). I proceed to write the minimal code to make the test pass. I run the test and verify that it’s green. I can then safely refactor.
– TLD-A: The “best case” of TLD (closest to TDD for sake of fair comparison) is, based on the requirement, to first write the code, then write ONE test. But, during writing the test, I might discover that I can’t write the test because my code wasn’t designed in a testable way! So then I have to rework BOTH the code and test. Great, I’ve now written the test, but I might discover that the way I’m calling the interface isn’t really consumer-friendly (after all, the test is the first consumer of the code). To modify the contract, I have to rework BOTH the code and the test. Finally, I run the test to check it passes. Green, great! But how do I know that it’s actually my code which caused the test to pass, or was it a false positive (case of the test always passing)? I don’t know. To get that assurance, I’d need to comment out the code, run the test to see it fail, then uncomment the code, and run the test to see it pass. Then I can refactor the code.
– TLD-B: The next case of TLD, is where I do coding first, then write MULTIPLE tests. So unlike TLD-A, I’m taking a more coarse approach, whereby I might want to cover multiple requirements/scenarios in the implementation all-at-once and THEN to write SEVERAL tests after writing the code. The problem here is my short-term memory. By the time I get to writing tests, I’m not sure if I remember which requirements/scenarios I had covered (I might accidentally miss some). Perhaps I also got carried away with “gold-plating” and over-engineering. Furthermore, since I had written much more code before getting to the multiple tests, what if I discover then that my code isn’t testable? Or that my interface isn’t consumable? Oh no, I’ll have to rework so much code and the tests? Hmm, I feel these tests are dragging me down…
– TLD-C: Lastly, we have the case where I say to myself that I’ll write the tests “later”, but it turns into “never”. Developers just do manual testing instead.