This is why I end up creating an interface for the calls that perform modifications. Then I have one implementation that logs and one implementation that does the actual work. I end up with the output being as representative as possible as to what would happen. I also feel a lot more comfortable that a dry run truly won't write anything when the only class that could ever actually write anything is not even instantiated in dry run mode. I don't get that same comfort when there's a ton of branches sprinkled throughout checking for a dry run flag.