The Boy Scouts have a rule:
Leave your campsite cleaner than you found it.
We know how to apply this rule when writing code but we often overlook this rule when it comes to installing or deploying that software. I’ve seen, and committed, some pretty heinous accounts of changing a user’s machine, and in every single case- every single case- I’ve discovered in retrospect it was a poor decision. Note I am only talking about internally deployed software where you have control over the environment (ie, I’m not discussing game installers and the like!).
At this point, I live by one golden rule:
Never leave persistent state on a user’s machine. If you must, all state should be stored in a single folder.
Two caveats:
- “Never”: Some third-party software will not adhere to this, and there are some situations where it cannot be avoided due to third party dependencies, so you may have to adapt. I apply this rule only to what I have control over.
- “persistent state”: Anything that sticks around after a process exits or a user logs off, that isn’t under version control. Examples of persistent state are files, registry entries, and environment variables. Usages include installation, file association, and settings persistence.
Some examples of things my tools or tools I’ve seen have put in or required:
- Editing 3rd-party application preferences files or adding files to the application’s preferences folder.
- Copying over scripts or other files out of version control onto the user’s machine.
- Installing shell extensions.
- Setting a user’s source control environment variables (P4PASSWD, P4CLIENT, etc).
- Mapping a temporary drive (that scripts rely on for an absolute path, of course!).
- Leaving persistent registry or environment variables for the user’s branch, project, etc.
- Storing preferences for applications in multiple places.
I consider all of these mortal sins and red flags warning flares go up when I see them.
Why you shouldn’t do it!
Games development is chaotic. Computers go through a lot of change, they install a lot of software (first and third party) and uninstall almost as much. To make matters worse, things often go wrong, and many people are generally writing software and scripts that need to run independently and not interfere with one another. You can avoid conflicts by not making any persistent changes to a user’s machine. As long as everything is local to the process, or in some unique files in a well define place (AppData/Local/<company or group>/<app or tool name> on Windows), the risk of conflict is almost none. By leaving the computer in an unmolested state, apps that do cause persistent changes become noticeable and problems more fixable (and it is easier to clean up after offenders if you have 5 suspicious environment variables rather than 50).
Change also happens in unpredictable ways. While hard-coding a virtual disk drive seems fine, what happens when you need to run your tools on a machine (an outsourcer’s, for example) that already has a drive with that name? Setting a persistent environment variable indicating the target branch seems fine, but what happens when 4 different tools each store their own (it will happen if you let it!)?
I’m not going to get into installers. Don’t do it. I’ve never seen a reason to do it for internal software. If your studio does it, I wonder how many people actually understand it or can maintain it. There’s less and less reason to do anything of the sort nowadays- all your python and .NET applications have no need of a traditional installation. I’d love to be educated about why some studios use installers for their internal tools, so if you have a success (or horror) story I’d love to hear about it in the comments.
Persistence is a drug- Just say No!
I realize now that persistent settings were a deployment drug. They didn’t make anything easier. They were an appealing way to either do things I shouldn’t have been doing, or support workflows I shouldn’t have designed. And global persistent state like this has the additional unfortunate effect of negatively impacting everything else in the system- because everything, and everyone, views them as the same easy solution, or key to complete power and ease over deployment and bootstrapping.
There are options. I’ll tell you about them in future posts because I don’t have much time now. In the meantime, join me in taking the Deployment Boy Scout’s Oath:
On my honor, I will do my best, to do my duty to developers and their computers. To avoid the use of persistent global state, to seek out better solutions to deployment problems, to keep users’ machines clean and under their control, and to keep my code free of such corrupting influences, always.