News for hackers. Stuff that matters.
Re:When I do TDD and when I don’t by thatswrong0 on Thursday February 17, 2022 @02:38PM (#30377636)
Agree with the reasoning here, so as a result I almost never use TDD: I pretty much always have to spike + iterate in order to come to a reasonable and clean solution for whatever I'm working on.. no matter how much I've tried to spec things out exactly how they should work, it always ends up being different. I'm also just not great at abstract vs. hands on thinking.

On top of this, I've also come to find unit tests to generally require more work and be less useful for identifying regressions than integration tests for the work I do. Maybe this is just a result of the kind of work I do though.

Re:When I do TDD and when I don’t by no_wizard on Thursday February 17, 2022 @03:05PM (#30377967)
I think this highlights that the core of TDD is understated. The core of TDD is encapsulated in the saying Red, Green, Refactor

- Write the Test, they're going to fail cause you have no implementation

- Write the implementation, so that those tests are green

- Refactor to clean up the code, make it real nice

Rinse and repeat as needed, until you've settled on a fully tested solutions. If you do this, you are practicing TDD as its intended. I think the overall message around TDD, how it gets talked about in industry, and how its gotten promoted (or not promoted, I guess?) makes it so confusing. This is the heart of it here, is to rinse and repeat these 3 steps, always starting with writing Tests first, which is to validate that you understand what you're building

What I have found in my decade+ doing this is that most of the time when I run into team members who draw blanks or feel that TDD is a roadblock is that's one way or another they don't have enough information about the requirements of the work involved in what they're doing.

Not sure if this helps anyone or not, this has been my general experience and may not capture every case, though I feel confident enough that this is a shared experience that I hope it brings another way to think about TDD in terms of simplicity.

Re:When I do TDD and when I don’t by thatswrong0 on Thursday February 17, 2022 @03:55PM (#30378539)
> Write the Test, they're going to fail cause you have no implementation

But this is where I falter every time: the test necessarily depends on the implementation. I could write a test for my first pass at a function... but then if I decide I need to actually split that function into two or go for a different approach entirely, then I have to basically scrap that test. And then I've just created a bunch of friction that slows down my development process.. for what gain?

And to your point, yes, it may have to do with the fact that often my requirements are amorphous and I discover them as I go. For example, say a designer wants a specific behavior, but then I realize it doesn't work in an edge case that we will probably hit, and fixing that edge case will take twice as much time. So then I work with them to find a less time consuming compromise -> bam, new implementation, new tests.

Or maybe it's not a user facing behavior, and I realize after 10 hours there's a way simpler way of doing the thing I want. Same thing -> new tests.

Once I've got the basic code layout in a satisfying state, only then do I feel comfortable starting tests and ensuring I most or all of my conditional branches -> success and error cases.

I feel like I'm missing something

Re:When I do TDD and when I don’t by no_wizard on Thursday February 17, 2022 @04:00PM (#30378600)
> I could write a test for my first pass at a function... but then if I decide I need to actually split that function into two or go for a different approach entirely, then I have to basically scrap that test.

Then you're writing a function coupled to the test, not writing logic you can plug into the test to reasonably verify it works as intended.

That's the bit people miss I think. Tests should reflect how the code is consumed, and test for that (inputs and outputs, more or less) not for implementation details. Your test shouldn't care if its 1 function or 7.

Re:When I do TDD and when I don’t by saurik on Thursday February 17, 2022 @04:11PM (#30378731)
But the point was that to know how the function will be consumed before you write it implies you fully specified it ahead of time without the benefit of knowing how--or frankly even if--it will work, which (to me) is backwards.
Re:When I do TDD and when I don’t by nybble41 on Thursday February 17, 2022 @04:39PM (#30379028)
Yes, the point of TDD is to force you to think about what your requirements are—and how you will prove that they have been met—from the users' (and thus the tests') point of view before writing the code.

If you want to take a more exploratory approach and make up the requirements as you go along, fine, but that won't look anything like TDD.

Re:When I do TDD and when I don’t by Decker87 on Friday February 18, 2022 @12:56AM (#30382560)
This is where TDD folds in on itself. It's nominally about iteration, but requires that you know how the inputs and outputs will look up front before iterating.
Re:When I do TDD and when I don’t by nybble41 on Friday February 18, 2022 @10:47AM (#30387207)
TDD is about iterating on the implementation. If you don't know what your inputs and outputs will look like then you're still in the specification phase and not ready to write code.

You can use TDD as part of an iterative specification process as well, but then you need to apply it for each iteration: determine the new specifications, write new tests based on those specifications, and update the code until the tests pass. Then revise your specifications based on feedback and repeat the process.

Re:When I do TDD and when I don’t by michaelpb on Thursday February 17, 2022 @03:53PM (#30378505)
Yeah, I TDD / TFD as much as I can, much simpler. Even just stubbing out a few simple smoke tests that I red/green/refactor saves so much time. For me, I think I spend less time writing code as well, since it forces me to be clear to myself about requirements early on (even if the story/ticket wasn't clear enough), and keeps a "check" on my natural tendency to go down rabbit-holes before properly speccing out non-essential features or tempting optimizations. I ask myself: Does this help me pass the tests and complete the feature? If no, then I need to sit on my hands and not get all code-cowboy trigger-happy :)
Re:When I do TDD and when I don’t by thewarrior on Thursday February 17, 2022 @09:30PM (#30381480)
Okay so I've been programming for many years, work at a well known company and all that. But when it comes to writing tests and designing my code (OO or FP) I still am not sure what the best way to go about it is. There is so much contradictory and sometimes just plain confusing advice.

Mocks vs stubs vs no mocks. Integration vs Unit vs End to End tests. TDD vs no TDD. OOP vs FP.

Grey beards of HN. Where do I learn the best ways to do testing ? I am happy for any kind of pointers. Whether they be books, talks, blog posts or code bases. Anything outside of the usual examples would be doubly welcome.

Re:When I do TDD and when I don’t by jhanschoo on Thursday February 17, 2022 @11:23PM (#30382120)
> But when it comes to writing tests and designing my code (OO or FP) I still am not sure what the best way to go about it is. There is so much contradictory and sometimes just plain confusing advice.

Well, programming is not a monolith. Different high-level requirements demand different standards and processes, even though for many things a standard solution works. A safety-critical product (or just one that can lose lots of money) demands a different process than a toy app.

Re:When I do TDD and when I don’t by eesmith on Thursday February 17, 2022 @05:27PM (#30379542)
I've never liked what's missing under the red-green-refactor TDD description. Perhaps your experience can offer insights?

Consider Martin's primes kata, at http://www.butunclebob.com/ArticleS.UncleBob.ThePrimeFactors... . The final version is:

  public class PrimeFactors {
    public static List<Integer> generate(int n) {
      List<Integer> primes = new ArrayList<Integer>();

      for (int candidate = 2; n > 1; candidate++)
        for (; n%candidate == 0; n/=candidate)
          primes.add(candidate);

      return primes;
    }
  }
In red-green-refector TDD, where do I add tests that are expected to pass?

In this case, boundary analysis says that if the function takes an int, then I should include tests for negative numbers, and tests for large values, like 2^31-1, which is MAXINT and also a Mersenne prime.

(Neither of these are in Martin's tests, which only test 1, 2, 3, 4, 6, 8, and 9.)

When should I add the test for 2^31-1? Your "Write the test" says we should only write tests which will fail because it has no implementation, but in this case we expect it to pass because we have an implementation. Do we not write that test?

Which leads to my issue with the "refactor" step of "red-green-refactor."

Suppose you add that test for MAXINT. It takes about 5 seconds to run because of it does >2.1B modulo tests.

Implicitly, TDD tests are a supposed to be fast. Not 5 seconds per test. Or the spec might explicitly require (say) a 1ms execution time, or you might find that system tests fail because this algorithm is too slow.

There are any number of faster factoring methods, as Eratosthenes well knew, so pick one and implement it.

Is this in the "refactor" step? Technically "Substitute Algorithm" is one of Fowler's refactorings, so yes.

But Fowler's refactoring are meant to make things cleaner and easier to understand. Not whole-sale replacements with additional complexity. In the discussions I've seen, the refactor step in red-green-refactor starts and ends with the same tests.

While a more complicated implementation may have its own set of special cases to consider. (For example, a complex sorting method like Timsort needs more tests than quicksort to cover all the code paths.)

The descriptions of "red, green, refactor" TDD I've seen completely ignore these issues of when to add additional tests you expect to pass, and how to refactor for purposes other than "make it real nice."

I agree that starting with MAXINT would immediately 'validate that you understand what you're building.' But most TDD examples seem to start with the easy cases first, not the hardest. They teach an incremental design approach where experience from the easy cases helps progress towards the final solution. My experience is that approach can lead to an implementation which requires a design methodology more powerful than red-green-refactor to resolve.

Re:When I do TDD and when I don’t by bvirb on Thursday February 17, 2022 @02:50PM (#30377783)
Same here. So much so we've basically just dropped "unit" testing in favor of integration testing. I guess we still call it TDD though.

I was actually surprised what the author was describing was somehow _not_ TDD. I thought it was pretty normal to try some things out, make some decisions, and then return to codifying those decisions in tests.

We do web app development, and 90% of our tests are browser-based integration tests that test whether the given inputs (usually forms) lead to the expected outputs (usually something printed on a web page).

I wonder if this is more natural when you're mostly writing integration tests?

Re:When I do TDD and when I don’t by leemcalilly on Thursday February 17, 2022 @03:55PM (#30378535)
I find my system/integration tests to be the most valuable because those test the behavior of my code, what the end user cares about.

It often helps to start with the design first (even if just a napkin sketch). Once I’ve done that I usually have enough information to write system tests (which also forces me to consider edge cases). Then I can then fill in with unit tests as needed as I write the code to get the system tests for that feature passing.

Re:When I do TDD and when I don’t by jasonswett on Thursday February 17, 2022 @03:37PM (#30378342)
I personally don't see any reason why the type of test matters when doing TDD. As I see it you can do TDD with integration tests just as much as you can do TDD with unit tests. The only difference to me is that the work involved might take on a bit of a different character. But that doesn't make it not TDD to me.
Re:When I do TDD and when I don’t by pydry on Thursday February 17, 2022 @03:39PM (#30378357)
I've found TDD can work pretty well with integration tests. Often better.

I dont really get why the practise is so intrinsically linked to the practise of writing unit tests.

Increasingly I'm starting to believe unit tests are a scam, but TDD is going to stick around in one form of another forever.

Re:When I do TDD and when I don’t by markmaglana on Saturday February 19, 2022 @04:18AM (#30395633)
JB Rainsberger would like a word with you :-)

https://blog.thecodewhisperer.com/permalink/integrated-tests...

Re:When I do TDD and when I don’t by commandlinefan on Thursday February 17, 2022 @04:17PM (#30378804)
> less useful for identifying regressions

I've observed the same, but having the ability to run any given function in isolation is huge for diagnosing problems. Does this function respond correctly to the correct input? Yes? Ok, that's not where the problem is. Next.