59 ms·
I have complicated feelings about TDD
- danpalmer 4y agoLike almost every spectrum of opinions, the strongest opinions are typically the least practical, and useful only in a theoretical sense and for evolving the conversation in new directions. I think TDD has a lot to offer, but don't go in for the purist approach. I like Free Software but don't agree with Stallman. It's the same thing. The author takes a well reasoned, mature, productive, engineering focused approach, like the majority of people should be doing. We shouldn't be applying the pure views directly, we should be informed by them and figure out what we can learn for our own work.
- totetsu 4y agoBut we need to use FDD to use the full spectrum of options.
- discreteevent 4y agoThis was the funny thing about extreme programming. I remember reading the book when it came out. In it Kent Beck more or less said that he came up with the idea because waterfall was so entrenched that he thought the only way to move the dial back to something more incremental was to go to the other extreme end. This took off like wildfire probably for the same reason that we see extreme social movements/politics take off. People love purity because it's so clean and tidy. Nice easy answers. If I write a test for everything something good will emerge. No need for judgement and hand wringing. But the thing is that I think Kent Beck got caught up in this himself and forgot the original intention. I could be wrong but it seems like that.
- ad404b8a372f2b9 4y agoIncreasingly I've been wondering whether these agile approaches might be a detriment to most open source projects. There is a massive pool of talented and motivated programmers that could contribute to open source projects, much more massive than any company's engineering dept, yet most projects follow a power law where a few contributors write all the code. I think eschewing processes and documentation in favour of pure programming centered development, where tests & code serve as documentation and design tools, means the barrier to entry is much higher, and onboarding new members is bottlenecked by their ability to talk with the few main contributors. The most successful open source projects have a clear established process for contributing and a lot of documentation. But the majority don't have anything like that, and that's only exacerbated by git hosting platforms that put all their emphasis on code over process. I wonder whether setting up new tools around git allowing for all projects to follow the waterfall or a V-cycle might improve the contribution inequality.
- ImPleadThe5th 4y agoMy personal mentality about TDD is that it is an unreachable ideal. Striving for it puts you on a good path, but business logic is rarely so straight forward. If you are lucky enough to be writing code in a way that each unit is absolutely clear before you start working, awesome you got it. But in business-logic-land things rarely end up this clean. Personally, I program the happy path then write tests and use them to help uncover edge cases.
- radus 4y ago> I program the happy path then write tests and use them to help uncover edge cases. This approach resonates with me as well. I would add that writing tests when investigating bugs or deviations from expected behavior is also useful.
- PheonixPharts 4y agoThe trouble with TDD is that quite often we don't really know how our programs are going to work when we start writing them, and often make design choices iteratively as we start to realize how our software should behave. This ultimately means, what most programmers intuitively know, that it's impossible to write adequate test coverage up front (since we don't even really know how we want the program to behave) or worse, test coverage gets in the way of the iterative design process. In theory TDD should work as part of that iterative design, but in practice it means a growing collection of broken tests and tests for parts of the program that end up being completely irrelevant. The obvious exception to this, where I still use TDD, is when implementing a well defined spec. Anytime you need to build a library to match an existing protocol, well documented api, or even an non-trivial mathematical function, TDD is a tremendous boon. But this is only because the program behavior is well defined. The times where I've used TDD and it makes sense it's be a tremendous productivity increase. If you're implementing some standard you can basically write the tests to confirm you understand how the protocol/api/function works. Unfortunately most software is just not well defined up front.
- SomeCallMeTim 4y agoThat's one issue with TDD. I agree 100% in that respect. Another partly orthogonal issue is that design is important for some problems, and you don't usually reach a good design by chipping away at a problem in tiny pieces. TDD fanatics insist that it works for everything. Do I believe them that it improved the quality of their code? Absolutely; I've seen tons of crap code that would have benefited from any improvement to the design, and forcing it to be testable is one way to coerce better design decisions. But it really only forces the first-order design at the lowest level to be decent. It doesn't help at all, or at least not much, with the data architecture or the overall data flow through the application. And sometimes the only sane way to achieve a solid result is to sit down and design a clean architecture for the problem you're trying to solve. I'm thinking of one solution I came up with for a problem that really wasn't amenable to the "write one test and get a positive result" approach of TDD. I built up a full tree data structure that was linked horizontally to "past" trees in the same hierarchy (each node was linked to its historical equivalent node). This data structure was really, really needed to handle the complex data constraints the client was requesting. As yes, we pushed the client to try to simplify those constraints, but they insisted. The absolute spaghetti mess that would have resulted from TDD wouldn't have been possible to refactor into what I came up with. There's just no evolutionary path between points A and B. And after it was implemented and it functioned correctly--they changed the constraints. About a hundred times. I'm not even exaggerating. Each new constraint required about 15 minutes of tweaking to the structure I'd created. And yes, I piled on tests to ensure it was working correctly--but the tests were all after the fact, and they weren't micro-unit tests but more of a broad system test that covered far more functionality than you'd normally put in a unit test. Some of the tests even needed to be serialized so that earlier tests could set up complex data and states for the later tests to exercise, which I understand is also a huge No No in TDD, but short of creating 10x as much testing code, much of it being completely redundant, I didn't really have a choice. So your point about the design changing as you go is important, but sometimes even the initial design is complex enough that you don't want to just sit down and start coding without thinking about how the whole design should work. And no methodology will magically grant good design sense; that's just something that needs to be learned. There Is No Silver Bullet, after all.
- zwieback 4y agoA lot of the software engineering approaches from that era (refactoring, TDD, patterns) make more sense in the world I grew up in: large pre-compiled code bases where everything other than the base OS layer is under the engineer's control. If you have to ship your SW as an installable which will end up on someone's machine far away your mindset will be more defensive. In this day and age of vastly distributed systems where distribution and re-distribution is relatively cheap we can afford to be a little less obsessive. Many exceptions still exist, of course, I would think that the teams developing my car's control system might warm up to TDD a bit more than someone putting together a quickie web app.
- buscoquadnary 4y agoI think you make an important point. It used to be I'd have to worry about the OS layer, and that was it. Now I have half a dozen layers running between my code and the actual die executing instructions and as consequence of that I've lost a considerable amount of control. The funny thing is I end spending just as much time trying to debug or figure out the other layers, looking at you AWS IAM, that I don't feel I am that much more productive, I've just taken what my code needed to do and scatterred it to the 4 winds. Now instead of dealing with an OS and the code I'm fighting with docker, and a cloud service, and permissions and network and a dozen other things. Honestly this feels like the OOP hype era of Object Database and Java EE all over again, just this time substitute OOP for tooling.
- marginalia_nu 4y agoI've always sort of thought of TDD a bit of a software development methodology cryptid. At best you get shaky camcorder footage (although on closer investigation it sure looks like Uncle Bob in a gorilla suit). Lots of shops claim to do TDD, but in practice what they mean is that they sometimes write unit tests. I've literally never encountered it outside of toy examples and small academic exercises. Where is the software successfully developed according to TDD principles? Surely a superior method of software development should produce abundant examples of superior software? TDD has been around for a pretty long time.
- fsdghrth3 4y agoI use TDD as a tool. I find it quite heavy handed for maintenance of legacy code where I basically know the solution to the task up front. I can either just rely on having enough existing coverage or create one test for my change and fix it all in one step. The times I actually use TDD are basically limited to really tricky problems I don't know how to solve or break down or when I have a problem with some rough ideas for domain boundaries but I don't quite know where I should draw the lines around things. TDD pulls these out of thin air like magic and they consistently take less time to reach than if I just sit there and think about it for a week by trying different approaches out.
- fiddlerwoaroof 4y agoI’ve worked at a place where we did TDD quite a bit. What I discovered was the important part was knowing what makes code easy to test and not the actual TDD methodology.
- twic 4y agoI've worked at three companies that did TDD rigorously. It absolutely does exist.
- klysm 4y agoWas it worth it? In what languages?
- rybosworld 4y agoSeems like the TLDR is: Well-intentioned patterns break down when taken maximally.
- twic 4y agoThat's definitely part of it. The article is really quite good. Much, much better than the discussion here prepared me for!
- stonemetal12 4y agoI am not a TDD person, but when you write some code you want to see if it works. So you either write a unit test, or you plugin your code and do the whole song and dance to get execution to your new code. I see TDD is REPL driven development for languages without a REPL. It allows you to play with your code in a tighter feed back loop, than you generally have without it.
- JonChesterfield 4y agoIt's closer to a repl with save state and replay. A repl will get the code working faster than tests but doesn't easily allow rechecking the same stuff later when things change (either your code or the users of it). I haven't seen a repl with save&replay but that might be a really efficient way to write the unit tests.
- sedachv 4y agoYou just copy-and-paste the relevant input-output and there is your test. There isn't a need for any extra tools when using the REPL to come up with regression tests (obviously a REPL cannot be used to do TDD).
- 3pt14159 4y agoThis has been rehashed a million times. My view is that TDD is great for non-explorative coding. So data science -> way less TDD. Web APIs -> almost always TDD. That said, one of the things I think the vast majority of the leans anti-TDD crowd misses is that someone else on the team is picking up the slack for you and you never really appreciated it. I've joined too many teams, even great ones, where I needed to make a change to an endpoint and there were no functional or integration tests against it. So now I'm the one that is writing the tests you should have written. I'm the one that has to figure out how the code should work, and I'm the one that puts it all together in a new test for all of your existing functionality before I can even get started. Had you written them in the first place I would have had a nice integration test that documents the intended behaviour and guards against regressions. Basically I'm carrying water for you and the rest of the team that has little to do with my feature. Now there are some devs out there that don't need TDD to remember to write tests, but I don't know many of them and they're usually writing really weird stuff (high performance or video or whatever). But I have stopped concerning myself with changing other peoples minds on this. Some people have just naturally reactive minds and TDD isn't what they like so they don't do it.
- randomdata 4y agoI find the opposite. TDD is great when you don't know what your program should look like. It gives you an opportunity to simulate how the program will be used on the outside, able to be quickly iterated upon until satisfaction, without having to write all the laborious internal code (often over and over again when exploring without TDD). Once you are happy with the result, then you just have to back and fill in the guts once. If you know exactly what you need upfront, you can simply start coding, adding a sprinkling of acceptance tests to help catch mistakes. No need for TDD in that case.
- 3pt14159 4y agoReally? When I get to a new database and don't even know what data is stored where I don't write a test first. I write a bunch of SQL scripts and then maybe take it into a python toolkit for stats stuff. When training a classifier and having to choose things like dimensionality I find that exploring what the dimensions actually express teaches me more about the dataset and the approach faster than starting with a test. Sometimes I don't even know what opportunities are in the data that I'm going through, so how would I even express the test? That said, I'll try it your way next time and see how it goes. If it works for you maybe I'll learn how to make it work for me, since I love TDD. As for knowing exactly what you need upfront, why start coding? Why not do TDD? I find the interfaces are more naturally expressed as the consumer than the implementer. I rarely find myself writing unnatural interfaces when starting with the test, and by starting with the test it makes abstractions that must be faked / mocked easier to slide into the code that implements the feature without too much damage to the rest of the codebase. I avoid them whenever possible, but sometimes a network call must be mocked and it's better to do so with minimal collateral damage.
- ahurmazda 4y agoMy beef with TDD is most every resource merely parrots the steps (red,green,..). No one teaches it well from what I have found. Nor am I convinced it’s easy to teach. I have picked up what I can by watching (what I believe) good TDD practitioners. I have a feeling this is where TDD loses out the most
- Jtsummers 4y agoI mean, there's the actual TDD book by Kent Beck. It's pretty good, and only 240 pages. It was an easy one-week read for me, spread out in the evenings.
- pramodbiligiri 4y agoThere’s TDD by Example, and there’s also “Growing Object-Oriented Software, Guided by Tests”.
- twic 4y agoAbsolutely. Actually doing TDD is nontrivial, and it has to be learned. Most of the early learning was by pairing with people who already knew how to do it, working on a codebase using it. People learn it easily and fast that way. But that doesn't scale, and at some point people started trying to do it having only read about it. It doesn't surprise me at all that that has often been unsuccessful.
- gnulinux 4y agoI practice TDD for the most part, I agree that it's not easy. E.g. there are a lot of unanswered questions: What if you write the test first, red, write the code but it's still red. Could be your code wrong, could be your test wrong. If your test is wrong, do you go back and see the red? (I do). Do you test your tests? (I don't). Treating TDD like a formal system doesn't make any sense since it's meant to be a tool engineer can use as a heuristic to make judgements about the stage of the development.
- GnarfGnarf 4y agoI keep wanting to be converted to TDD, but I can't shake the feeling that I'd be writing half the code in twice the time.
- dbrueck 4y agoThat's accurate. Worse, as the complexity of the scenario you're trying to test goes up, not only does the cost of creating the test go up, the cost of maintaining it almost always goes up too.
- twic 4y agoWriting half the code sounds pretty good.
- GnarfGnarf 4y agoNo, I didn't mean doing the job in half the code (which for sure is better). I meant writing half the code that needs to be written, and then writing the other half that needs to be written, in addition.
- joshstrange 4y agoYep, I'm pretty anti-test because I've yet to see it ever payoff at any company I've worked at. That said, I keep hoping I'll catch the bug, be converted, have it click in my head. On the surface it seems quite nice but it's always with trivial examples. When you are dealing with real code I've had testing fall apart very quickly and/or make refactors extremely painful. And on top of it all, you are writing twice as much code in a world that doesn't care that you wrote tests, meaning it takes you longer to do that same work
- JonChesterfield 4y agoThere's some absolute nonsense in the TDD style. Exposing internal details for test is recommended and bad for non-test users of the interface. Only testing through the interface (kind of the same as above) means tests contort to hit the edge cases or miss them entirely. The whole interface hazard evaporates if you write the tests in the same scope as the implementation, so the tests can access internals directly without changing the interface. E.g. put them in the same translation unit for C++. Have separate source files only containing API tests as well if you like. Weird that's so unpopular. There's also a strong synergy with design by contract, especially for data structures. Put (expensive) pre/post and invariants on the methods, then hit the edge cases from unit tests, and fuzz the thing for good measure. You get exactly the public API you want plus great assurance that the structure works, provided you don't change semantics when disabling the contract checks.
- rmetzler 4y agoIt’s similar in Java, where people often only know about public and private, and forget about package scoped functions. You can use these to test utility functions etc. The post is weird, I agree with almost everything in the first half and disagreed with most of the second part. What makes TDD hard for integration testing is that there are no simple readymade tools similar to XUnit frameworks and people need to build their own tools and make them fast.
- madsbuch 4y agoTo me, it really depends: 1. Writing frontend code -- I've left testing all together. I'd never hope to keep up with the pace 2, Writing APIs -- rudimentary testing that at least catches when I introduce regressions 3. Writing smart contracts -- magnitudes more test than actual code.
- gravytron 4y agoTDD helps facilitates the process of building up of confidence in the product. However, the value it adds is contextual in the sense that if a product is not well defined and at a certain point of maturity then it may not be helpful to shift gears and adopt TDD. But fundamentally no one should ever be trying to merge code that hasn’t been unit tested. If they are, that is a huge problem because it shows arrogance, ignorance, willingness to kick-the-can-down-the-road, etc. From an engineering perspective the problem is simple: if you’re not willing to test your solution then you have failed to demonstrate that you understand the problem. If you’re willing to subsidize poor engineering then you’re going to have to come to terms with adopting TDD eventually, at some stage of the project’s lifecycle, because, you have created an environment where people have merged untested code and you have no way to guarantee to stakeholders that you’re not blowing smoke. More importantly, your users care. Because your users are trusting you. And you should care most of all about your users. They are the ones paying your bills. Be good to them.
- srer 4y ago> But fundamentally no one should ever be trying to merge code that hasn’t been unit tested. If they are, that is a huge problem because it shows arrogance, ignorance, willingness to kick-the-can-down-the-road, etc. Here you are asserting that unit testing is fundamental, and that not believing this is arrogance and ignorance. I'd suggest your view that your way is "the" way, is an ironic display of arrogance, and perhaps ignorance. And this perhaps I think is the core of much of the anti-TDD sentiment. It's not that we don't think TDD and unit tests are without their positives, it's that we don't like being told this is the one true way to write software, and if we don't do it your way we are engaging in poor engineering.
- woeirua 4y agoTDD is great for some types of code, where the code is mostly self-contained with few external dependencies and the expected inputs and outputs are well defined and known ahead of time. TDD is miserable for code that is dependent on data or external resources (especially stateful resources). In most cases, writing "integration" tests feels like its not worth the effort given all the code that goes into managing those external resources. Yes, I know about mocking. But mocking frameworks are: 1 - not trivial to use correctly, and 2 - often don't implement all the functionality you may need to mock.
- zoomablemind 4y ago>...TDD is great for some types of code, where the code is mostly self-contained with few external dependencies and the expected inputs and outputs are well defined and known ahead of time. I find that TDD is very well fit to fix the expectations from the external dependencies. Of course, when such dependency is extensive, like an API wrapper, then writing equally extensive tests would be redundant. Even then, the core aspects of the external dependencies should be fixed testably. Testing is a balance game, even with TDD. The goal is to increase certainty under dynamic changes and increasing complexity.
- evouga 4y agoI completely agree. I'll use TDD when implementing a function "where the code is mostly self-contained with few external dependencies and the expected inputs and outputs are well defined and known ahead of time" and where the function is complex enough that I'm uncertain about its correctness. Though I find I usually do property testing, or comparison to a baseline on random inputs, similar to the quicksort example in the blog post (against a slow, naive implementation of the function; or an older version of the function, if I'm refactoring) rather than straight TDD. When debugging, I'll also turn failure cases into unit tests and add them to the CI. The cost to write the test has already been paid in this case, so using them to catch regressions is all-upside. System tests are harder to do (since they require reasoning about the entire program rather than single functions) but in my experience are the most productive, in terms of catching the most bugs in least time. Certainly every minute spent writing a framework for mocking inputs into unit tests should probably have been spent on system testing instead.
- ChrisMarshallNY 4y agoI find some of the techniques espoused by TDD proponents to be quite useful. In some of my projects. Like any technique, it's not dogma; just another tool. One of my biggest issues with "pure" TDD, is the requirement to have a very well-developed upfront spec; which is actually a good thing. sometimes. I like to take an "evolutionary" approach to design and implementation[0], and "pure" TDD isn't particularly helpful, here. [0] https://littlegreenviper.com/miscellany/evolutionary-design-specification/ https://littlegreenviper.com/miscellany/evolutionary-design-... Also, I do a lot of GUI and device interface stuff. Unit tests tend to be a problem, in these types of scenarios (no, "UI unit testing" is not a solution I like). That's why I often prefer test harnesses[1]. My testing code generally dwarfs my implementation code. [1] https://littlegreenviper.com/miscellany/testing-harness-vs-unit/ https://littlegreenviper.com/miscellany/testing-harness-vs-u... Here's a story on how I ran into an issue, early on[2]. [2] https://littlegreenviper.com/miscellany/concrete-galoshes/#story_time https://littlegreenviper.com/miscellany/concrete-galoshes/#s...
- twic 4y ago> One of my biggest issues with "pure" TDD, is the requirement to have a very well-developed upfront spec; which is actually a good thing. Can you expand on what you mean by "a very well-developed upfront spec"? Because that doesn't sound at all like TDD as i know it. I work on software that takes in prices for financial instruments and does calcualtions with them. initially there was one input price for everything. A while ago, a requirement came up to take in price quotes from multiple authorities, create a consensus, and use that. I had a chat with some expert colleagues about how we could do that, so i had a rough idea of what we needed. Nothing written down. I created an empty PriceQuoteCombiner class. Then an empty PriceQuoteCombinerTest class. Then i thought, "well, what is the first thing it needs to do?". And decided "if we get a price from one authority, we should just use that". So i wrote a test that expressed that. Then made it pass. Then thought "well, what is the next thing it should do?". And so on and so forth. And today, it has tests for one authority, multiple authorities, no authorities, multiple authorities but then one sends bad data, multiple authorities and one has a suspicious jump in its price which might be correct, might not, and many more cases. The only point at which i had anything resembling a well-developed upfront spec was when i had written a test, and that was only an upfront spec for the 1-100 lines of implementation code i was about to write. So your mention of "a very well-developed upfront spec" makes me wonder if you weren't actually doing TDD. No argument about testing user interfaces, though. There is no really good solution to that, as far as i know.
- yuan43 4y ago> ... I practice “weak TDD”, which just means “writing tests before code, in short feedback cycles”. This is sometimes derogatively referred to as “test-first”. Strong TDD follows a much stricter “red-green-refactor” cycle: > 1. Write a minimal failing test. > 2. Write the minimum code possible to pass the test. > 3. Refactor everything without introducing new behavior. > The emphasis is on minimality. In its purest form we have Kent Beck’s test && commit || reset (TCR): if the minimal code doesn’t pass, erase all changes and start over. An example would be helpful here. In fact, there's only a single example in the entire article. That's part of the problem with TDD and criticisms of it. General discussions leave too much to the imagination and biases from past experience. Give me an example (pick any language - it doesn't matter), and now we can talk about something interesting. You have a much better chance of changing my mind and I have a much better chance of changing yours. The example in the article (quick sort) is interesting, but it's not clear how it would apply to different kinds of functions. The author uses "property testing" to assert that a sorted list's members are of ascending value. The author contrasts this with the alleged TDD approach of picking specific lists with specific features. It's not clear how this approach would translate to a different kind of function (say, a boolean result). Nor is it clear what the actual difference is because in both cases specific lists are being chosen.
- tikhonj 4y agoThere was an example of what it means to write minimal code to pass a test with QuickCheck which illustrates pretty much exactly the stuff you quoted.
- jmconfuzeus 4y agoI noticed that proponents of TDD are mostly consultants who sell TDD courses or seminars. You rarely see someone who writes production code preach TDD. Something fishy there...
- salawat 4y agoPeople who write production code generally have QA teams they yeet the testing burden to. Said teams absorb a lot of the pain of Soft Devs who don't bother even running their own code.
- xtracto 4y agoThe "throw shit at the wall and see what sticks" programming technique. Several years ago I was part of a team of developers in an org that did not have a formal QA process. Code was "just OK" but we shipped working products. At some point we (the management) decided to add a QA step with formal QA Engineers (doing part QA automation and manual QA). As a result Engineers became sloppy and realized they could get "extra time" if they delivered half-assed code that had bugs that were caught by QA. That was painful.
- joshstrange 4y agoThat's fair but let's not pretend QA is even in the same ballpark as tests, QA is about a billion times more useful. First and foremost because they didn't write the code. I believe strongly that developers make horrible tests because it's a completely different mindset that is not easy to switch between and near impossible if you wrote the code yourself that you are testing. We tend to lean into the "happy path" and don't even consider "outlandish" things a user might do. I have immense respect for a good QA person and I've had the privilege of working with a number of them, some I'd hire in a heartbeat if it were up to me. I'm not 100% anti-testing but the only testing I've seen produce real results was automated browser testing, and that was only after 2 very large attempts by the development team to do it. Finally we brought in someone whose sole job was the automated browser testing suite. In a very short amount of time he had something working that was producing useful results, something our 2 previous attempts never did. I believe it was in part since he didn't work with or write any of the code, he had no preconceptions, he didn't "think" the way we did since we knew the inner workings. From this and other experiences I think QA and Dev should be 2 seperate groups/teams without overlap (don't have devs do QA, they don't like doing it and they just aren't good at it).
- Joker_vD 4y agoThe fact that some people really argue that TDD produce better designs... sigh. Here, look at this [0] implementation of Dijkstra's algorithm, written by Uncle Bob himself. If you think that is well-designed (have you ever seen weighted graphs represented like this?) then, well, I guess nothing will ever sway your opinion on TDD. And mind you, this is a task that does have what a top comment in this very thread calls a "well defined spec". [0] https://blog.cleancoder.com/uncle-bob/2016/10/26/DijkstrasAlg.html https://blog.cleancoder.com/uncle-bob/2016/10/26/DijkstrasAl...
- rmetzler 4y agoCan you link to an implementation you would consider great? I would just like to compare them. I too find Uncle Bobs “clean code” book very much overrated. My understanding of the “design” aspect of TDD is, that you start from client code and create the code that conforms to your tests. Too often I worked in a team with other developers and I wanted to use what they wrote, and they somehow coded what was part of the spec, but it was unusable from my code. Only because I was able to change their code (most often the public API) I was able to use it.
- whimsicalism 4y agoIt stores it as a collection of edges? Why not use adjacency list representation? You iterate through all of the edges every time to find a nodes neighbors? idk, this code just looks terrible to me.
- sdevonoes 4y agoBut TDD (the main topic being discussed here) has nothing to do with that, right? I mean, how on earth is TDD going to help you decide between a) using a simple data structure like a collection and b) a more sophisticated data structure like the adjacency list, if you have no idea what an adjacency list is?
- whimsicalism 4y ago
- tippytippytango 4y agoThe main reason TDD hasn't caught on is there's no evidence it makes a big difference in the grand scheme of things. You can't operationalize it at scale either. There is no metric or objective test that you can run code through that will give you a number in [0, 1] that tells you the TDDness of the code. So if you decide to use TDD in your business, you can't tell the degree of compliance with the initiative or correlation with any business metrics you care about. The customers can't tell if the product was developed with TDD. Short of looking over every developer's shoulder, how do you actually know the extent to which TDD is being practiced as prescribed? (red, green, refactor) Code review? How do you validate your code reviewer's ability to identify TDD code? What if someone submits working tested code; but, you smell it's not TDD, what then? Tell them to pretend they didn't write it and start over with the correct process? What part of the development process to you start to practice it? Do you make the R&D people do it? Do you make the prototypers do it? What if the prototype got shipped into production? Because of all this, even if the programmers really do write good TDD code, the business people still can't trust you, they still have to QA test all your stuff. Because they can't measure TDD, they have no idea when you are doing it. Maybe you did TDD for the last release; but, are starting to slip? Who knows, just QA the product anyways. I like his characterization of TDD as a technique. That's exactly what it is, a tool you use when the situation calls for it. It's a fantastic technique when you need it.
- deleted 4y ago[deleted]
- mehagar 4y agoYou make a good point about not being able to enforce that TDD is actually followed. The best we could do is check that unit tests exist at all. In theory, if TDD really reduces the number of bugs and speeds up development you would see if reflected in those higher level metrics that impact the customer.
- tippytippytango 4y agoExactly, if it made a big difference to profitability then it would be evident in the market place. TDD shops would out compete the ones that don’t use it. This doesn’t seem to happen in the market. What that means, if TDD is a benefit, it is such a small benefit that other factors in the business eclipse its impact.
- shadowgovt 4y agoWhere I come from, unit-test-driven-development tends to be a waste of resources. The interfaces will change so much during development that anything you write initially is guaranteed to be torn up. The one exception is if you're writing an interface that crosses teams; for "ship your org chart" reasons, we not only can, but must assume that interface is stable enough to mock and test against (and a knife-fight is necessary if it isn't). However, getting the client to agree that their design feature is satisfied by a specific set of steps, then writing software that satisfies that request, is a form of test-driven-development and I support it.
- agentultra 4y agoI've been in software development for over twenty years. I have similar feelings about maximalism in a lot of areas. Many organizations producing software today don't share many values with me as an engineer. Startups aren't going to value correctness, reliability, and performance nearly as much as an established hardware company. A startup is stumbling around trying to find a niche in a market to exploit. They will value time to market above most anything else: quick, fast solutions with minimal effort. Almost all code written in this context is going to be sloppy balls of mud. The goal of the organization is to cash out as fast as possible; the code only has to be sufficient to find product-market fit and everyone riding the coat-tails of this effort will tolerate a huge number of software errors, performance issues, etc. In my experience practicing TDD in the context of a startup is a coping mechanism to keep the ball of mud going long enough that we don't drown in errors and defects. It's the least amount of effort to maintain machine-checked specifications that our software does what we think it does. It's not great. In other contexts it's not even sufficient. But it's often the only form of verification you can get away with. Often startups will combine testing strategies and that's usually, "good enough." This tends to result in the testing pyramid some might be familiar with: many unit tests at the bottom, a good amount of integration tests in the middle, and some end-to-end tests and acceptance tests at the top. However the problem with TDD is that I often find it insufficient. As the article alludes to there are plenty of cases where property based testing has stronger guarantees towards correctness and can prevent a great deal more errors by stating properties about our software that must be true in order for our system to be correct: queued items must always be ordered appropriately, state must be fully re-entrant, algorithms must be lock-free: these things are extremely hard to prove with examples: you need property tests at a minimum. The difficulty with this is that the skills used to think about correctness, reliability, and performance require a certain level of mathematical sophistication that is not introduced into most commercial/industrial programming pedagogy. Teaching programmers how to think about what it would mean to specify that a program is correct is a broad and deep topic that isn't very popular. Most people are satisfied with "works for me." In the end I tend to agree that it takes a portfolio of techniques and the wisdom to see the context you're working in to choose the appropriate techniques that are sufficient for your goals. If you're working at a startup where the consequences are pretty low it's unlikely you're going to be using proof repair techniques. However if you're working at a security company and are providing a verified computing base: this will be your bread-and-butter. Unit tests alone would be insufficient.
- SkyMarshal 4y agoTDD is just a huge ugly kluge to compensate for languages designed with inadequate internal correctness guarantees. So instead we have to tack on a huge infrastructure of external correctness guarantees instead. TDD is an ad-hoc, informally-specified, bug-ridden, slow implementation of half of a strong type system.
- Jtsummers 4y agoUnless your language includes a proper proof system for the entire program logic (see Idris or SPARK/Ada for something close to this, though in the latter it can only work with a subset of the overall Ada language), you will need tests. Even in languages like Haskell, Rust, and Ada which have very good and expressive type systems tests are helpful for validating the actual logic of the system.
- SomeCallMeTim 4y agoNeeding tests != TDD. Needing tests != Unit Tests. Adding larger system tests after the fact is perfectly reasonable. TDD wants you to write tiny tests for every square millimeter of functionality. It's just not worth it, and 99% of the value is to make up for shortcomings in dynamic languages.
- SkyMarshal 4y agoYes that’s true, and imho the objective should be to move as much of TDD as possible into the type system. Despite my OP maybe implying it’s binary, it’s not, and getting closer to that objective is just as worthy as getting all the way there. It’s still a hard problem and getting all the way there will take years or decades more experience, experimentation, research, and learning.
- AnthonBerg 4y agoAgreed!; Personally, I am of the opinion that Idris for one is mature enough that there is no need to forego tools that have a proper proof system for the entire program. It’s feasible today. Idris is carefully and purposefully described by its creators as not production ready. Nonetheless, because of what Idris is, it’s arguably more production-ready than languages which don’t even attempt formal soundness to anywhere near the same degree. In other words: Idris is not a complete Idris. But! All the other languages are even less complete Idrises! Big old “personal opinion” disclaimer here though. –Let’s prove it’s not possible to use Idris by doing it! Shall we?
- sandreas 4y agoIn my opinion TDD is a good thing, but too demanding and too strict. In real life, there are very different knowledge / experience levels in a development team and if TDD is not applied professionally, it may not help. It just needs a lot of practise and experience. What it helps with a lot is improving your individual programming skills. So I recommend TDD to everyone, who never did it in practise (best case on a legacy code base) - if not to improve the code itself, then just to LEARN how it could improve your code. It helped me to understand, why IoC and Dependency Injection are a thing and when to use it. Writing "testable" code is important, while writing real tests may be not as important, as long as you do not plan to have along running project or do a major refactoring. If you ARE planning a major refactoring, you should first write the tests to ensure you don't break anything, though ;) What I also would recommend is having a CI / Build-Environment supporting TDD, SonarQube and CodeCoverage - not trying to establish that afterwards... Being able to switch to TDD is also a very neat way to get a nice CI setup. My feeling is, that my programming and deployment skills improved best, when I did one of my personal pet projects strictly test driven with automated CI and found out about the things in TDD and CI, I really need to care about.
- elboru 4y agoOne of the biggest issues with our industry is the ambiguity in our definitions. The author mentions “unit tests” as if it was a well defined term. But some people understand “unit” as a class, other understand it as a module, others as a behavior. Some TDDers write unit tests that would be considered “integration tests” by other developers. Then we have TDD itself, there are at least two different schools of TDD. What the author calls “maximal TDD” sounds like the mockist school to me. Would his criticism also apply to the classical school? I’m sincerely curious. If we don’t have a common ground, communication becomes really difficult. Discussion and criticism becomes unfruitful.
- geodel 4y agoThe way I see, all this cultish crap: Agile, TDD, Scrum, Kanban, XP etc..etc works when essentially same thing is done nth time. I have seen plenty of success with these when same project is roughly repeated for many different clients. It is also no surprise these terms have mostly to do with IT or related consulting and not really about engineering endeavor. In my first hand experience when I worked at engineering department there was whole lot of work done with almost non-existent buzzword bullshit. And later on with merger etc it is now an IT department so there is endless money on process training, resources, scrum masters and so on but little money is left for half decent computer setup. Outside work I have seen this in my cooking, first time new dish is a hustle but in future iterations I would create little in-brain task list tickets for my own processing. Doing this in jackasstic consulting framework way would turn 1 hr worth of butter chicken recipe into 1 month work of taste feature implementation sprints.
- fasteddie31003 4y agoThe TDD tradition comes from dynamically typed languages. If you write a Ruby or JavaScript function it's got a good chance of not working the first time you run it. However, with statically typed languages your function has a much better chance of running, if it compiles. IMO TDD only makes sense for dynamically typed languages.
- MattPalmer1086 4y agoI once tried to write something using a pure TDD approach. It was enlightening. Pluses were refactoring was easy and I had confidence that the system would work well at the end. Minuses were it took a lot longer to write and I had to throw away a lot of code and tests as my understanding increased. It slowed down exploration immensely. Also, factoring the code to be completely testable led to some dubious design decisions that I wouldn't make if I wasn't following a pure TDD approach. On balance I decided it wasn't a generally good way to write code, although I guess there may be some circumstances it works well for.
- Lapsa 4y agodamn it. hoped it's about that train game
- AtNightWeCode 4y agoThe productivity rate went through the roof when we ditched TDD. TDD has a bit of the same problem as strict DDD. You spend a lot of time making upfront decisions about things that does not really matter or you don’t know about. I see unit tests as a tool to be used where it makes sense and I use it a lot. It is true that testable code is better. Testability should be a factor when selecting tech.
- righttoolforjob 4y agoI agree with your first sentence, but TDD and unit tests are completely diametrical concerns. Unit tests serve multiple purposes. Number 1 is to have a way for you to play around with your design. Then it also can document requirements. I then lastly serves as a vehicle for you to prove something about your design, typically the fulfillment of a requirement, or the handling of some edge case, etc. This last part is what people unfortunately mostly refer to as a test. TDD says that you should write your tests before you even have a design, one-by-one typically, adding in more functionality and design as you go. You will end up with crap code. If you do not throw the first iteration away then you will commit crappy code. Most people naturally find that an iterative cycle of design and test code works the best and trying to sell TDD to them is a harmful activity, because it yields no benefits and might actually be a big step backwards.
- AtNightWeCode 4y agoUnit test has at least three different meanings so I think the term should be scrapped. Here I meant basically automated tests. I worked with TDD and you basically write twice as much code that is four times as complicated and then you stick with poor design choices cause you have to update all the tests as well.
- moomoo11 4y agoI like TDD. It’s just a tool on our tech belt. If done right (takes practice and open mind tbh) the major benefit is you have code that is single responsibility and easy to understand, isolate, or modify. We have so many things on our tech belt, like clean architecture or x pattern. This is just another tool, and I think it helps especially in building complex software. Just be practical and don’t try to be “the 100%er” who is super rigid about things. Go into everything with a 80/20 mindset. If this is something mission critical and needs to be as dependable as possible, then use the tools best suited for it. If you’re literally putting buttons on the screen which Product is going to scrap in two weeks, maybe use TDD for the code responsible for dynamically switching code based on Product mindset that week.
- gregors 4y agoWrite the code you wish you had. Define your expectation. Does your coding ability keep up with your expectations? Does that continue to hold for you or anyone else on your team on your worst day? Don't have any expectations and are exploring? Don't do any of this.
- peteradio 4y agoI write tests in order to have something to run and hit breakpoints on while I develop code. Is that TDD? The tests don't even necessarily check anything at the earliest stages, obviously they are red if the code barfs but that's about it. Once the code solidifies I may take some output and persist it to make sure it doesn't change, but "does not crash" is technically a testable endpoint!
- metanonsense 4y agoI always liked the discussion "Is TDD dead" between David Heinemeier Hansson (of Ruby on Rails and Basecamp fame) and Kent Beck. DHH arguing against, Kent Beck obviously in favor of TDD. Martin Fowler is moderator and the discussion is very nuanced and slowly identifies areas where TDD has its benefits and where it should be rather avoided. https://martinfowler.com/articles/is-tdd-dead/ https://martinfowler.com/articles/is-tdd-dead/
- ajkjk 4y agoI feel like TDD's usefulness depends very much on what type of code you're writing. If it's C libraries that fiddle that do lots of munging of variables, like positioning UI or fiddling with data structures... then yes, totally, it has well-defined requirements that you can assert in tests before you write it. If it's like React UI code, though, get out of here. You shouldn't even really be writing unit tests for most of that (IMO), much less blocking on writing it first. It'll probably change 20 times before it's done anyway; writing the tests up from is going to just be annoying.
- mal-2 4y agoDefinitely agree. In the time it took you to mock your the state management, the backend endpoints, and the browser localStorage to isolate your unit, you probably could have written it in Playwright end-to-end with nothing mocked. The you'd actually know if your react code broke when the API changed, instead of pretending your out of date mock is still in sync.
- lynndotpy 4y agoIMO TDD should be by opportunity and not policy. That solves basically all the problems I have with it. TDD is great because it forces you to concretize and challenge assumptions, and provides a library of examples for new devs to a codebase.
- righttoolforjob 4y agoYou are arguing for having tests and good coverage, not for doing TDD.
- lynndotpy 4y agoNo, I am arguing for TDD, specifically, writing tests before code. It feels like a superpower when it works. Maybe that's for a whole program or only small parts of it.
- mehagar 4y agoI think TDD is great in the ideal, but in reality I have only worked on legacy systems where TDD was not practiced from the start. Such systems are hard to fit TDD style tests into because modifying existing code often requires large refactoring to properly inject dependencies and create seams for testing. The catch-22 is that refactoring itself is prone to breaking things without sufficient testing. As a result, I often try to fit my tests into these existing systems rather than starting with the test and refactor the code under test to fit that shape. The only resource I've seen for dealing with this issue is the advice in the book "Working Effectively with Legacy Code", to write larger system tests first so you can safely refactor the code at a lower level. Still, that's a daunting amount of work when it's ultimately much easier for me to just make the change and move on.
- bonestamp2 4y agoWe follow what we call TID (Test Informed Development). Basically, we know that we're going to have to write tests when we're done, so we are sure to develop it in a way that is going to be (relatively) easy to write accurate and comprehensive tests for.
- choeger 4y agoThe observation about the focus on unit tests is well-made. I think it's a crucial problem that stems from very good tools for unit testing and developers that are very familiar with these tools. It's then very simple to discard anything that isn't covered by these great tools. But here's an anecdote that explains why you'd always want integration tests (other anecdotes for other test paradigms probably also exist): imagine a modern subway train. That train is highly automated but, for safety reasons, still requires a driver. The train has two important safety features: 1. The train won't leave a station unless the driver gives their OK. 2. The train won't leave the station unless all doors are closed. The following happened during testing: The driver gives the OK to leave the station. The train doesn't start because a door is still open. The driver leaves the train and finds one door blocked. After the driver removes the blockage the door closes and the train departs. Now driverless. I think it's crucial to view integration tests as unit tests on a different level: You need to test services, programs, and subsystems as well as your classes, methods, or modules.
- pjmlp 4y agoMy feelings are quite clear, it just doesn't work besides some simple cases without any kind of GUI (including native ones), or distributed computing algorithms. It does for nice conference talks though.
- gnulinux 4y agoWhen you say TDD doesn't work do you mean it doesn't work if it's religiously practiced? I've worked for many companies who do TDD and I personally enjoy it very much and we ship code, we make money. So clearly something is not not working. I think the trick with TDD is making sure you don't use it religiously and understand in what cases it'll help you.
- pjmlp 4y agoProve me wrong designing a good native Windows application according to customer's UI/UX guidelines by religiously following TDD. Replace Windows by favourite desktop, mobile or console OS.
- gnulinux 4y agoI don't do Windows work, I don't do UI/UX and I do not religiously follow TDD. TDD is a tool, just like other tools I know when it applies to a scenario and when it applies I know what it's helping me with.
- pjmlp 4y agoThat isn't how it is sold. It only works for basic use cases and conference talks.
- gnulinux 4y agoI'm not trying to sell anything. I'm reporting you an anecdote that I'm a practicing software engineer, I've been professionally writing code for almost a decade and I do use TDD when I write code. I don't care if you do or do not.
- brightball 4y agoAs with anything, there's going to be a group of strict adherents, strong opposition and the set of people who have used it enough to only apply it where useful. It's definitely useful, but those strongly opposed often won't use it at all unless it mandated which tends to lead to strict adherence policies at a lot of companies.
- sedachv 4y agoTDD use would be a lot different if people actually bothered to read the entirety of Kent Beck's _Test Driven Development: By Example_. It's a lot to ask, because it is such a terribly written book, but there is one particular sentence where Beck gives it away: > This has happened to me several times while writing this book. I would get the code a bit twisted. “But I have to finish the book. The children are starving, and the bill collectors are pounding on the door.” Instead of realizing that Kent Beck stretched out an article-sized idea into an entire book, because he makes his money writing vague books on vague "methodology" that are really advertising brochures for his corporate training seminars, people actually took the thing seriously and legitimately believed that you (yes, you) should write all code that way. So a technique that is sometimes useful for refactoring and sometimes useful for writing new code got cargo-culted into a no-exceptions-this-is-how-you-must-do-all-your-work Law by people that don't really understand what they are doing anymore or why. Don't let the TDD zealots ruin TDD.
- evouga 4y agoThis seems to be the case with a lot of "methodologies" like TDD, Agile, XP, etc. as well as "XXX considered harmful"-style proscriptions. A simple idea ("hey, I was facing a tricky problem and this new way of approaching it worked for me. Maybe it will help you too?") mutates into a blanket law ("this is the only way to solve all the problems") and then pointy-haired folks notice the trend and enshrine it into corporate policy. But Fred Brooks was right: there are no silver bullets. Do what works best for you/your team.
- cpill 4y agoyeah, I find software engineers like to find absolute answers to fuzzy problems. I guess it's the nature of the job
- bitwize 4y agoThe 2000s design-patterns-mania is another case. Design patterns should be thought of less as things you have to memorize and apply in a textbook fashion, and more like tropes: things you'll see over and over in code, and once you know their names you can start talking about them and their interactions in meaningful ways. Just as writers like tropes because they make the job of writing easier, overuse of them is a sign of laziness; and so it is with design patterns.
- reggieband 4y agoI could write an entire blog post on my opinions on this topic. I continue to be extremely skeptical of TDD. It is sort of infamous but there is the incident where a TDD proponent tries and fails to develop a sudoku solver and keeps failing at it [1]. This kind of situation matches my experience. It was cemented when I worked with a guy who was a zealot about TDD and the whole Clean Code cabal around Uncle Bob. He was also one of the worst programmers I have worked with. I don't mean to say that whole mindset is necessarily bad. I just found that becoming obsessed with it isn't sufficient. I've worked with guys who have never written a single test yet ship code that does the job, meets performance specs, and runs in production environments with no issues. And I've worked with guys who get on their high horse about TDD but can't ship code on time, or it is too slow, and it has constant issues in production. No amount of rationalizing about the theoretical benefits can match my experience. I do not believe you can take a bad programmer and make them good by forcing them to adhere to TDD. 1. https://news.ycombinator.com/item?id=3033446 https://news.ycombinator.com/item?id=3033446
- mikkergp 4y ago>I've worked with guys who have never written a single test yet ship code that does the job, meets performance specs, and runs in production environments with no issues. I'm curious to unpack this a bit. I'm curious what other tools people use other than testing programatic testing; programatic testing seems to be the most efficient, especially for a programmer. I'm also maybe a bit stuck on the binary nature of your statement. You know developers who've never let a bug or performance issue enter production(with or without testing)?
- reggieband 4y agoOriginally when I started out in the gaming industry in the early 2000s. There were close to zero code tests written by developers at that time at the studios I worked for. However, there were large departments of QA, probably in the ratio of 3 testers per developer. There was also an experimental Test Engineer group at one of the companies that did automated testing, but it was closer to automating QA (e.g. test rigs to simulate user input for fuzzing). The most careful programmers I worked with were obsessive about running their code step by step. One guy I recall put a breakpoint after every single curly brace (C++ code) and ensured he tested every single path in his debugger line by line for a range of expected inputs. At each step he examined the relevant contents of memory and often the generated assembly. It is a slow and methodical approach that I could never keep the patience for. When I asked him about automating this (unit testing I suppose) he told me that understanding the code by manually inspecting it was the benefit to him. Rather than assuming what the code would (or should) do, he manually verified all of his assumptions. One apocryphal story was from the PS1 days before technical documentation for the device was available. Legend had it that the intrepid young man brought in an oscilloscope to debug and fix an issue. I did not say that I know any developers who've never let a bug or performance issue enter production. I'm contrasting two extremes among the developers I have worked with for effect. Well written programs and well unit tested programs are orthogonal concepts. You can have one, the other, both or neither. Some people, often in my experience TDD zealots, confuse well unit tested programs with well written programs. If I could have both, I would, but if I could only have one then I'll take the well-written one. Also, since it probably isn't clear, I am not against unit testing. I am a huge proponent for them, advocating for their introduction alongside code coverage metrics and appropriate PR checks to ensure compliance. I also strongly push for integration testing and load testing when appropriate. But I do not recommend strict TDD, the kind where you do not write a line of code until you first write a failing test. I do not recommend use of this process to drive technical design decisions.
- m463 4y agoTDD - test driven development
- righttoolforjob 4y agoTDD is really, really bad. I won't even add arguments. TDD is typically sold by Agilists from which most content deserves to go in the same trash bin. Most of these people have never written code for real. Their opinions are worthless. Thanks, bye.
- littlestymaar 4y agoIt looks like the human brain is wired up in a way that can turn anything into a religion
- deleted 4y ago[deleted]
- deleted 4y ago[deleted]
- dbrueck 4y agoIt's all about tradeoffs. I've done a few decades of non-TDD with a middle period of ~5 years of zealot-level commitment to TDD, and as a rule of thumb, the cost is usually not worth the benefit. Some hidden/unexpected side effects of TDD include the often extremely high cost of maintaining the tests once you get past the simple cases, the subtle incentive to not think too holistically about certain things, and the progression as a developer in which you naturally improve and stop writing the types of bugs that basic tests are good at catching but which you continue to write anyway (a real benefit, sure, but one that further devalues the tests). The cost of creating a test that would have caught the really "interesting" bugs is often exorbitant, both up front and to maintain. The closest thing I've encountered to a reliable exception is that having e.g. a comprehensive suite of regression tests is really great when you are doing a total rewrite of a library or critical routine. But even that doesn't necessarily mean that the cost of creating and maintaining that test suite was worth it, and so far every time I've encountered this situation, it's always been relatively easy to amass a huge collection of real world test data, which not only exercises the code to be replaced but also provides you a high degree of confidence that the rewrite is correct.
- bndr 4y agoThere are three things in my opinion that speak against going with TDD: 1. Many companies are agile, and the requirements constantly change, which makes implementing TDD even harder. 2. TDD does not bring enough value to justify the investment of time (for writing & maintaining the test suites), the benefits are negligible, and the changes are often. 3. Everything is subjective [1], and there's no reason to have such strongly held opinions about the "only right way to write code" when people write software in a way that is efficient for their companies. [1] https://vadimkravcenko.com/shorts/software-development-subjective/ https://vadimkravcenko.com/shorts/software-development-subje...
- cannam 4y agoThis is a good article, with (for me anyway) quite a twist at the end. The author quotes a tweet expressing amazement that any company might not use TDD, 20 years after it was first popularised - and then writes "I’d equate it to shell scripting. I spent a lot of time this spring learning shell scripting" Wow! I feel like the person in the tweet. It's amazing to me that someone could be in a position to write an article with such solid development background without having had shell scripting in their everyday toolbox. (I use TDD some of the time - I was slow to pick it up and a lot of my older code would have been much better if I had appreciated it back then. I like it very much when I don't really know how the algorithm is going to work yet, or what a good API looks like.)
- NohatCoder 4y agoYou can use a "real" programming language for anything more complicated than running a program with some parameters. Really, the only thing the various Shell variants have going for them is that you can type it directly into the console. For any lightly complicated programming task they are abysmal languages.
- cannam 4y agoQuite right! But approximate experiments and lightweight automation are really useful in deciding where to go and then making sure you stay there. I'm all for test-first, but I'd find it very hard to argue that it's a more important tool than, well, scripting things.
- NohatCoder 4y agoShell scripting is just one option for scripting, some popular (and IMO better) options are Perl, Python and JavaScript. I'm sure there are also people who use C for quick and dirty tasks. Seems weird, yes. But if that is the language you know best it may be the fastest in the short term.
- n4jm4 4y agoTDD's contribution to software quality scrapes the bottom of the barrel. Attention to detail in scalable design, formal verification, fuzzing, and mutation testing offer deeper guarantees of successful operation. But of course, the American ideal "make money" is worn proudly on the rim of management noses. It's the wrong prescription, but they're too busy counting their bills to care. This is evident especially in cybersecurity, where the posture amounts to silent prayer that no one stumbles across their JRE 1.0's and their Windows XP's and Google's latest attempt at a programming language with buffer overflows by design--batteries included.
- gregmac 4y agoThe author defines two types of TDD: "weak TDD" and "strong TDD". I'd argue there's another, though I'm not sure what to call it -- "Pragmatic TDD" perhaps? What I care about is having unit tests that cover the complicated situations that cause bugs. I think one of the main problems with TDD is its proponents focus so much on the process as opposed to the end result. The way I practice "pragmatic TDD" is to construct my code in a way that allows it to be tested. I use dependency injection. I prefer small, static methods when possible. I try not to add interfaces unless actually needed, and I also try to avoid requiring mocks in my unit tests (because I find those tests harder to write, understand, and maintain). Notably: I explicitly don't test "glue code". This includes stuff in startup -- initializing DI and wiring up config -- and things like MVC controllers. That code just doesn't have the cost-benefit to writing tests: it's often insanely difficult to test (requiring lots of mocks or way over-complicated design) and it's obvious when broken as the app just won't work at all. Integration or UI automation tests are a better way to check this if you want to automate it. I strive to just test algorithm code. Stuff with math, if/else logic, and parsing. I typically write the code and tests in parallel. Sometimes I start writing what I think is a simple glue method before realizing it has logic, so I'll refactor it to be easy to test: move the logic out to its own method, make it static with a couple extra parameters (rather than accessing instance properties), move it to its own class, etc. Sometimes I write tests first, sometimes last, but most often I write a few lines of code before I write the first tests. As I continue writing the code I think up a new edge case and go add it as a test, and then usually that triggers me to think of a dozen more variations which I add even if I don't implement them immediately. I try not to have broken commits though, so I'll sometimes comment out the broken ones with a `TODO`, or interactive rebase my branch and squash some stuff together. By the time anyone sees my PR everything is passing. I think the important thing is: if you look at my PR you can't tell what TDD method I used. All you see is I have a bunch of code that is (hopefully) easy to understand and has a lot of unit tests. If you want to argue some (non-tested) code I added should have tests, I'm happy to discuss and/or add tests, but your argument had better be stronger than "to get our code coverage metric higher". Whether I did "strong red-green-refactor TDD" or "weak TDD" or "pragmatic TDD" the result is the same. I'd argue caring about how I got there is as relevant as caring about what model of keyboard I used to type it.
- joshstrange 4y agoI'm not anti-TDD necessarily but I've yet to see tests yield useful results at almost everyone company I've worked it. It could be I've just never worked with someone who was actually good at tests. Tests in general aren't something I regularly use and a lot of TDD feels somewhat insane to me. You can write all the tests you want ahead of time but until the rubber meet the road it's a lot of wishful thinking in my experience. Also it makes refactoring hell since you often have to rewrite all the tests except the ones at the top level and sometimes even those if you change enough. I believe tests can work, I've just never really seen them work well expect for very well defined sets of functionality that are core to a product. For example I worked at a company that had tests around their geofencing code. Due to backfilling data, zones being turned on/off by time, exception zones within zones, and locations not always being super accurate, the test suite was impressive. Something like 16 different use cases it tested for (to determine if a person was in violation for a given set of locations, for a given time). However, at the same company, there was a huge push to get 80%+ code coverage. So many of our tests were brittle that we ended up shipping code regularly with broken tests because we knew they couldn't be trusted. The tests that were less brittle often had complicated code to generate the test data and the test expectations (who tests the tests?). In my entire time at that company we very rarely (I want to say "never" but my memory could be wrong) had a test break that actually was pointing at a real issue, instead the test was just brittle or the function changed and someone forgot to update the test. If you have to update the test every time you touch the code it's testing... well I don't find that super useful, especially coupled with it never catching real bugs. In a lot of TDD/Tests in general tutorials I've seen they make it seem all roses and sunshine but their examples are simple and look nothing like code I've seen in the wild. I'd be interested in some real-world code and the tests as the evolved over time. All that said, I continue to be at least interested in tests/TDD in the hopes one day it will "click" for me and not see just like a huge waste of time.
- lifeisstillgood 4y ago"The code is the design" conflicts with "TDD". Write code first. If that code is the v0.1 of the protocol between two blog systems great ! you can do that on a whiteboard and it looks like design when actually it's writing code on a whiteboard. Now you know what to test so write the test, after writing the code. Now write the next piece of code. Do not at any time let a project manager in the room
- stuckinhell 4y agoTDD is a great example of where major differences between businesses and departments has direct impact on your software engineering. When business people don't know what they want, do not try TDD. It will be a waste of time. When people do KNOW, or you have a RELIABLE subject matter expert (at a big company you might have one of these), TDD is a lot safer and easier to do.
- _greim_ 4y agoI've chosen to interpret TDD as "test driven design", based on the idea that systems designed to be easily unit-testable tend to also be easier to understand, maintain, extend, compose, repurpose, refactor, etc. I deviate from some proponents in that I think this kind of TDD can be done while writing zero unit tests, but in practice they keep you sensitized to good design techniques. Plus the tests do occasionally catch bugs, and are otherwise a good forum to exercise your types and illustrate your code in action.
- varispeed 4y agoWhat I do is not really pure TDD. I usually don't have a very clear specification of what system needs to be doing (as it is an iterative process). So I write the code and then write tests to see if it gives required outputs for given inputs. Then I write tests to see if it behaves correctly under edge cases. I also pretty much stopped using debuggers because of that. Simply there is no need. I can reproduce an error using the test and then fix the code until it passes it.
- ttctciyf 4y agoIMO, a lot of sage advice about TDD, well informed by years of practice, is in two Ian Cooper NDC talks, his controversial-at-the-time "TDD, Where Did It All Go Wrong?"[1] and, seven years later, "TDD Revisited"[2]. The blurb from the latter: > In this talk we will look at the key Fallacies of Test-Driven Development, such as 'Developers write Unit Tests', or 'Test After is as effective as Test First' and explore a set of Principles that let us write good unit tests instead. Attendees should be able to take away a clear set of guidelines as to how they should be approaching TDD to be successful. The session is intended to be pragmatic advice on how to follow the ideas outlined in my 2013 talk "TDD Where Did it All Go Wrong" The talks focus on reasons to avoid slavish TDD and advocate for the benefits of judiciously applying TDD's originating principles. 1: https://www.youtube.com/watch?v=EZ05e7EMOLM https://www.youtube.com/watch?v=EZ05e7EMOLM 2: https://www.youtube.com/watch?v=vOO3hulIcsY https://www.youtube.com/watch?v=vOO3hulIcsY
- Sohcahtoa82 4y agoI got turned off from TDD in my senior year getting my CS degree. During class, the teacher taught us TDD, using the Test-Code-Refactor loop. Then he wanted us to write an implementation of Conway's Game of Life using TDD. As the students were doing it, he was doing it as well. After the lesson but before the exercise, I thought "This looks tedious and looks like it would make coding take far longer than necessary" and just wrote the Game first, then wrote a couple dozen tests. Took me probably about 45 minutes. At that point, I looked up on the projector and saw the teacher had barely done much more than having a window, a couple buttons, and some squares drawn on it, and a dozen tests making sure the window was created, buttons were created, clicking the button called the function, and that the calls to draw squares succeeded. What really bothers me about "true" TDD (and TFA points this out), is that if you're writing bare minimum code to make a unit test pass, then it will likely be incorrect. Imagine writing an abs() function, and your first test is "assert (abs(-1) == 1)". So you write in your function "if (i == -1) return 1". Congrats, you wrote the bare minimum code. Tadaa! TDD!
- gnulinux 4y agoI'm really sorry but these kind of "I mocked a simple program in 45 mins when my TDD practicing counterpart took longer" comments mean nothing. The code is never written once and done. If you were maintaining that code for the next 6 years and there was no rush to ship it, it absolutely doesn't matter how fast it was written in the first place. I would much rather take code that was written better in 6 hours, than bad code written in 45 mins. I'm not saying you wrote bad code, but time to ship, in general, rarely matters in this context.
- tester756 4y ago>If you were maintaining that code for the next 6 years and there was no rush to ship it, it absolutely doesn't matter how fast it was written in the first place. Unfortunately that's not how software is written. >I would much rather take code that was written better in 6 hours, than bad code written in 45 mins. I'm not saying you wrote bad code, but time to ship, in general, rarely matters in this context. I disagree, time is not the best proxy for good code. 10x engineer will probably write way better code in 45mins than -10x engineer in 6h.
- holoduke 4y agoI believe a good way of programming is to always reverse program. So you start with the output and work back to where the algorithm or program starts. In that way you can easily extract an unit test after you finished your task.
- deleted 4y ago[deleted]
- sdevonoes 4y agoThe first time I encounter TDD, I was a bit surprised because it encourages you to write tests (client code) first. Well, I started my professional career without knowing about TDD, but I did know that usually it's best to start writing the client code first. E.g., you write your main.c/Main.java/main.go first, referencing classes/code that do not exist yet, and wiring everything together. Then you move on to the next layer, write code that should exist but still relying on future code that doesn't exist yet. Eventually you end up writing the whole thing. Sometimes the other approach works equally well (e.g., starting from the small blocks and going up).
- worik 4y agoTesting is very important. Ok. The problem I have with TDD is the concept of writing tests first. Tests are not specifications (in TDD world the line is blurred.) Tests are confirmation. I develop my code (I write back end plumbing code for iOS currently) from a test frame work. My flow: * Specify. A weak and short specification. putting too much work into the specification is a waste. "The Gizmo record must be imported and decoded from the WHIZZBAZ encoding into a Gizmo object" is plenty of specification. * Write code for the basic function. * Write a test for validity of the code (the validity of the record once loaded in the Gizmo/WHIZBAZ case) But the most important tests are small micro tests (usually asserts) before and after every major section (a tight loop, a network operation, system calls etcetera). More than half my code is that sort of test.
- gherkinnn 4y ago> Testable code is best code. Only TDD gets you there. I smell a circular argument but can’t quite put my finger on it. > If it doesn’t work for you, you’re doing it wrong Ah. Start with a nigh unattainable and self-justifying moral standard, sell services to get people there, and treat any deviation as heresy. How convenient. Reminds me of Scrum evangelists. Or a cult. TDD is a great tool for library-level code and in cases where the details are known upfront and stable. But I can’t get it to work for exploratory work or anything directly UI related. It traps me in a local optimum and has draws my focus to the wrong places.
- fleddr 4y agoMy feelings are far less complicated: TDD is a high-discipline approach to software development, and that's why it doesn't work or doesn't get done. High-discipline meaning, it entirely depends on highly competent developers (able to produce clean code, deep understanding of programming), rigorously disciplined out of pure intrinsic motivation, and even able to do this under peak pressure. Which is not at all how most software is built today. Specs are shit so you gradually find out what it needs to do. Most coders are bread programmers and I don't mean that in any insulting way. They barely get by getting anything to work. Most projects are under very high time pressure, shit needs to get delivered and as fast as possible. Code being written in such a way that it's not really testable. We think in 2 week sprints which means anything long term is pretty much ignored. In such an environment, the shortest path is taken. And since updating your tests is also something you can skip, coverage will sink. Bugs escape the test suite and the belief in the point of TDD crumbles. Like a broken window effect. My point is not against TDD. It's against ivory tower thinking that does not take into account a typical messy real world situation. I've noticed a major shift in the last decade. We used to think like this, in TDD, in documenting things with UML, in reasoning about design patterns. It feels like we lost it all, as if it's all totally irrelevant now. The paradigm is now hyper speed. Deliver. Fast. In any way you can. This short-sighted approach leading to long term catastrophe? Not even that seems to matter anymore, as the thing you're working on has the shelf life of fish. It seems to be business as usual to replace everything in about 3-5 years. The world is really, really fast now.
- daviding 4y agoThe 'T' in TDD stands for design. :) The name of it has always hurt the concept I think. In my experience TDD uptake and understanding suffers because a lot of developers are in a context of using an existing framework, and that framework sort of fights against the TDD concepts sometimes. Getting around that with things like dependency injections, reversals etc then gets into the weeds and all sorts of 'Why am I doing this' pain. Put another way, a lot of commercial development isn't the nice green-field coding katas freedom, it's spelunking through 'Why did ActiveRecord give me that?' or 'Why isn't the DOM refreshing now?'. Any friction then gets interpreted as something wrong about TDD and the flow gets stopped.
- andersonvom 4y agoI think people sometimes forget that tests are made of code too. If it's possible to write bad code, it's certainly possible to write bad tests. And writing bad tests first (as in `test-driven`) won't make them any better. At some point, people see bad tests _and_ bad code together and instead of blaming it on the "bad" part, they blame it either on the tests, or on the fact that the tests were written first.
- 0xbadcafebee 4y agoWhy does TDD exist? 1. We want a useful target for our software. You could design a graphical mock-up of software and design your software to fit it. Or you could create a diagram (or several). Or you could create a piece of software (a test) which explains how the software is supposed to work and demonstrates it. 2. When we modify software over time, the software eventually has regressions, bugs, design changes, etc. These problems are natural and unavoidable. If we write tests before merging code, we catch these problems quickly and early. Catching problems early reduces cost and time and increases quality. (This concept has been studied thoroughly, is at the root of practices such as Toyota Production System, and is now called Shift Left) 3. It's easy to over-design something, and hard to design it "only as much as needed". By writing a simple test, and then writing only enough code to pass the test, we can force ourselves to write simpler code in smaller deliverable units. This helps deliver value quicker by only providing what is needed and no more. 4. Other reasons that are "in the weeds" of software design, and can be carefully avoided or left alone if desired. Depends on if you're building a bicycle, a car, or a spaceship. :-) But as in all things, the devil's in the details. It's easy to run into problems following this method. It's also easy to run into problems not following this method. If you use it, you will probably screw up for a while, until you find your own way of making it work. You shouldn't use it for everything, and you should use good judgement in how to do it. This is an example of software being more craft than science. Not every craftsperson develops the same object with the same methods, and that's fine. Just because you use ceramic to make a mug, and another person uses glass, doesn't mean one or the other method is bad. And you can even make something with both. Try to keep an open mind; even if you don't find them productive, others do.
- jldugger 4y ago> You write more tests. If writing a test “gates” writing code, you have to do it. If you can write tests later, you can keep putting it off and never get around to it. This, IMO, is the principle benefit of teaching TDD to early-stage programmers. Early stage programmers and all stages of project manager.
- pkrumins 4y agoMy advice is to follow the famous quote “given enough eyeballs all bugs are shallow”. Add a “send feedback” link in your application and let your users quickly and easily notify you when something goes wrong. My product has several million users and has zero tests and when bugs get pushed to production, users tell me in seconds. Sometimes pushing bugs to production is part of my workflow and then quickly fixing them allows me to iterate at record speeds.
- benreesman 4y agoI had no idea that people were quite so religious about this sort of thing. It’s pretty clear at this point that testing is one of the most valuable tools in the box for getting sufficiently “correct” software in most domains. But it’s only one tool. Some people would call property checkers like Hypothesis or QuickCheck “testing”, some people wouldn’t. Either way they are awesome. Formal methods are also known to be critical in extreme low-defect settings, and seem to be gaining ground more generally, which is a good thing. Richer and richer type systems are going mainstream with like Rust and other things heavily influenced by Haskell and Idris et al. And then there’s good old: “shipping is a feature, and sometimes a more important feature than a low defect count”. This is also true in some settings. jwz talk very compellingly about this. I think it’s fine to be religious about certain kinds of correctness-preserving, defect-preventing processes in domains that call for an extreme posture on defects. Maybe you work on avionics software or something. But in general? This “Minimal test case! Red light! Green light! Cast out the unbelievers!” is woo-woo stuff. I had no idea people took this shit seriously.
- GuB-42 4y agoI never really understood how TDD can make software better, except for one thing: it forces people to write tests. But that's just a discipline thing: tests are boring and development is fun, you have to deserve your fun by doing the boring part first. It also makes cutting corners more difficult, because it is possible to have (sort of) working software without testing, but you can't have working software if the only thing you have are failing tests (the important first step in TDD). Most TDD people probably thing of that as a positive, I don't. Sometimes, cutting corners is the right thing to do, sometimes, you actually need to write the code to see if it is viable, and if it is not, well, you wasted both the tests and the code, not just the code. But I don't think it is the only problem with TDD. The main problem, I think, is right there in the name "test driven". With a few exceptions, tests shouldn't drive development, the user needs should. Test driven development essentially means: write tests based on the users need, and then write code based on the tests. It means that if your tests are wrong and your code passes the tests, the code will be wrong, 100% chance, and you won't notice because by focusing on the tests, you lost track of the user needs. It is an extra level of indirection, and things get lost in translation. Another issue I have noticed personally: it can make you write code no one understands, not even yourself. For example, your function is supposed to returned a number, but after testing, you notice that are always off by +1, the solution: easy, subtract 1 to the final value. Why? dunno, it passes the tests, it may even work, but no one understands, and it may bite you later. Should I work like that? Of course not, but this is a behavior that is encouraged by the rapid feedback loop that TDD permits. I speak from experience, I wrote some of my worst code using that method. If you want an analogy of why I am not a fan of TDD: if you are a teacher and give your students the test answers before you start your lesson, most will probably just study the test and not the lesson, and as a consequence they will most likely end up with good grades but poor understanding of the subject.
- sirsinsalot 4y agoThere's a lot of conflating unit-testing/TDD and QA here. Yes, when you start writing code, it may not be well defined, or you (the coder) may not understand the requirement as intended. That's OK. Write your test. Make clear your assumptions and write the code against that. Now your code is easier to refactor and acts as living documentation of how you understood the requirement. It also acts to help other engineers not break your code when they "improve" it. If QA, the client or God himself decides the code needs to change later, for whatever reason, well that's OK too.
- wvenable 4y ago> Now your code is easier to refactor Unless you need to change the design of the interface in any way -- then it's harder. Tests lock a particular interface in place -- which is great if you have a well defined interface. But if you're trying to figure out that interface then you've prematurely locked yourself in.
- sirsinsalot 4y agoTrue, easier to refactor within the interface. I'd argue if your interface changes and it's a chore to refactor or rewrite the test then there's other tech debt issues going on.
- wvenable 4y agoIn my opinion, a lot tech debt comes from not changing the interfaces when they need to be changed. Tests fix your design so if your design is broken you're going to live with that. But when I'm developing something new, I will frequently change the interface until I get something to be what I want to it be.
- rodrigosetti 4y agoTDD doesn’t work for the really interesting problems: you can’t achieve a deep creative solution through small mechanical improvements
- pdimitar 4y agoI don't have complicated feelings towards TDD at all. It has a good idea but as many others have said, you need a pretty well spec'ed software beforehand for it to work. When you code a certain piece you might change it, top to bottom, several times -- we aren't perfectly thinking machines and we need to iterate. Having to re-prototype tests every time hurts productivity not only in terms of hours -- an obstacle that can be overcame in a positive environment and is rarely a true problem. It hurts in terms of it demotivating you and you losing the creative energy you wanted to devote to solving the problem. The "it depends" thing will always be true. When you gather enough experience you will intuitively know the right approach to prototyping + testing an idea. TDD is but one tool in a huge toolbox. Don't become religious over it. I liked part of Kent Beck's writings back in the day but I am inclined to agree with other posters that he mostly wrote books to sell courses. I mean the book had good content, don't get me wrong, but they also didn't teach you much except "don't do waterfall". Martin Fowler also wrote some gems, especially "Refactoring", but in the end he too just tried to enrich your toolbox -- for which I am grateful. Ultimately, do just that: enrich your toolbox. Don't over-fixate on one solution. There is not one universal solution, at least we don't know it yet. Probably one day a mix of mathematical notation + a programming language will converge into one and we won't ever need another notation again but sadly none of us will live to see it.
- jboy55 4y agoI feel like I've never seen a project that I liked, where I surprisingly discovered it was developed using TDD. I have seen only a handful of projects, show as examples of TDD, that actually were projects I liked. Its a variation of the "don't worry they'll tell you" joke. How do you know a project was TDD?
- danieltanfh95 4y agoTrouble with TDD is that it doesn't fit product development. 1. TDD isn't faster than simply writing test cases down, and executing them manually, especially when UI is involved. 2. TDD quadruples the amount of work needed for any given change. 3. TDD is the opposite of agile where you try to ship some product to the user ASAP to get feedback before spending time to refactor and clear technical debt. Write tests only for features that are confirmed so you don't spend time and effort on stuff people don't want. 4. Similar point as 1, but you need to evaluate if making something easy to test is worth the time savings than just running the test manually.
- davesque 4y agoIt seems to me that I began hearing a lot about TDD during an era of abundant web development work in the early 2010s. I think that kind of work lends itself well to TDD since there are a lot of well established design principles and conventions in that space. But it doesn't work as well in other more general software design contexts that are more open ended.
- avl999 4y agoWhat is frustrating is TDD evangelists insisting everyone do purist TDD in their regular development (like the guy being quoted in this article). You set your standards as a team of what you will consider acceptable tests and as long as the dev submitting the PR meets that standard why does it matter if they did TDD or not? TDD is a means to end, it's not a religion. As long as you write tests that meet the standard it doesn't matter when you write those tests. The level of micromanaging that TDD evangelists seem to want in people's workflows is infuriating. It's literally cultish. Edit: I realize this came across more negative and abrasive than I intended. I think TDD has some good parts (primarily around gamification of writing tests and giving a serotonin hit whenever a test goes from red to green). I practice TDD around 50% of the time when appropriate, but most people who have worked in the industry that TDD as sold by purists is impractical and adds negative value.
- fbrncci 4y agoWorking on API, Services and a lot of automation. At some point I got really into the habbit of TDD. Now I just can't go without it anymore. When I am thinking of a feature, I am always thinking of the test first. It has gotten to the point where it feels like I am walking around naked when I write test-less code/features. It's not just that I have gotten used to it, because whenever I coded myself into a corner, without tests, it seemed like the answer was having tests first. At least, it would have caught a lot of the issues I would have run into later. https://www.youtube.com/watch?v=iwUR0kOVNs8 https://www.youtube.com/watch?v=iwUR0kOVNs8
- erdos4d 4y agoI think TDD is just busywork in another form. Managers seem to like to keep people busy, often just to watch them work and feel power or something from it. They might have a really good dev on the team who can smash everything in front of them super quickly and they can't keep them busy enough to get their power trip on, so they add a boat anchor and tell the dev to drag that around while they work. Instant slowdown in productivity, dev takes 3X as long, manager is loving it. I think that's also why you find this junk in megacorps where there is little actual work and everyone is politicking all day. Lotta power trippers in those companies.
- kjgkjhfkjf 4y agoI generally expect to see decent tests along with code in the same PR. I don't care whether the tests were written before or after the code.
- dangarbri3 4y agoThe method that works best for me is from code complete. McConnell argues (correctly, IMO) that tests are a technique, and writing tests means more code to maintain and debug. Tests can be wrong, and if the test is wrong, the code will also be wrong. Thus, a bug is introduced. He advocates first making sure you have good software design, i.e. components are laid out, how they're going to interact with each other is well defined. So before writing any code at all, make sure you have a documented design that works conceptually. Define the systems that make up your software, the classes that make up the systems, and then the functions they'll use to talk to each other. Once it works on paper, start coding. If the design is good, the code should be so brain dead simple to write that a monkey could write it. I find doing this I do end up with long call stacks, because each module will do something, then pass the data on like an assembly line. In each step my functions are super short and I don't find it worth writing a test for 3 lines of code that I can tell is correct at a glance. For those few meaty functions that do more heavy logic, I will write tests for, though.
- osigurdson 4y agoOne thing that I have observed is, there is often a problem dependent sweet spot for the integration level of a test suite. Sometimes that is literally testing the behaviors of every method while other times it can be end-to-end testing or somewhere in-between. The challenge is, it can take a great deal of thought to arrive at the appropriate inflection points. One approach I take is to try to think about what suite of tests would make it easier for a developer who is new to the code base to be productive in it. They should feel that the test suite is helping them, not holding them back.
- matchagaucho 4y agoMy reluctance to do pure "red-green-refactor" is more a side-effect of the IDE than the testing philosophy. Maybe it's an OCD thing, but I don't like seeing compiler errors of unimplemented pseudo-code and mock placeholders. It breaks my flow. But 2 files open at all times, writing tests as the main class is being developed? And no compiler errors? Love it.
- t43562 4y agoIs dogma really useful? No matter how sensible some strategy is, can we afford to treat it as an absolute truth? I get the feeling that we are all inclined to think that we have the entire story of development in our own personal heads and can therefore lay down laws. ...and yet most of these disciplines need everyone's co-operation and one can feel that if you don't treat it as dogma then you're never going to make everyone "comply"... I think the fact that TDD (and other popularly debated methodologies) haven't taken over just by being obviously easier and better is a sign that they aren't really suitable for being made into dogmas. They're tools and we should have the choice like any workman to choose them or not.
- kazinator 4y agoI don't understand where/how in TDD you are allowed to switch from concrete "base case" tests to tests which probe the inductive hypothesis. It seems that TDD can forever evade actually solving a problem in its general form, always just extending the number of concrete cases that work. For instance, a function to measure the length of a string first works only for the case len("") == 0; the result is wrong for all else. TDD allows this to be extended into "working" in idiotic steps like len("a") == 1, but len("b") returns 0, and so on. Also, how, in TDD, can we write a test which says "for any input not handled by the tests developed so far, I want an exception". That is to say, when I write the first test len("") == 0 and get it to pass, I don't want len("a") to return 0; I want it to throw. I could write a test for that: throws(len("a")), and it would initially fail. But I want the behavior to be entirely general, and I don't want to maintain the test when len("a") changes to returning 1. These problems make TDD just look like a way to get useful work out of complete morons, in problem areas involving calculating functions that have finite domains that can be exhaustively tested. As soon as you write a code that is more general: which makes more than the new test case to pass, you're leaving TDD. For instance, the test case wants len("a") == 1, but you write code such that len("b") == 1 would also pass, and len("abc") == 3 would also pass and so on. You now have a lot of useful and good behavior that is not tested. You've not had a len("abc") == 3 which went from red to green. Once other code starts relying on len being a reliable length function, you must have left TDD behind. Code is calling len("foo.txt"), which has not been tested! How realistic is to prevent that? At some point, a supposedly TDD-developed program must handle real-world inputs, and they could not all have been tested, because that's the reality. Only simple functions with small finite input spaces can be exhaustively tested. TDD must necessarily allow a lack of testing to creep in, and the rules for that, if any, are ad hoc.
- andy_ppp 4y agoMe too but let’s play devils advocate here. 1) you likely aren’t going to get the job without some absurd degree of unit testing 2) most of your code should be pure functions making them trivial to unit test 3) writing pure functions and making your code testable makes your system less coupled which is a good thing 4) designing the tests is designing the software which is often helpful That’s it I don’t have a fifth point. Actually I do, writing software is a form of art and it cannot be summed up as simply as unit testing everything always bad or always good. There might be somethings like converting an engine performance simulation to Golang from Excel that might be fantastic to unit test the shit out of, testing if onPress works on your button component is basically pointless.
- throwaway1777 4y agoI don’t. Never once seen TDD help more than it was a time sink. On the other hand writing lots of tests is great, but no need for TDD.
- nestorD 4y agoThere are quantitative studies showing that TDD has little to no impact development time or code quality[0]. What has been found, however, is that writing code in short increments helps a lot (something that can be caused by using TDD). For more information on studies covering the topic (and much more), I highly recommend watching Greg Wilson's Software Engineering's Greatest Hits[1]. [0]: https://neverworkintheory.org/2016/10/05/test-driven-development.html https://neverworkintheory.org/2016/10/05/test-driven-develop... [1]: https://youtu.be/HrVtA-ue-x0?t=448 https://youtu.be/HrVtA-ue-x0?t=448
- silentsea90 4y agoIt's odd how much time software engineers will spend on discussing the same old boring stuff like TDD. There are a thousand flowers blooming in cryptography, ML/AI, cryptocurrencies etc. Yet here we are with yet another rehash of the same discussion
- he0001 4y agoOne thing with TDD is that the code you are writing, you know, is testable. It’s also easy testable code, as it’s already written in such way. Code which isn’t written with TDD may be testable but more often than not it’s hard to test it. And code that’s hard to test will not be tested. And that’s a slippery slope.
- Graffur 4y agoI laugh every time I see someone trying to push TDD as the one way to write software. If it is useful to you.. then go ahead. Don't try push it on everyone.
- CornCobs 4y agoSlightly off topic, but I find the author's attempt to use an iterative method (TDD) to derive a recursive algorithm (quicksort) somewhat comical
- Tainnor 4y agoI think a lot of distinct, but interrelated topics are being brought up here: * Using tests as a (or even the primary) design tool (strong TDD) * Test-first development (weak TDD) * Integration vs. unit testing * What is a unit test? * Should one use mocks and if so, when and how? I think each of these topics merits a separate discussion and you can be e.g. in favour of at least weak TDD while maintaining that unit tests have little value, or you can be in favour of unit tests but disagree that "unit test" means "unit = class/method/function". You can have differing opinions on the value of mocks even if you subscribe to strong TDD (that's essentially the classicist vs. mockist divide in the TDD scene - for example, Bob Martin is more skeptical of mocking than, say, the "Growing Object-Oriented Software, Guided by Tests" crowd is). IMHO, the biggest problem with testing is that most developers are not very good at it. I routinely see tests that are so complicated that it becomes very hard to understand, let alone debug them. In my experience, a lot of people also skip tests when reviewing code. Well-written tests make a code base a joy to work with. Bad tests make everything painful. I don't know how to fix this, but we should pay more attention to it. If we had better tests, it would be easier to argue about the merits of TDD, unit testing, mocking etc. With badly written tests, everything devolves into a "why even test [this specific thing]?" kind of discussion.
- alfonsodev 4y agoI think TDD shines in combination with a layered architecture, the combination of both increases “changeability” of the project. Layered architecture and DI makes easy and possible to test any layer. And the test become a live documentation of how to use the code you have written. Refactoring becomes then easy although sometimes tedious, but provides a degree of confidence that your change works with all posible ways to use the code. Its also healthy to break the rules if time pressure, but keeping a registry of technical debt, helps keeping the morale up. There is nothing more demoralizing that working on an environment where you can’t estimate because who knows what will be broken, it’s hard to make improvements because everything is entangled, and there is no time to invest in a rewrite. This usually ends up with very talent people quitting if they are unable to fix it.
- bbarn 4y agoTDD is another tool in the toolbox. It has it's place, and combined with good tooling, can make for a great development experience. I use it mostly when adding features to an existing code base. In C#, with modern tooling like Visual Studio, Rider, or ReSharper, you can use your test as a base to start scaffolding methods out with auto generated code, and that can end up being a time saver. For a brand new product, I'm almost never using TDD. I'm building out a solution in the pattern I want, getting some minimal feature or features up, and then I write tests appropriate to that pattern. Later on I might use TDD to keep working on it, but it can be a burden at the start of projects.
- lakomen 4y agoI don't want to write tests, why? Because most of them are like x = 1; if x != 1 panic(); If you don't trust the language, why do you use it? But then there are tests that make sense but are hard to write. And then there are tests that require infrastucture. I don't write tests for every little thing. But I do write them if I actually do want to test the functionality of what I just wrote. But stuff like s := new (Service) if s == nil { t.Fail() } is completely unnecessary
- majikandy 4y agoSome people do tests, some people do development, and some people do test driven development. If you are picking up some code to work on, the nicest to work with is the one that was done with TDD.
- dingosity 4y agoMeh. OP sets of a strawman that rarely exists outside Reddit message boards. TDD is the wind, it cannot be captured by your net.
- dingosity 4y agoWhich is to say... It sounds like the OP inhabits an environment where design is decidedly un-ad hoc (the reference to TLA+ is a dead give-away.) Not everyone lives there. Not everyone approaches design the same way. People dissing the OP should chill. The OP should probably also chill. If someone tells you "you're doing it wrong," just ignore them. People who know what they're doing won't say "you're doing it wrong," they'll say... "Hey, that's different than how we initially thought this methodology would be used... you must have a different environment from what we're used to. Let's dig into this a bit more."