5 ms·
My beef with TDD is the same as my beef with a lot of estimation techniques. They really need for you to have done the thing before. Faith that you "know what
by taeric 4y ago
My beef with TDD is the same as my beef with a lot of estimation techniques. They really need for you to have done the thing before. Faith that you "know what tests are needed" is surprisingly loaded. Unless you are writing, effectively, integration tests for specific layer. But, at that point there is no guarantee that you know how to write the magic in between. (There was an interesting attempt at a sudoku solver using TDD once. It... didn't end well.)
Though, typing that last part out. Maybe the concern is over the level of the tests. Unit tests are surprisingly easy to understand based on how you have divided out the code. However, there is very little that is required on how you have done this division. Path dependence is a huge thing to define what divisions of code you will end up with. Such that I have a hard time seeing how that works in a TDD fashion.
- wpietri 4y agoI don't find much need to have done the thing before. Before I write a line of code, test or no, I usually have some idea of what the code should do. Then I run the code to see if it does what I want. So if I'm not doing TDD, I'm still doing "manual test test first"; the test is just in my head. TDD is just saying, "Let's start by automating a bit of that test and make the test fails correctly. Then we write production code until the test passes. Once it goes green, we look at what we've got, see how we like it, and maybe refactor a bit before writing the next test." If I'm totally off the map and flailing around, yeah, I won't write tests first. I'll hack at something until I have a clue. And then I'll throw that code away and write my first test. Which is something I should do regardless of whether I'm doing TDD, as scratch code like that is too messy to keep. Easier to dump it and start fresh.
- taeric 4y agoBut this "scratch code" is against the described cycle?
- wpietri 4y agoFor TDD, sure. I'm saying if you're doing scratch work, don't use TDD. It's a tool, not a religion.
- taeric 4y agoFair. Than my main beef is with all of the zealots. :)
- wpietri 4y agoYeah, almost everything good in tech attracts people who push a good thing too far. If not for working with some reasonable advocates, the FP zealots would have seriously put me off the techniques entirely.
- taeric 4y agoThe best is when you realize you are yelling at the mirror. :D And, to be fully fair, I'm sure this is in many walks. Cast iron advocates. Electric stoves. Manual transmission vehicles. The worst is when things /used/ to be true. The world has a habit of moving on.
- karmelapple 4y agoI feel exactly the same way. TDD helps me think about the requirements, because even if I’m building something as a prototype, I still have specific requirements in mind. Those will change as I get feedback for the prototype, but even a really, really simple test will help me be more secure in knowing my reworking of the prototype didn’t break some very fundamental needs of the system. My guidance would be to not start with many tests when writing a prototype / initial development of something - just write one or two of the most basic things you’re confident you’ll need. As your finished product comes into focus, then you can add more tests. I don’t literally write a test before every line of code, yet I still consider what I do to mostly be TDD.
- wpietri 4y agoAbsolutely. For me it's an incremental, iterative process. I write a tiny bit of test. And then I make it pass, often in a way that's a little too simple. So then I'll go back and improve the test, which forces me to improve the code. Writing too many tests feels like getting ahead of myself. It feels like a bet that I won't learn anything or think of anything new as I go. Which is a bet I don't like making, because it often becomes self-fulfilling.
- BoiledCabbage 4y ago> My beef with TDD is the same as my beef with a lot of estimation techniques. They really need for you to have done the thing before. Faith that you "know what tests are needed" is surprisingly loaded. Why would you nee to know what tests are needed? Just about any bit of functionality you can come up with to implement you should be able to come up with a test to test it. It's not really harder to know what code to implement than it is to know what test to exercise that implementation. And at any point in time you only need to think of a single test before you're back to coding. It's not like you need to plan out 50 tests up front. Whatever the next handful of lines of code you're going to write write a test for that first, then write those same lines. Then pick the next handful via test, then write them. I don't understand the difference in knowledge at all.
- taeric 4y agoThe best example I can think of on this, is to look up that TDD creation of a Sudoku solver. This is collected in an old HN post at https://news.ycombinator.com/item?id=3033446 https://news.ycombinator.com/item?id=3033446. It is reasonable to think you can know what functionality you need to test. And, for certain, if you know the boundaries of the system you are building, you will know some. That said, there is a tendency to build more boundaries than needed in our industry, period. Would be like a community garden that thought they should arrange things by type of plant that will be created by the community. When the actual divisions should be on how many community members you will have.
- BoiledCabbage 4y ago> The best example I can think of on this, is It's not the best example. It's the one well worn example that everyone pulls out and is a perfect case of letting perfect be the enemy of good. Something works for 99% of cases, someone finds a 1% case it doesn't work for an says "ok I don't need to evaluate it it's useless". Not tool works 100% of the time, the fact that it didn't work for someone creating a constraint solver is effectively irrelevant.
- taeric 4y ago
- dmitriid 4y agoThe more I progress through my career, the more useless unit tests become. My requirements are in terms of observable program behaviour, and that is what needs testing. Not the hindreds/thousands of tiny one-off tests in between. And... you can't test that observable behaviour with TDD until you've written a solid chunk in between.
- randomdata 4y agoTDD agrees that you should only test observable behaviour. There should be no need for you to implement a large chunk of your application for the first test to pass. Are you writing many tests before you begin implementation? TDD promotes that you start with just one.
- dmitriid 4y ago> Are you writing many tests before you begin implementation? No. I usually write functional/integration tests after I've written most of the code. > TDD promotes that you start with just one. And that one will be absolutely entirely useless. Because what would be that "first one test"? Let's assume it's a REST or GraphQL service that returns aggregated data from multiple external services. Until you have more-or-less functioning code (including all model definitions, client definitions, data transforms etc.) you can't even write a "first test for observable behaviour". Also here: https://news.ycombinator.com/item?id=34765360 https://news.ycombinator.com/item?id=34765360
- randomdata 4y ago> Because what would be that "first one test"? Whatever you want. Just pick some small attribute that you expect to observe. I'd personally start with failure modes as they are the most important and interesting code you will write. Hell, you can likely not even bother testing the so-called "happy path" because, really, who cares what happens during success? Failure is where you want users and future readers to have the most documentation to ensure that when things go wrong the metaphorical bridge doesn't come crashing down into the river but rather remains in a repairable state. If it's a REST endpoint that aggregates data from multiple external services, you probably want to see a "retry after" response sent to the client if any of those external services are temporarily unavailable. So write a test that asserts that, then write code that does it. This is also a nice first case as you can detect an unavailable external service quite early in your pipeline, requiring very little of the implementation to see the test pass. No need for religion. If documenting your code later works for you, go for it. Nobody cares. Tests won't be driving your development, so it won't be TDD, but it'll be something and that may be enough. However, in reality most people simply don't have the wherewithal to plan for things like being able to test unavailable remote services if they don't have a test case in front of them forcing them to and won't bother when it is too hard to add later, so there is something to be said about the TDD approach as a general rule, deviating only after you fully understand the tradeoffs.
- gotgotgotgot 4y agoExactly. To me, TDD seems to be a way for experienced programmers to solve puzzles in a new way. It's all very well saying that good architecture will emerge from TDD, but there's no way that's true unless the programmer has a good idea of where they are going in the first place.
- randomdata 4y agoIf you know where you are going, what value would you derive from having tests drive your development? Why wouldn't you want to be the driver? TDD is most useful when you don't know what you are getting into. It allows you to quickly run small experiments against your hypotheses to see if the fuzzy thoughts running around your head are useful or need to be thrown out. The data gained from those experiments is what drives your development decisions. If you already have everything already figured out, what more data do you need?
- IshKebab 4y agoThat's a really good way of putting it. TDD assume that you can write a test as the first step. Which sort of sounds reasonable if you don't think about it too much. Sometimes it is reasonable (e.g. leetcode, improving existing code, well defined problems). But a lot of the time that is sneakily missing out the enormous steps of prototyping, experimenting, trying solutions that didn't turn out to be a good idea, finding out that the problem wasn't a good idea, etc. etc. All that can take longer than actually implementing a solution. So, fine use TDD where it works well but don't pretend it is the only way to do things.
- deterministic 4y agoI use tests all the time when implementing new features I haven’t implemented before. It makes me think about the API before implementing it and gives me a way to auto test it which is excellent.