FileMaker 17 introduces a new script step: Perform Script by Name. FileMaker Devs have been asking for this feature for a long time. It sounds like a useful idea, but we should probably try to understand how it works before we just adopt it willy-nilly, for all our script calling needs. Let’s explore this idea together.
Perform Script by Name: The basics
Perform Script By Name is a script step that functions as it is named. We now have two options when using the Perform Script step: By Name & From list.
If “From list” is chosen, then we go about choosing a script in the normal way. However, if “By name” is selected, we get to set the name of the script using the calculation dialog.
At the script’s runtime, this step checks to see if the script is in the list of scripts and runs that one. If it isn’t in the list, then we get the good ol’ message:
We can suppress the message with the Set Error Capture [on] step and capture the error (104 Script is missing) with the Get (LastError) function.
In a multi-file solution, we can use this same step to call a script in another file using the same table/field format: ExternalFileRefName::ScriptName.
Notice this step is using the external file reference name, not the actual file name. We need to use the name we gave to the file reference.
Pretty simple. There doesn’t seem to be much else to this. Set the name of the script or external file reference name and script in some manner, and this step will run that script.
Oh, by the way, this works for Perform Script on Server as well. As we set up a script to run there, we are presented with the same dialog.
Wait, what? Why is this useful?
Here in FileMaker Pro 17 Advanced, we have the option to set a script name and run that script, a step that belongs in the ‘by name’ group of steps: Set Field By Name, Go to Layout by Name, and this one. When I first saw it, it struck me as odd: why would I ever use this step that adds another source of indirection to my file and is fragile. Let’s consider its possible uses and the idea that this step is fragile to see if we can find some workarounds.
It is useful after all
The option to perform script by name is actually useful. It seems to get rid of complex If / Else if / End if logic steps that determine the script to run. Maybe in a custom app, there’s a script called “Edit” and this script is run from a student record and a teacher record. The first part of this Edit script would have to use the If logic to determine which edit script to run, something like
Quite a few script steps.
With this new option, we can reduce the steps:
This does seem useful. It would certainly reduce the number of steps needed to determine the script. In a recent project, I saw one navigation script that ran for the entire system. IT was literally 150 lines long with a bunch of Else If logic steps. It was tough to debug. So there’s that. This option is useful.
Notice in the example above, I’m setting the name of the script into a variable and then passing that variable into the Perform Script step. That seems useful and handy.
Since the name of the script is a calculation dialog, I have a plethora of ways to get the script. I can construct it like shown above. I could get it from some preference table, or I could pass in the script name via a parameter, to name a few.
This new option in Perform Script allows us to write some pretty complex logic in a simpler way. If reducing the number of lines of code is your goal, Perform Script By Name is a must-use.
“Fra-gee-lay. It must be Italian”
Any developer’s first thought about this script step is that it can be easily broken. If my script name today is “ThatScript” and for some reason (legit or not) I decide to change it to “That Script”, then my perform script by name step is broken. That is certainly true.
Another factor to consider is that Perform Script By Name is another source of indirection, one that our Realtime Developer Intelligence tool FMPerception can find and point out, but this is an indirect source. Every time I use Perform Script by Name [“ThatScript”] I reduce the number of times FMPerception or database analysis tools can identify in the DDR where and when that script is used. That’s not bad. It is just something to consider.
But just because something is fragile or introduces indirection, there’s no reason to avoid this script step option. There are possible workarounds to the fragility issue. Let’s take a look at some of those.
Don’t change names
The first ‘workaround’ I can think of is: don’t change your script names. It seems obvious, but also almost unthinkable. FIleMaker is a rapid-application development tool. We can create a custom app quickly and easily, and that includes changing things on the fly. If our fieldName or script or layout’s original name is now unsatisfactory to us, it is easy to change. FileMaker after all actually looks at the ID of fields, layouts, scripts when calling or going to or setting. We’ve had it easy: change names as much as we want. I’d argue that this is a sign of not-fully-thought out planning, but I make no judgements. It happens. But I’d encourage us to change names of things as little as possible.
Second, if we do start using a script in the ‘by name’ option of Perform Script, we need to very clearly document that. In the above pictures, my script “ThatScript” is being used in the ‘by name’ option. So I should go over to “ThatScript” and document at the top “###### USED IN PERFORM SCRIPT BY NAME. DO NOT CHANGE THE NAME ######” or something along those lines to inform everyone, including your future self, to tread carefully with this script. Or put these called scripts in a “BY NAME” folder. Something to alert folks to its special case.
Generate script names
Third, we can generate the name of the scripts that will be used in the following parent script.
At the top of my Edit_Record script, I have a code block that gathers the names of the scripts that could be used in this parent script. I first set a global variable to 1. Then I go into each of the scripts that could be used.
Inside each script, at the top, I immediately exit with the script name.
and then collect that name into a JSON object, in my case, in $scripts.
This works. It adds complexity to your parent script, but it does ensure that I get the correct script name each time.
There’s more ways to ensure that you have the correct script names every time. There’s a good function I just discovered: ScriptNames(). It returns a list of the scripts in a file. That could be useful somehow. Maybe you could gather all the scripts into a global and then check against this list every time using Filter().
Don’t be afraid
This new option is useful and valuable in the right circumstances. I’d say we shouldn’t be afraid of it or avoid it. Use it where appropriate. But don’t go overboard. Don’t use it like we all started using ExecuteSQL() when it came out (that is, everywhere).
Be deliberate in its use. Document the heck out of scripts that are used in this “by name” manner, and be careful about refactoring script names for no good reason.
I look forward to using this to simplify complex logic. Give it a try, and let us know how you use the new Perform Script by Name step.