So I watched Kent Beck’s TCR tutorials after trying it out myself (maybe it is perverse, but I like to see if I can get there first before reading the instructions. I learn better that way!).
What I found particularly interesting was two things:
One, every time he saved, his TCR ran. So only one file could be edited at a time, and the tests had to pass afterwards. I didn’t run until I tried to commit. On save is a whole new level! However it requires that your tests be in the same file as your code. Now Rust does this by default. Your integration and end to end tests can be in their own files but unit tests belong in the same file as the code they are testing. I believe this is how it should be.
It is hard to do with Java/ Kotlin and probably a lot of other languages, at least it isn’t how it was intended. I fear my test code may get deployed into my release jars and such. Maybe not, probably bears some experimentation.
Secondly, you really must reduce coupling/ increase cohesion! If you don’t have maximum cohesion for the element you are changing, you will not be able to make the change! Very interesting… probably a great exercise.
However a third thing I noticed was that since it is automatically running every time he saves, then the commit has no information besides “working” in it. I know that under ideal circumstances we would never need these commit messages, but wouldn’t it be nice to have AI make us a nice little commit message? That is what we will attempt here.
So for starters I will attempt to create a python script that will scan the code, scan the diff, and give me a one line summary of what was changed. I won’t go deep into the creation of this, but you can check it out at https://github.com/vextorspace/aiCommit. However what is interesting is the first attempt at my prompt:
"""
You are a terse and efficient developer.
You only state the most important changes in commit messages.
Each change should be on its own line.
Each change message should be 50 characters or less.
the diff is: {diff}:
Write a non-generic commit message."""
where diff is the output of git diff.
So how do you think it performed? I am using gpt-4o, and it does pretty well. However I noticed that it seems to be ignoring added files. It must be taking change to mean change to a file rather than change to the system, so added or deleted things simply don’t count in its eyes. So the next variant is:
You are a terse and efficient developer.
You only state the most important changes in commit messages.
Each change should be on its own line.
Each change message should be 50 characters or less.
An added or removed file should be mentioned in the message.
The diff is: {diff}:
Write a non-generic commit message.
this led to commit messages for new files like:
Add build.sh for PyInstaller execution
Not too bad, but we are also getting lines like:
Set git diff context lines to 10 in get_diff method.
which I think is a bit verbose. I am going to try a smaller character limit, say 5 words, but make it soft:
You are a terse and efficient developer.
You only state the most important changes in commit messages.
Each change should be on its own line.
Each change message should be 50 characters or less.
Try to keep each change message below 6 words if possible.
An added or removed file should be mentioned in the message.
The diff is: {diff}:
Write a non-generic commit message.
Now we get:
Add guideline for concise commit messages
It no longer adds things like what method. This is my preferred style of a commit message. If you need more you can look at the actual diffs. So I added a pyinstaller
to turn it into an executable, and added that to my test hello world project: https://github.com/vextorspace/kotlinTcrOnSave by changing the tcr script to use it to generate the commit messages. Now I have a TCR On Save that automatically generates the commit messages instead of just saying “working”. They are actually pretty good! Anyway, I also have a template for python programs using AI. My next goal will be to give it the new tests, and ask it to make the new one pass without failing the old ones. I added the ability to use a list of people to greet. The TCRonSave methodology made me
add a greetList function to Greeting
convert all the uses of greet to greetList
remove greet
copy greetList to greet
convert all the uses of greetList to greet
delete greetList
Very safe. And when you get the habit going, also very quick! It is that thing where if you eliminate choices at stages that don’t need them, you don’t pause. You just keep going - flow
See you next time when we try to get ai to write the code.