Live data from Hacker News

TDD did not live up to expectations

blogs.msdn.microsoft.com

141–150 of 450 posts

Re: TDD did not live up to expectations

#141
post #8

In the earlier days of the ruby community, I feel TDD was seen as gospel. And if you dared say that TDD wasn't the way (which I always felt), you'd feel like you were ostracized (update: just rewording to say, you'd worry that it would hurt you in a job search, not that people were mean to you). So I never spoke up. I feel like I was in the TDD-bad closet. I absolutely think _tests_ are useful, but have never found a…

Like the author in the original article, I used to be all about TDD. Now, I like to tell people that "I'm apostate in the ways of TDD". I specifically use the language of religion because I think strict adherence to TDD is itself a religion. I somewhat disagree with the statement he makes, "we know that most developers do not have great design/refactoring skills". I've certainly worked at places that all but ordered…

Interesting that you mention REPLs. I wonder if the often maligned Python docstring concept has/had more merit than it is currently given credit for.

Re: TDD did not live up to expectations

#142

Any programming language suitable for business application development is going to have static analysis tools that can reveal your percentage of test coverage. As long as 95% (or whatever) of your logical branches are covered by tests, I don't really care whether you wrote the tests beforehand or after the fact. However, TDD being hard is not a justification for not writing the test coverage at some point in the dev…

> As long as 95% (or whatever) of your logical branches are covered by tests, I don't really care whether you wrote the tests beforehand or after the fact. Do you care that those tests reflect the business goal or just the implementation? 'Cause TDD is way, way more likely to do the former than test-last development.

What are you talking about? TDD generally deals with unit testing. Which by definition is more fine-grained than end-to-end integration tests against non-mock dependencies.

All of which is unrelated to UAT. Where you show the alpha to the business, and it's only after seeing it live for the first time that they start to get on the same page about what their business goals were to begin with.

Re: TDD did not live up to expectations

#143
post #33

Earlier quoted context omitted.

It doesn't necessarily lead you there at all. "Dependency injection" is a fancy phrase for "pass stuff a function needs into the function", only it does so by adding state to objects where that state probably shouldn't exist. You don't have to faff around with IoC or MVVM to properly isolate dependencies; indeed, it's the core idea behind something like Gary Bernhardt's "Functional Core, Imperative Shell" (which, if…

Sometimes state is an actual desirable thing and strategy can be a dependency. Heck, higher order functions (functions taking functions as argument) are dependency injection personified.

State is a desirable thing in the code that wraps your business logic, for sure! Otherwise you're not actually doing anything. That's distinct from state in your business logic, though.

Re: TDD did not live up to expectations

#144

Earlier quoted context omitted.

Playing devil's advocate here: I'd say that algorithm design (Which is what a sudoku solver is) is a bad fit for TDD. However, I'd argue that most problems in commercial coding are of a more engineering/architectural type of nature. Here, outside-in TDD has it's place. Outside-in TDD can help you tackle problems that seem enormous, and slowly but steadily break them into smaller components.

I find TDD useless as a way of poking at problems I don't actually know how to solve (as Jeffries found with Sudoku), in the way and slowing down when writing large new systems, and excellent when bug-fixing maintenance. Test Driven Debugging!

In a similar vein, I've found it super-helpful when refactoring. It gives you extra confidence that your refactoring isn't gradually breaking important stuff.

Re: TDD did not live up to expectations

#145
The tests get in the way. Because my design does not have low coupling, I end up with tests that also do not have low coupling.

Not to be smug, but I feel like this is a rookie mistake I learned 10 years ago immediately after starting TDD.

The slogan I use in my head is that testing calcifies interfaces. Once you have a test against an interface, it's hard to change it. If you find yourself changing tests and code AT THE SAME TIME, e.g. while refactoring, then your tests become less useful, and are just slowing you down.

Instead, you want to test against stable interfaces -- ones you did NOT create. That could be HTTP/WSGI/Rack for web services, or stdin/stdout/argv for command line tools.

Unit test frameworks and in particular mocking frameworks can lead you into this trap. I've never used a mocking library -- they are the worst.

There are pretty straightforward solutions to this problem. If I want to be fancy then I will say I write "bespoke test frameworks", but all this means is: write some simple Python or shell scripts to test your code from a coarse-grained level. Your tests can often be in a different langauge than your code.

The last two posts on my blog are about this:

"How I Use Tests": http://www.oilshell.org/blog/2017/06/22.html

"How I Plan to Use Tests: Transforming OSH": http://www.oilshell.org/blog/2017/06/24.html -- I want to change the LANGUAGE my code is written in, but preserve the tests, and use them as a guide.

And definitely these kinds of tests work better for data manipulation rather than heavily stateful code. But the point is that testing teaches you good design, and good design is to separate your data manipulation from your program state as much as possible. State is hard, and logic is easy (if you have isolated it and tested it.)

Summary: I use TDD, it absolutely works. But I use more coarse-grained tests against STABLE INTERFACES I didn't create.

Re: TDD did not live up to expectations

#146

Earlier quoted context omitted.

> As long as 95% (or whatever) of your logical branches are covered by tests, I don't really care whether you wrote the tests beforehand or after the fact. Do you care that those tests reflect the business goal or just the implementation? 'Cause TDD is way, way more likely to do the former than test-last development.

What are you talking about? TDD generally deals with unit testing. Which by definition is more fine-grained than end-to-end integration tests against non-mock dependencies. All of which is unrelated to UAT. Where you show the alpha to the business, and it's only after seeing it live for the first time that they start to get on the same page about what their business goals were to begin with.

TDD totally deals with unit testing. Are your units not reflective of business goals? Mine tend very strongly to be, perhaps because I extract IO and other state crap out into the less functional part of my program (and I don't really unit test that).

Re: TDD did not live up to expectations

#147

Earlier quoted context omitted.

I was quite comfortable with refactoring for a very long time before I started doing tests, and I think that colors my approach to the problem space. I write code until it misbehaves the first time, and then I start writing tests, comfortable in the knowledge that in another half hour this code will be unit testable and look better than what everyone else is turning in, and that I'll spend 20 minutes at the end clean…

> They do a LOT of transcription instead of copy and paste Transcription makes you think about what you're typing in and avoids the whole class of errors that arise from copy-and-paste. Transcribing code rather than pasting it is not a red flag.

Transcription can lead to the same conditional in two blocks of similar code instead of the two intended. It can lead to fencepost errors due to changing or inverting an inequality. And in some languages it can lead to code that looks up data that doesn't exist (misspell a property name outside the happy path).

The big problem is that you're chewing up short term memory slots that used to hold the next thing you planned to do. For me I generally use only a couple slots for a single refactor because it's all muscle memory.

Additionally, it just takes a hell of a long time, which means you go from virtually no chance of interruption to a measurable one.

When I was young I had an exceptional short term memory and could pull off some crazy big refactor without introducing errors. But now it's normal at best, and also I rely far less on those sorts of feats, in part because I put a higher value on commit history readability.

Re: TDD did not live up to expectations

#148

No article about TDD, particularly one that shouts out to the respected Ron Jeffries http://ronjeffries.com/ , is complete without mentioning the TDD Sudoku Fiasco :) Ravi has a nice summary: http://ravimohan.blogspot.se/2007/04/learning-from-sudoku-so... Peter Norvig's old-fashioned approach is excellent counterbalance: http://norvig.com/sudoku.html

Well, to me it seems that if you stretch the idea of separation of concerns, you should separate the process finding out what you should do, from the process of how you should do it right.

Re: TDD did not live up to expectations

#150

Earlier quoted context omitted.

I'd agree with this characterization. I started my career in Boston - actually, one of the first companies I interned at did high-assurance systems for avionics, financials, and medical devices. However, look at the size of the West Coast tech industry vs. the size of tech firms in New England or the Midwest. That's what I mean by an economic argument. I got paid 5x more at Google than I did in Boston, and I was empl…

Unless the causal relationship is the other direction. That is, everyone always assumes in our industry that the chaos allows this volume of people to be employed. But usually large number of people leads to chaos all by itself. Maybe we have it backward. I know I've worked on a lot of projects that got version one out quick and could never get version 3 out the door. It gets old after a while. Why do I want to spend…

I actually don't think either of these factors is causal.

Rather, I think money is the primary causal agent. The top 5 most valuable companies on earth right now are all West Coast tech companies, and they got that way by building software systems that are an integral part of the lives of billions of people. The fact that software is an integral part of those activities is a function of it being a million+ times more efficient than humans; any company could've filled that need, but AppAmaGooBookSoft was the one who actually did it first.

Money (and specifically, rapid growth in customers & revenues) causes chaos, and money causes lots of people to be employed, and money lets you pay them a lot. The specific engineering practices - at this stage in the industry - are a sideshow. They're important to practitioners, but not important to customers, as long as the software basically works. And the reason TDD has fallen short is because you can build software that "basically works" without it, so it's just overhead until you need software that "really needs to work in all situations".

Post reply on HN