5 ms·
I’ve only ever heard of TDD in the context of greenfield development. I thought the whole point of TDD as opposed to just “writing a lot of tests” is that you w
by et1337 2y ago
I’ve only ever heard of TDD in the context of greenfield development. I thought the whole point of TDD as opposed to just “writing a lot of tests” is that you write the tests first, and that more or less determines the design of the system? TDD looks at tests not just as a cost center that pays off on the future, but as a tool to help you design stuff right now.
This is my perception as a non-TDD person. Maybe someone can validate if this makes sense or not.
- sebtron 2y agoI too find it hard to apply TDD to the big existing project I am working on. Most of my day-to-day coding is adding small bits here and there in the right place, discovering the architecture of the whole thing as I go. Without knowing what I have to do to achieve the desired result in the first place, I cannot begin writing a test with the half dozen mocks it needs (I know it's bad). The only tasks where I can succesfully apply TDD are bug fixing, where I write a new test to prove that I understood the bug (the test should fail with existing code), before I fix it. But I have colleagues (working in other projects) who told me how they are succesfully applying TDD to refactor an old codebase. They start with big, not-so-"Unit" tests to make sure that they don't break the thing at any step, and then they move to more specialized tests when tackling specific parts of the code.
- motorest 2y ago> Most of my day-to-day coding is adding small bits here and there in the right place, discovering the architecture of the whole thing as I go. Without knowing what I have to do to achieve the desired result in the first place, I cannot begin writing a test with the half dozen mocks it needs (I know it's bad). Nothing in your example prohibits or even hinders TDD. The only thing required by TDD is that you specify an interface and add tests to specify what behavior you expect from them. The moment you have something you can compile and run, your TDD path is completely open. Also, I'm noting the hints of the same specious reasoning that plagues discussions on microservices, mainly the "it's-all-or-nothing" fallacy. You can benefit from TDD if you, say, are writing a RESTful interface and start off by only adding unit tests checking for controller behavior. If your project can live with 0% line coverage, it can certainly live with TDD buying you 20% line coverage.
- nunez 2y agoYour situation is the best opportunity to add tests, IMO. The codebase is mature and it's architecture is likely well established. It's easier to write tests for small changes in a very established system than it is to write tests for a system that's still in flux. In most cases that I've seen, this isn't done because there's no financial upside to doing so. When your bonus is tied to velocity, not quality, any effort on testing is too much effort.
- Jtsummers 2y ago> a tool to help you design stuff right now TDD stands for "Test-Driven Development" not Design. Your design could change radically after creating the initial tests, they should not be used as a way to freeze your system unless there really is a true finished and complete state for it. (This is true for any test suite, not just those developed doing TDD.)
- meiraleal 2y ago> Your design could change radically after creating the initial tests Which implies a cost of at least 2x in dev hours. One should always evaluate if it is worth double or triple LoCs to maintain.
- deleted 2y ago[deleted]
- Jtsummers 2y agoWhy would it be double or triple the LoCs to maintain?
- 8n4vidtmkvmk 2y agoVs zero tests? My tests are usually bigger than my implementation.
- motorest 2y ago> Vs zero tests? If you don't bother with tests, discussing TDD is like famine victims discussing nutritional levels reported in food labels. > My tests are usually bigger than my implementation. That's perfectly fine if you feel your tests are important. Getting back to the topic, TDD does not enforce coverage targets or even minimum coverage bars.
- meiraleal 2y agoBecause test is code, it has bugs, it needs refactoring, needs to update dependencies, creates technical debt just like the code it is testing. We could even create tests for the tests to be sure our test suíte works. It is just a tradeoff of speed and increased complexity.
- jandrewrogers 2y agoTDD often doesn’t work for greenfield development because you have no idea how the software will be designed and structured until after you’ve done substantial implementation to prove out the viability of the software architecture and how implementation details interact. Major aspects of software architecture may need to be redesigned and reimplemented multiple times in order to better optimize the tradeoffs that manifest. By definition, greenfield development doesn’t lend itself to trivial analysis upfront, particularly for non-trivial systems. Tests don’t help you design software, they help verify properties of the implementation. For non-trivial greenfield systems, the full set of properties (which is a very high dimensionality tradeoff space) and their expression in the implementation isn’t really knowable ahead of time.
- lll-o-lll 2y agoDesigning the tests means you have to design the software. This is a low-key way of enforcing some upfront design, which is good. Also, this is not specific to software. Defining how you will validate a system, before you go build the system, is simply good engineering.
- deleted 2y ago[deleted]
- jandrewrogers 2y agoThe design of some software, even in substantial detail, is not sufficient to design tests of an implementation. Good tests can be completely dependent on the implementation details far below the level of design because those implementation details determine how the thing you are testing can even be measured. How it is measured isn’t actually important. You can get closer with extreme (over-)specification of the implementation, which almost no one does because it comes with an inordinate cost, but even that can fail because software properties are also a function of the hardware it runs on. To some extent, modeling the interaction of software on hardware for the purposes of building good tests is by actually measuring running code on real hardware. Hardcoding specific implementation detail assumptions into the design of complex non-trivial systems so that you can write a test is a brittle way to go about writing software. There is a reason that waterfall-style never seems to produce good systems in a reasonable amount of time or money. I write non-trivial greenfield systems and put inordinate amounts of design work into them (literally years in some cases). I have never found a case where that allowed me to write useful tests prior to implementation. At a minimum you need a complete architectural skeleton that runs and has had its non-functional properties verified analytically before you can write tests that you’ll likely use. I’m not against writing tests. I invest far more in testing than most devs due to atypically high reliability and robustness requirements. I’m against the complete waste of time that would be writing tests before there is sufficient implementation to design maximally efficient and appropriate tests. Testing of some software is extremely expensive in both time and money, so optimizing test effectiveness and efficiency becomes valuable.
- lowbloodsugar 2y agoWhat you’ve described is TFD: test first development. TDD is not about writing all the tests first. And I agree with the article: you couldn’t do either for a greenfield project.
- motorest 2y ago> I thought the whole point of TDD as opposed to just “writing a lot of tests” is that you write the tests first, and that more or less determines the design of the system? Yes, my thoughts exactly. At its core, TDD forces a workflow where the interface is the first thing laid out, and the expected behavior follows. Therefore when designing new components, it becomes readily apparent when the interface doesn't work, even before anyone invests any time adding the missing behavior.
- kazinator 2y agoI've done TDD-like changes (not full blown TDD methodology) on legacy code bases. The main idea of writing a test which fails and then fixing it with the code change applies almost anywhere. E.g. when fixing a bug, write a test case that fails because of the bug, and passes due to the bugfix. You don't necessarily need the refactor step, though. The continuous refactoring is the greenfield aspect, perhaps. Refactoring can leave a trail of TDD tests that used to be independent, but are now tied together and redundant.