Lately I’ve been thinking a lot about script modules in Octopus Deploy. Script Modules, for those of you not ITK, are a collection of PowerShell cmdlets or functions that exist outside of a script step that can be used across multiple steps across different projects/environments. They don’t have to be used to contain modules exclusively; they can just contain that will get executed upon the initial import of the module. The issue here is that these script modules are imported or every step in a process. So unless the code you write is idempotent, you’ll probably cause an error in the process. This is by design.

So at first I thought “put nothing in script modules” because they’re pretty pointless, right? Anything you write will pertain to a step exclusively, so why do you need to share code across steps. Turns out quite a bit of code is shared across steps, particularly checking and validating parameters.

Then, as step templates got more sophisticated they got harder to read, so then I thought “put everything in script modules!” It aided in legibility of the step templates and allowed them to focus mainly on setting up a process and using script modules to execute the function.

There is however an issue to this: script modules are the “magic” of a step template. If you’re not aware that a step template requires a script module, how can you communicate this implicitly? You could mention that a script module is required in a step template, but this is still a manual process that everyone remembers, or even buys into.

There is also another issue: I had to make a change to a step template that required a change to the script module. The step template in question was in heavy use, and so careful planning was required to make sure that the change in the step template and the script module was not a breaking change: basically what I mean is that whereas a step template has to be explicitly updated for a given step in an deployment pipeline, the same cannot be said for a script module. So whatever is the latest version of the script template is what a user gets. And if you make a few changes to the step template in an iterative manner, you have to be sure that if anyone updates the step template then all version have to match one another.

This caused me quite a headache, and though I was able to make the changes without breaking any deployment pipelines, it sure was a lot harder to work this way. What made it easier was that the step templates and script modules are deployed via a deployment pipeline themselves. I also have a VM with the step templates and script modules stored, so I was able to treat that as a local developer machine. This reduced the number of changes I had to make at any one time.

So where is my thinking now with script modules? I think they’re great, and I encourage them to be used. But they must be used with caution: if they are almost too successful and spread across too many step templates, one small change could have far reaching consequences. So if you are to use script modules, use them where step templates are expected to grow large and careful organisation of the modules is required, and use the step templates to set up and execute the functions. And because Octopus Deploy does not version either script modules nor step templates I encourage you to source control the files and deploy them. And on the matter, take into consideration that steps that make use of step templates have to be updated to the latest version whilst script modules will always use the latest version on the server. This is crucial to understand, and so limiting the number of updates and careful testing/use of feature flags as well as source control is key to ensuring no breaking changes are made.