6 ms·
I learned TDD years ago and never looked back. It is true that there are some things where it is less suitable and therefore I would perhaps decide not to use i
by cjfd 5y ago
I learned TDD years ago and never looked back. It is true that there are some things where it is less suitable and therefore I would perhaps decide not to use it. E.g., user interfaces in case of changes that are mainly visual. Or code that tightly integrates with the system. E.g., file system manipulations. For all other code I think TDD is absolutely the best way to write anything more complicated than a throw-away script. Frankly, I am pretty much at the point where I consider anything less than TDD borderline unprofessional. I have come to expect code that was not TTD-ed to be buggy or more complicated than necessary or both.
- echelon 5y agoIt also seems really ill suited for new systems and places where you're experimenting with new languages or frameworks. You don't know the shape well enough to be able to test the inputs and outputs before writing the thing, and learning via TDD seems highly suboptimal.
- rytor718 5y agoI think you have a fair point in regards to learning new things. YOu don't need tests to explore tools and languages. Tests are for development. Thats just the thing with TDD: used properly (which is clearly tricky for many of us), it should help you think through what the inputs and outputs of the program you hope to write are. It does assume you know what you want to build though, even if you're unsure of how to build it. I think of it as a design tool to be honest. When I'm not quite sure exactly how something should work, but I have a clear idea of what I want it to do, tests help me work through it in a way that produces extensible code.
- user-the-name 5y agoIt's not tools or languages you are exploring, you are exploring the problem you are trying to solve, and its possible solutions. If you have a problem that is well understood, well documented and that has a straightforward solution, TDD is great because you know where you are going. But a lot of the time, you have none of that. You don't know where you are going. You need to experiment, you need to iterate, you need to occasionally change directions completely. When you're doing that, TDD holds you back and gives you nothing.
- karmelapple 5y agoIn my experience a problem doesn’t need to be well understood, well documented, and straightforward to benefit from TDD. Rarely are we building something with absolutely no idea what the final outcome should be, are we? There’s a general idea of, “this new feature should mostly work like this” description, correct? If not, you’re doing code very different than the stuff I build. And that might be the case! But I’m curious what kind of projects you’re working on where you have basically no idea what you’re aiming for. Even when I don’t understand what’s wrong, I’ll generally have an idea of either: * what is undesired behavior to fix, or * new behavior to add I can at least play around with the code a little to see how that impacts existing tests, or write some simple test that will demonstrate a really high level desired outcome. As I iterate the functionality, I might see the opportunity for another assertion or three, and then keep iterating on that until I’ve figured out what I truly want, both functionally and test-wise.
- rytor718 5y agoI agree with Karm on this. I'm not usually trying to figure out how to solve a problem at the first stage. I'm trying to understand what the app should do. I'm exploring the language or framework to understand how to pull that off. Once I know, I can write a test based on just that information. The problems usually come well after that step as my implementation becomes more complex with the size of the app.
- pydry 5y agoYes, it's awful for spikes. I have done a variant of TDD where the output is slightly uncertain where: * I build a test with everything filled in except output of some kind. * I write code that generates an output I want to eyeball. * I run the test in "rewrite mode" where the output is generated by the program and saved with the test. I eyeball it to check if it's ok and then commit. * In CI it checks the output against the fixed version. There's plenty of scenarios where it doesnt work or is generally inadvisable but I find it to be a super effective technique where it does. I think it's an approach that would work better for code that generates text, images, sounds, than common-o-garden TDD.
- berkes 5y agoI don't entirely agree here, though. If you are learning a new language, new paradigms or new frameworks, then, indeed, often testing is an extra burden that adds little at this point. But in this stage, I hope, one should be aware that the code you are writing is bad anyway. In a year, you'll probably be very ashamed of all the things you did there. But in languages or paradigms that you are already familiar with, TDD helps a lot when learning new things. You can very easily learn about a new library by writing tests that use the lib. Or learn a new pattern by implementing them in tests. For example, write some tests that wrap a Stripe library, then change the test to change some setting, call a method, or feed it some weird data, and assert some outcome rather than manually putting stuff in a cart, filling your address, CC details and then see that the setting you thought did X actually does Y. And repeat again.
- ramblerman 5y ago> Frankly, I am pretty much at the point where I consider anything less than TDD borderline unprofessional. Would you feel that way about the linux kernel for example?
- cjfd 5y agoActually, I am not entirely sure how much of the testing there is automated. Presumably there are at least some automated test tools floating around here and there for the kernel. Major parts of the kernel could fall under the 'systems' exceptions where they are very close to the hardware. It is possible to do TDD to stuff that is close to hardware but it certainly is harder and it is more likely that some failures fall through the cracks when doing TDD. One thing that is different about the linux kernel, as far as I know, is how thorough the reviewing is that is going on for every patch. Also, there is the merge window followed by a long stabilization period. I would say that if you are not doing TDD you are going to need processes like that if you want to maintain stability. Also note that processes like thorough review by multiple people and a stabilization period four or five times longer than the merge window sound really expensive. Much more expensive than TDD. But also if one does TDD, still system/end-to-end tests are desirable. Not as much as without TDD but without it things would still break somewhat regularly.
- Chris_Newton 5y agoWith systems programming, performance matters, and all that extra indirection can be expensive. Indirection can also make it harder to rigorously analyse all possible paths through a piece of code and make sure you’ve handled all required cases.
- dnautics 5y agoIt's very possible to do the indirection at compile-time, set a flag only active during tests.
- Chris_Newton 5y ago
- chitowneats 5y agoThese sentiments are basically copypasta from Bob's books. All this indicates to me is that you've drunk the koolaid.
- serverholic 5y agoHave you considered that maybe TDD is just a really good fit for your brain? I've worked at a TDD-focused company and it always felt like I was coding through molasses. Some of us weren't as strict about TDD and I didn't notice a difference in our code quality.
- wpietri 5y agoI would be very curious to see the code base there. Some places are pretty bonkers about testing, in a way that seems almost religious to me. Excess mocking, extremely verbose tests, and a lot of cleanup to do in testing-land whenever you make significant changes in the production code. Maybe you were at one of those? To me, doing TDD right is about having the minimum amount of testing needed to keep bug rates extremely low. It's also about keeping the test code as well factored as the production code, such that changing or refactoring the production code doesn't create disproportionate work in the test suite to bring it back in line. An experiment I've tried repeatedly is to start a new project and shoot for zero bugs. I think I'm pretty smart, so that at first seems achievable without tests. But pretty quickly complexity increases that I at least have to manually test. And not long after that, manually testing everything gets tedious, so I have to start automating the things I am manually checking. If I keep pursuing zero bugs and feeling like I'm spending my time optimally, I keep ending back up at TDD. Maybe try that for yourself on a hobby project? You might find that the TDD-focused company was better at talking about TDD than doing it.
- mypalmike 5y agoI've found more problems with insufficient mocking as opposed to excess mocking. If you're not using mocks, you're likely using real dependencies. And that's where you get molasses testing. One small code change has cascading effects on tests, and small feature changes that take a few minutes to implement can result in a day or more of just fixing the affected tests.
- twh270 5y agoLook up the Object Mother pattern. The idea is to have 'baked' objects which you can use repeatedly in tests, which fulfill a certain scenario. For example a hotel reservation system needs to be able to handle a single person up to a whole family (maybe with an allergy or special needs thrown in for good measure). So you set up a bunch of Guest objects using a GuestObjectMother. When you make a change to Guest, you only need to change the GuestObjectMother and any tests that may directly be involved in the change to Guest. Tests that simply require a Guest to be involved in the test probably won't have to change, as they're simply retrieving the appropriate Guest object and then handing it off to something else.
- sidlls 5y agoI take the opposite view. Code developed with TDD tends to be overly complicated and inefficient, and the test suites themselves are often bizarre labyrinthian hellscapes of mocks, facades, and workarounds. "They just did it wrong, then," you say? That statement ceases to be meaningful when it can applied routinely: it's the norm, and if it's the norm, it's not something "they just did it wrong" applies to.
- blacktriangle 5y agoSo the way that TDD advocates point out that if your tests are ugly, its a sign your code is ugly. I think this also applies to languages and frameworks as well. For example, I think of the experience doing TDD in Rails with all its ORM and callback interconectedness to TDD on functional code that is mostly exchanging values between systems. All the stub and mock crap goes away since values become the boundary of the system. Gary Bernhardt has an awesome talk making that exact point. I'm now of the opinion that if TDD is a struggle, its a sign that your environment has serious underlying flaws.
- carlmr 5y ago>TDD on functional code that is mostly exchanging values between systems. All the stub and mock crap goes away since values become the boundary of the system. That's generally why I think functional programming is taking off. It's much easier to reason about input-output of stateless functions. They're much easier to test and develop. They're way easier to understand for the reader, because the reader can understand what's happening in one place, instead of having to look through many different files, creating a complex model of all the inheritance relationships between classes.
- sidlls 5y ago"[I]f your tests are ugly, its a sign your code is ugly" is a bit tautological, and highly subjective besides. I consider the 50-line function to be "less ugly" than the same function butchered for "testability" into a bog of poor abstractions and single-use smaller functions.