5

If you haven't heard of Kent Beck's TCR, it can be summarized with this: any time your tests go green, you commit; anytime your tests go red, you git reset --hard.

This post is about how to practice TCR correctly. It ISN'T about the merits or deficiencies of TCR (although that would be an interesting topic for another post).

In TDD, you start with failing tests, make them pass, and then refactor. I know TCR != TDD, but I'm going to use TDD terminology for my question:

I can't tell if TCR is just "green, refactor" or if it is "red, green, refactor." It's not explicitly stated in the article.

Many times I've experienced situations where my test started green because I wrote the test wrong, that's why I always like to start with a red test -- to give me confidence I'm testing what I really think I am.

TCR seems fascinating and I'd like to try it, but I want to make sure I'm actually trying it, not some bastardization I unintentionally created. So when practicing TCR, should I start with a failing test first?

11
  • 1
    @DocBrown: I very much doubt that TCR is even a thing. It's a wacky idea that someone thought to try, over the dubious principle of "symmetry." Ergo, the idea that there's some sort of "correctness" that could be applied to it is patently ludicrous. That said, I didn't downvote, and I do agree with your prior assertion that bad ideas shouldn't be downvoted, only bad questions. Aug 30, 2021 at 14:31
  • 1
    @RobertHarvey It's a wacky idea that someone thought to try, over the dubious principle of "symmetry." Ergo, the idea that there's some sort of "correctness" that could be applied to it is patently ludicrous. Tomorrow, I could invent a new card game with a unique set of rules. Even if I'm the only one that knows about it, there is still a "correct" and "incorrect" way of playing it. Aug 30, 2021 at 14:35
  • No, there is a "correct" and "incorrect" way of applying the rules (assuming the rules are clear enough to be interpreted unambiguously), which is not at all the same thing. "Correctness" is a term that has a very specific meaning in computer science; it should not be abused to mean other things. Aug 30, 2021 at 14:36
  • @RobertHarvey If it makes a difference, I didn't mean correctness as a computer science term. I didn't realize you were using it that way either. Aug 30, 2021 at 14:43
  • Fair enough. But I've seen too many people ask "What is the right way to do this," as if there could actually be an answer to such a question without more context. I'm not accusing you of this, but usually the asker has failed to do a cost/benefit analysis to see if what they're asking really makes any sense from the perspective of their own project's specific requirements. Aug 30, 2021 at 14:48

3 Answers 3

4

Kent Beck actually answers this question himself if you watch a video of him teaching TCR. The answer is yes. You do skip "red" when you are practicing TCR.

I also found this article that directly states you skip the "red" of red, green, refactor when you practice TCR. And this TCR tool can only be used under that assumption.

I think that article is clear and concise. Here are two useful pictures from it:

TDD

enter image description here

TCR

enter image description here

2
  • 5
    Neither Beck nor Wake mention it, but if you wanted to verify that the tests are measuring what they are supposed to, then you would inject the fault you expect the tests to detect. TCR, and the failed tests rolls the code back, removing the fault. Of course, if the test doesn't detect the fault, you now have a commit with a known fault (and two commits with a broken test). Aug 29, 2021 at 15:14
  • @VoiceOfUnreason that's very clever. Aug 29, 2021 at 19:01
1

The following is just a few thoughts from me, no facts or "the truth", so take what you think is valuable, and ignore the rest. :-)

When i encounter a new "methodology" my first question is "what problem does it try to tackle?".

While TDD focuses on commiting stable code, most people just remember the "red, green, refactor" rule. And yes thats kind of the heart of TDD. But quite a lot developers i encounter have big problems to make the cycle very small. That means to slice the increments into very small chunks.
As a result quite often they write a test, write productive code, the test still fails, the code is changed, and changed and changed, until the test is finally green.
That makes it very likely, that the resulting code contains elements that are not necessary, because they were left from a previous try. And now we can only hope that in the refactoring phase, those elements will be eliminated. As a result, the first refactoring phase has to focus on simple cleanups, instead of optimizing the design. And, quite often, after the simple cleanup, some devs think "i have done the refactoring, i am finished".

With not "allowing" productive code which results in a red test, this issue is kind of tackled. Now the procedure looks like this:

  • My code is in a green state
  • I am writing a new test (which may be faulty) => should result in a red flag
  • I am writing production code (which also may be faulty)
  • i run the tests and at least one fail.
  • I analyze the issue (may be the new test was wrong, the new productive code did not fit the test, or the changes to the productive code broke existing tests)
  • With the new knowledge, i reset my code and try again.
  • Rinse and repeat, until all tests are green.

Personally i WANT in my version of TCR one red test result. After i wrote the test, before i started implementing the productive code. This red flag gives me the safe feeling, that my new test is not implemented with a "will always be green" mistake. So, this "red" i accept. But after i start implementing the productive code, "red" results (mostly, see later), result in a code reset.

When i want to follow this method, i have to learn to make my increments very small. Writing the test and the corresponding productive code for the next increment, may not take longer then just a few minutes. If it takes longer, the "reset" will erase a lot of work.

Following TDD is an API first approach (the API of the productive code that is used by the tests) and enforces deep thoughts about the code design. Following additionally TCR enforces the habit of having very small increments.

But perhaps some last words. TCR is a methodology, and like TDD it is not wise to follow it under all circumstances. If my test fails, because i made a spelling mistake, then i would correct that spelling mistake instead of reverting and just continue. The goal of TCR is to not patch code until it works, because the result will be very likely not be as clean as it could be. That means if my "patch" is extremely small and i can fully oversee it, then i would not reset my code.
Just remember, TCR will result in "having very small increments". And now think about an "exremely small patch"" in a "very small increment". That means we are really talking just about things the size of a spelling mistakes.

EDIT: Kent Beck mentions this methodology in combination with "testing legacy code". That means the productive code already exists and we just now add tests to it.
In that scenario a new test should be green from the beginning. Again, personally i would try to ensure that the test is not faulty (beeing always green), therefore after the test runs green and i have commited the change, i would change the test in a way were it should fail. Please not by adding a "expect(1 === 2)" or something like that, but by changing the expected result slightly, like from expect(result === "Hallo World") to expect(result === "Hallo").

Also Kent Beck uses an automated reverting approach. Whenever a test fails, the code is reverted automatically. This is fine if you ONLY write tests (and do not change the productive code) AND your test is quite small, so that the error can ONLY be a wrong expectation (expecting a different result of the productive code). As soon as something else could be wrong. The test itself or the changed productive code, this approach will instantly delete the chance to analyze the issue. Therefore in those circumstances myself i would NOT use an automated approach.

2
  • Kent Beck mostly mentions this methodology in combination with "testing legacy code". I'm going to need some evidence of that. He doesn't mention legacy code anywhere in his article, and when he is demonstrating the technique on his YouTube channel, he has one video of 11 minutes demonstrating how to use TCR on legacy code. On the other hand, he has 90 minutes of multiple videos demonstrating TCR on greenfield code. Aug 30, 2021 at 14:29
  • Point taken, i did some more searching and also found more text/videos about the greenfield style. The legacy code was just an additional use case. Sorry, my first search was a bit to narrow. I have edited my answer and removed the "mostly".
    – JanRecker
    Aug 30, 2021 at 14:35
0

As I wanted myself to get more disciplined, I found myself with the same limitation of not allowing the 'red' in 'red-green-refactor' with TCR, which makes 'watchers' (which I like) really hard. So tweaked the suggestion a bit while trying to formalize:

On a failure, revert everything except your test files.

Not to self-promote - I wouldn't even recommend using the plugin - but to illustrate how to make it operational with a 'watcher' https://github.com/lenntt/tcr-jest-watch-plugin

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.