TCR Variants (test && commit || revert)

Thomas Deniffel
Nov 15, 2018 · 5 min read
Image for post
Image for post

In his post, Kent Beck suggests ‘test && commit || revert.’ This a simplification. This post explores, which variants available to this and how you can implement TCR.

Note: TCR is new to you? Check out this post, which provides background, context and an example.

The Original

$ ./test && git commit -am working || git reset — hard

This initial approximation has some flaws you will recognize as soon as you implement something: As soon as your project does not compile it reverts and as soon as the current test fails, the test gets deleted.

In Pseudocode:

if(test().success)
commit()
else
revert()

BTCR

$ ./buildIt && (./test && git commit -am working || git reset — hard)

This version tries to build the software first. If it fails, nothing is executed — no commit, no revert. Compilation-Issue solved.

There are some details, that are interesting. Gradle, for example, has tested in its build-process. Therefore you do a ‘-x text’ in your build command. You also don’t lose performance (at least with Gradle), because the tests use the built artifacts — no extra work is done.

In Pseudo-Code:

if(build().failed)
return
if(test().success)
commit()
else
revert()

The Relaxed

# git checkout HEAD — src/main/$ ./buildIt && (./test && git commit -am working || git checkout HEAD — src/main/)

It is worth, to put this in its script, called revert (much more beautiful to read).

In Pseudo-Code:

if(build().failed)
return
if(test().success)
commit()
else
revert('src/main')

The Gentle

## git stash drop 0 2&>/dev/null; git add -A && git stash push$ ./buildIt && (git stash drop 0 2&>/dev/null; git add -A && git stash push)

After TCR kicked in and reverted our code, we can still type

$ git stash apply

to get our wrong code back. You can argue, that this hurts the idea of TCR, but sometimes you want to do this version.

The Split

$ cat ./test
./scripts/buildIt && (./scripts/runTests && ./scripts/commit || ./scripts/revert)
$ tree script
scripts/
├── buildIt
├── commit
├── revert
└── runTests
$ cat scripts/buildIt
./gradlew build -x test
$ cat scripts/commit
git commit -am working
$ cat scripts/revert
# git reset --hard
git checkout HEAD -- src/main/
$ cat scripts/runTests
./gradlew test

The buddy — Continous TCR

while true
do
./tcr
done
$ cat tcr
./buildIt && (./test && git commit -am working || git checkout HEAD — src/main/)

So, why is this called “The buddy”? You have to try it. When you code it is like someone is sitting beside you and as soon he spots an error, he brings you back in a green state. Replace in the example in this post of Fibonacci the plus with a minus. A ghost hand changes it back immediately. With the buddy, you will feel the real spirit of TCR.

Pseudo-Code:

while(true) {
tcr()
}
function tcr() {
if(build().failed)
return
if(test().success)
commit()
else
revert()
}

The watch buddy

while true
do
inotifywait -r -e modify .
./tcr
done
$ cat tcr
./buildIt && (./test && git commit -am working || git checkout HEAD — src/main/)

ionotifywait -r srcblocks until there is a change in the src directory. The rest is the same as in ‘The buddy’. The Pseudo-code looks familiar:

while(true) {
block_until_change_in_directory('src')
tcr()
}
function tcr() {
if(build().failed)
return
if(test().success)
commit()
else
revert()
}

You can watch Alejandro implementing an example with ‘The watch buddy’ on YouTube.

The Collaborator

  1. ‘test && commit’: This can be used together with push/pull to synchronize with your colleagues. It becomes a collaboration tool.
  2. ‘test && revert’: This changes the way you code and supports the ideas of TDD much better as TDD (commit is here included as well, but only as an implementation detail).

In the collaborator, we add and run another script together with another variant (Kent Beck proposed this as part of “Limbo on the Cheap”:

while true
do
git pull --rebase
git push origin master
done

This script makes synchronization transparent — like Google Docs. As soon we run ‘./tcr.’ (whatever variant you choose), the second Git command pushes it, and on every workplace of your colleagues, the first command synchronizes their code.

In Pseudocode:

async {
while(true) {
Git.pull('rebase')
Git.push('origin', 'master')
}
}
./tcr

Local Buddy, Remote Team

do
git pull --rebase
git push origin master
done
## Open new Tabwhile true
do
./tcr
done

I prefer “The Relaxed” with “The Split” as the implementation of ‘./tcr.’

In Pseudo-Code:

async {
while(true) {
Git.pull('rebase')
Git.push('origin', 'master')
}
}
function tcr() { ... }async {
while(true) {
tcr()
}
}

The Storyteller

tl;dr Instead of just resetting the code, ‘The storyteller’ communicates back in a ‘human’ way so that it feels like a pair works with me remotely on the project.

Conclusion

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store