TCR was recently introduced by Kent Beck as a new programming technique. TCR is currently being traded as a successor to Test Driven Development (TDD). This article describes how TCR was developed and what the difference is between TCR and TDD. The advantages and disadvantages of both techniques are compared and own ideas are discussed.
Preliminary Remarks on the English Version
This blog is addressed primarily to a German-speaking audience. The blog post „Was ist TCR?“ („What is TCR?“) was also very often clicked from countries that are not German-speaking. That’s why I make an exception and offer an English translation. Since I am a German native speaker, it is likely that the translation is not perfect.
History of Test Driven Development
is a legendary software pioneer. He is one of the authors and first signatories of the Agile Software Development Manifesto. He is the founder of Extreme Programming (XP) and a rediscoverer of Test Driven Development (TDD).
Beck once read the following in an ancient book about programming:
„Tape“ here does not mean magnetic tapes. These are the tapes that were used to send the output to a teleprinter as a printer.
As an assert() method, the two perforated strips were probably placed on top of each other and held against the light to be checked.
Kent Beck wrote the first xUnit framework in Smalltalk and is considered to be the founder of the modern TDD.
History of Test && Commit || Revert
Now he has discovered a whole new workflow. He calls it TCR and many believe the technique will soon replace TDD. Again the spark came from the outside. Kent Beck had just introduced the programming technique „test && commit“. Here the code is checked in immediately each time after the tests have been successfully executed. The programmer „Oddmund Strømmer“ had the criticism that for reasons of symmetry in failing tests the code had to be removed again (revert), i.e. – „test && commit || revert“. Beck hated this idea, but he was obsessed with trying it out. That’s how TCR came into existence.
So the idea of TCR is that the changes are committed as soon as a new test is green. However, if the test fails, the code is restored to its original state. On September 28, 2018 the article „test && commit || revert“ was published. Thus introduced the new programming technique officially for the first time.
Of course, the idea of deleting code that has just been written is absurd. But for me it’s also absurd to check in a tiny piece of code every time. How do such ideas emerge?
To answer that question, you have to do a little more research.
Birth of a New Idea
During the time on Facebook, which lasted until February 2018, Beck began to think about how 100,000 developers could work simultaneously on the same system. Facebook’s processes were very complex and resulted in unpredictable delays. After leaving Facebook, he returned to Smalltalk. In a project about the syntax tree for the bytecode compiler, he realized that tree transformations were very closely related to scaling issues.
Conways Game of Life inspired him to think that information could spread in a similar way. What if every pixel was a programmer and every change to a pixel was a change to a program? How are these state changes related to the transformations of a syntax tree?
Some years ago Beck worked with Thiago Hirai on the code editor Prune. Surprisingly, it was found that about 100 operations are sufficient to cover all common modification variants that are syntactically correct. A few transformations should therefore be sufficient to keep a program in a „correct“ state. Merge conflicts, such as renaming the same variables to different names, are thus easy to recognize.
This is how the idea of Limbo was born. Limbo is also associated in the English language with keeping something floating. Limbo is live, shared programming in which the focus of the following two principles is constantly kept in balance:
- Everyone works on the same executable program, which is represented by a syntax tree.
- No one is allowed to cause problems for others (including the users).
Tiny changes to the code base spread permanently along the syntax tree, as in Conway’s Game of Life and like living organisms.
Many questions are still open and there is still no tool that couples directly to the syntax tree. Changes would then only be possible as tree conversions. Limbo is currently still a thought experiment – a learning exercise.
To get practical experience, Beck encouraged his fans to experiment with GIT and source editors. He just wanted to see what Limbo feels like and what incentives it creates. He created Limbo on the cheap tour. He describes the use of GIT in the article „Limbo on the Cheap“ with the pun „(ab)using GIT
Rather than have tree transformations zipping around modifying the program, we chose to use Git. Both pairs cloned the same remote repository. Then we ran the following shell script:
git pull –rebase;
How would we make sure we didn’t break each others’ code? We wouldn’t propagate changes unless all the tests pass. After every change, we ran this script:
test && git commit -am working
The “test” script builds the system, runs the tests, and only returns 0 if all the tests pass. (We actually reverted if the tests failed, but that is a tale for a different article.)
Kent Beck – Limbo on the Cheap
TCR vs. TDD
That brings me back to the beginning of the story. The idea of the programmer Oddmund Strømmer led to the GIT command being changed to „test && commit || revert“. That’s how TCR was born. If a test is not successful, the just written code will be deleted. Thus all tests remain permanently green. By the way, Beck thinks that activating the undo function is cheating.
For TDD a test is always written first and then productive code. The first test must always be a failing test. Syntax errors are also included. For example, a function that does not yet exist is already used as an assert parameter. This state is called „red“. The next step is to implement exactly enough productive code for the test to run successfully. It is therefore a change of state to „green“. If necessary, a code „refactor“ for clean code follows. The rule is: „First make it work then make it right“. Such a cycle should only last a few minutes.
A typical beginner’s misconception with TDD is that the tests are formulated in such a way that a large amount of productive code has to be written to fulfill them. You do too many steps at once. This goes beyond the recommended time frame for a cycle. But even worse, the intermediate steps are untested. If the resulting productive code does not turn green unexpectedly during testing, you don’t know which intermediate step caused it. You have to work with the debugger again. The use of a debugger is always a symptom of not having understood the TDD technique properly.
Unlike TDD, TCR forces small steps. Who wants to risk the loss of a large amount of code? As an educational approach this is very welcome.
TDD has no instructions or recommendations for checking in code. A software developer who checks in code with syntax errors is considered as a codebreaker. A codebreaker causes problems for others in the team. This is especially the case, if the codebreaker checks in code shortly before the end of the workday, and is then no longer available. In order to be able to continue working, a solution must be found very quickly. This is often solved with a revert. At TDD you are already a codebreaker if any test becomes red. Therefore a local build run should always be executed before checking in, which recompiles all test suites and executes all tests.
This usually takes as long as there is time to drink a cup of coffee.
Typically, merging code (merging) leads to conflicts that lead to errors or cannot be resolved. The larger the amount of code and the less often the main branch is checked in, the larger and more problematic these conflicts become. With TCR, this problem can practically no longer occur. I cannot accept the excuse that it takes too long to run all the tests. Only the tests that are affected by the code changes have to be executed. Otherwise a nightly build is adequate.
TDD Is Dead, Long Live TCR
Is TCR now the new TDD? Should you learn TDD at all, or should you switch to TCR immediately? In a French blog I already read the headline „TDD est mort longue vie TCR?“. (Google translation: „TDD is dead, long life TCR?“ sic!).
No, TCR, unlike TDD, will not have any practical relevance. At least not in the currently practiced form. TCR is only an experiment for the future Limbo. The misuse of GIT causes many practical problems. GIT was never designed to check in code in tiny pieces. The commit protocols can hardly be used to document a code history.
Even without GIT, the TCR workflow currently performs even worse than TDD. Two benefits mentioned above are currently in contrast to serious problems. The main downside of pure TCR is that you can no longer see what mistakes you have made.
A Test-First method at TDD, with an initial failing test, guides the programmer like a guide beam to the target. Of course TDD is not an automatism to solve problems, as sometimes the impression is given. However, TDD is very helpful in focusing to the problem. You always have the next step to the solution in mind. TDD is directed towards the future solution. TCR, on the other hand, is always oriented towards the present.
Another downside of TCR compared to TDD is that it tempts you to do the tests after implementing the productive code. As long as you don’t do tests and as long as you don’t make syntax errors, everything is checked in. If you do the tests beforehand, they are the ones that destroy the code. If, on the other hand, you later write the test for buggy production code, the test is deleted instead of the bad implementation.
This leads directly to the most serious downside of TCR. What if at the beginning of a TDD cycle, instead of the expected failing test, a green signal suddenly appears?
Then something goes terribly wrong. Red alert! The test threatens to derail. The worst mistake you can make with TDD are defective tests with false negative results.
To reduce this danger, we follow the advice of Kent Beck: „Never write a single line of code unless you have a failing automated test.“ ( Highlighting by me.)
I strongly recommend: Do not use TCR for commercial software development.
I don’t know how GIT can help you to keep the „rules of the game“ and avoid the risk of false negative tests. My idea to solve these problems is a kind of hybrid TCR. A combination of TDD and TCR.
The developers work as usual with their local repository and run TDD. Each time a TDD test turns green, this triggers a TCR background process on the shared code. Almost always these tests would have to turn green just as successfully and thus lead to a final commit. At the same time, this background process ensures that the repository on the local workstation is synchronized with the current shared code.
In exceptional cases, a test fails even though it was successful locally. This can only occur if a conflict has occurred in the meantime. Developers receive a signal saying: „An immediate conflict resolution is required!“
A positive educational effect of TCR is thus also present, because conflict prevention is the fundamental aim. The conflict frequency is the lower and the conflict solutions are the easier the smaller the TDD cycles are.
Such a hybrid solution cannot simply be implemented via a GIT command. However, the effort required to implement it is much less than the effort required to implement Limbo.
The Forthcoming Limbo
Limbo’s a great idea. But a lot of effort is needed to make it a reality. Since each programming language has its own syntax, a separate Limbo must be created for each supported programming language. Actually, even a specially tailored development system is required, which supports collaborative editing to create graphical user interfaces. It would be easier to create a new programming language and development environment especially for Limbo. But then you have an acceptance problem.
I assume Kent Beck’s Limbo will be realized one day. TCR does not have to be included. An optimal Limbo development system only offers tree transformations that are syntactically and semantically correct. Tests and productive code are thus created practically in parallel.
The idea of Limbo should then also consider other requirements such as code reviews. Suppose we had a tool similar to Google Docs and we used it to collaboratively write a story in natural language. Suppose there was a group of proofreaders in addition to the group of text writers. They prevent a text from containing syntactic or semantic errors and becoming visible to everyone in this tool. Is the final text really good? Actually there should be another group. Editors who, on another level, only allow the satisfactory text to pass through. This corresponds to a code review. In addition, there could be another group that decides at the next level which parts of the story are so good that you can earn money by publishing them.
n my opinion Limbo should implement such a pipeline for different code layers. In a metaphorical sense this would be a kind of three-dimensional Game of Life.
Limbo has a promising future, but it doesn’t start tomorrow.
Update from 22 February 2019
There is a very interesting contribution by Thomas Deniffel, who also showed a presentation about TCR on 21. February at the Munich Meetup. In the medium article „All Downsides and Open Questions of TCR“ which is still open, downsides and open questions are listed which he encountered in his workshops and discussions. He does not do this because he wants to discredit TCR. On the contrary, he is committed and very open-minded towards TCR and Limbo. I also think it is very constructive to address problems openly. Some of the downsides mentioned there have already been mentioned in this blog post. But most of it is new or differently presented. IMHO: It’s worth looking for solutions. Limbo has the potential to trigger a second revolution in sustainable software development and TCR is the avantgarde.
Original article: Was ist TCR?