As part of my project to learn the Go programming language, I decided to rewrite some of my old Perl scripts in the newer language to see what was better, if anything was worse or if things stayed the same.
The scripts are not very glamorous, but are useful for my set up. One is for generating scripts that wrap around rsync in order to keep two directories in synch. The other (which is closely related) is for keeping track of which files have been marked for deletion and keeps deleting them if they reappear. Once one starts to copy files back and forth between directories, deleting files becomes a little bit complicated as the file you delete will keep reappearing unless you delete it everywhere. The script I wrote them before Dropbox and the like had come on the scene. I keep them around as I don’t like to have the only copy of my photos and videos in a folder managed by someone else. They are also useful for folders that have too much content to be stored practically in Dropbox, like virtual machine files, and synching folders on servers via SSH.
I have been meaning to update the scripts and change their behaviour for a while, so a rewrite is a good time to ditch some obsolete features. The synch script generator used to be able to generate batch files to run on Windows. Now, it just creates bash scripts. This is fine (for me) as, on Windows, I use Cygwin for rsync, so bash is not a problem for me as a dependency.
Another change is that the script generator used to silently skip generating a script if a file was in its destination. The thinking was that the generated scripts could be considered scaffolding for more capability that could be added by adding to or amending the scripts. The script should not overwrite these changes. Experience, here and elsewhere, has taught me that this is a nightmare to work with. Generated files should be regeneratable at any time. In light of this, the generated scripts are marked with a warning comment at the top saying that they have been autogenerated and are blasted out of the way when the program is run again, potentially as part of a scheduled task.
The script generation program is at:
https://github.com/robert-impey/generate-synch-scripts
The second program is for making sure that files stay deleted when two folders are synched as described above. This had been at
https://github.com/robert-impey/stay-deleted
However, as the project grew and I need to move code to more than one file I learned that package names in Go should not contain punctuation, so I started a fresh project and moved my code there:
https://github.com/robert-impey/staydeleted
My new version of the program is working correctly. I’ve also added a few new features like deleting old metadata files and an option to run repeatedly at random times, which is useful for running as a scheduled task.
The most immediate advantage that I have found for this script is the ease of distributing a binary generated by the Go compiler. The nature of the software requires that the program runs on every computer in the system, for my set up that includes Windows, macOS and Linux. Getting a perl script with a few library dependencies to run on all those computers was a pain. With Go, it’s been trivial so far.
In order to have a more modern command-line interface, my program now uses spf13’s Cobra library:
https://github.com/spf13/cobra
This has forced me to reorganize my code to some extent. This has been a good thing. However, I’m still very much at the beginning of my Go learning journey. Whilst the program works; the code is a bit of a mess. I’m not sure how to apply the clean code principles (such as SOLID) that I use in my day job writing C# to Go. Perhaps this is one of the main advantages of aiming to be a polyglot developer. Everyone should aim to write readable code in every language. We discuss and come to an agreement about design principles to do with how to use the language’s features in order to make code more readable. When one moves to a new language, you might not know how the language goes about implementing those features or those features don’t exist. What happens then to those design principles? Can they be reformulated for the new language?