In Praise of –dry-run

For the last few months, I have been developing a new reporting application. Early on, I decided to add a –dry-run option to the run command. This turned out to be quite useful – I have used it many times a day while developing and testing the application.

Background

The application will generate a set of reports every weekday. It has a loop that checks periodically if it is time to generate new reports. If so, it will read data from a database, apply some logic to create the reports, zip the reports, upload them to an sftp server, check for error responses on the sftp server, parse the error responses, and send out notification mails. The files (the generated reports, and the downloaded feedback files) are moved to different directories depending on the step in the process. A simple and straightforward application.

Early in the development process, when testing the incomplete application, I remembered that Subversion (the version control system after CVS, before Git) had a –dry-run option. Other linux commands have this option too. If a command is run with the argument –dry-run, the output will print what will happen when the command is run, but no changes will be made. This lets the user see what will happen if the command is run without the –dry-run argument.

I remembered how helpful that was, so I decided to add it to my command as well. When I run the command with –dry-run, it prints out the steps that will be taken in each phase: which reports that will be generated (and which will not be), which files will be zipped and moved, which files will be uploaded to the sftp server, and which files will be downloaded from it (it logs on and lists the files).

Looking back at the project, I realized that I ended up using the –dry-run option pretty much every day.

Benefits

I am surprised how useful I found it to be. I often used it as a check before getting started. Since I know –dry-run will not change anything, it is safe to run without thinking. I can immediately see that everything is accessible, that the configuration is correct, and that the state is as expected. It is a quick and easy sanity check.

I also used it quite a bit when testing the complete system. For example, if I changed a date in the report state file (the date for the last successful report of a given type), I could immediately see from the output whether it would now be generated or not. Without –dry-run, the actual report would also be generated, which takes some time. So I can test the behavior, and receive very quick feedback.

Downside

The downside is that the dryRun-flag pollutes the code a bit. In all the major phases, I need to check if the flag is set, and only print the action that will be taken, but not actually doing it. However, this doesn’t go very deep. For example, none of the code that actually generates the report needs to check it. I only need to check if that code should be invoked in the first place.

Conclusion

The type of application I have been writing is ideal for –dry-run. It is invoked by a command, and it may create some changes, for example generating new reports. More reactive applications (that wait for messages before acting) don’t seem to be a good fit.

I added –dry-run on a whim early on in the project. I was surprised at how useful I found it to be. Adding it early was also good, since I got the benefit of it while developing more functionality.

The –dry-run flag is not for every situation, but when it fits, it can be quite useful.

7 responses to “In Praise of –dry-run

  1. Faster debugging is a big help! It’s worth some extra code.

  2. I often write code so that it does not perform file system actions but instead writes the equivalent action to stdout. When I am satisfied with the actions, I pipe them to bash/sh/zsh. Effectively, I use dry-run all the time and pipe to run the side effects.

  3. Another great reason to have a –dry-run flag, is an AI coding agent like Claude Code can run the utility and inspect the output to understand what it does, which helps it more reliably incorporate usage of the tool, and debug. In fact, CLIs designed for agent consumption in mind is a very powerful technique.

  4. The last time I wished a “–dry-run” was yesterday, in the Google Cloud CLI (gcloud). The AWS CLI (aws) has a “–dry-run” option, and it helped me to fix a command line before executing it.

  5. I use the opposite for conversion routines. Quite often I need to repair or update some stuff in the database but before I do the actual conversion I like to see what will be changed, so I use a logical that indicates wether to update or not. Since logicals in my programming environment are by default FALSE, I need to explicitly state that the conversion must be done

    It saves me from accidentally updating the data before the script is bug free

    And don’t ask me how I know that this is a useful technique 😉

Leave a reply to Sujan Kapadia Cancel reply