We’re thrilled to have Don in Portland tonight, talking about some interesting philosophical aspects of FileMaker development, which translate into immediately useful tips in many cases.
Don first showed this at Pause on Error in New York in July, and now is doing the west coast FMPug tour.
This is mostly about the procedural script methods in FileMaker – the scripting language. This is not an object oriented system, so it makes sense to apply best practices from other procedural systems.
Build small scripts, that are independent. Expect all scripts to be called by other scripts, and they all have input and output. Consider the unix pipe | where you can send the output from one program (like ls or history) into the input of another unix program, like grep. In this way, you can filter the results of a directory or list of commands used by a certain string, for example #history | grep ssh Very cool stuff (the history command is new to me – it shows you all the commands you’ve done in Terminal)
Unix has the concepts of StandardInput, StandardOutput, and StandardError. These translate in FileMaker as Get (ScriptParameter) and Get (ScriptResult)
When a script fails, make it fail loudly. This way, it’s not a big problem for users when a small thing is failing that can aggregate to become a big problem, like the proverbial 2 cent rounding error. It’s a good idea and a common practice to turn Error Capture on, but this suppresses the display of error messages. The errors are still captured though, so if you call a subscript, make sure to pass any error.
Example script: Using a single script to create related record in a portal, to get around the lame issue of the last portal line being blank. But how to do this with a single script that can be used from any context or layout, and for multiple different portals on the same layout? The trick is the parameters he sends to the script being called, which specifies the ‘model’ (which is borrowed from the web world – I usually specify context, table, or action or something like that) then the table and key field where we’re starting (using the GetFieldName() function) and the context we’re heading to to create a record.
This utility script can then be tested very well, updated centrally, is insulated from layouts and context. It uses the SetFieldByName function to specify both the field and the value that were grabbed earlier. It’s beautiful because it’s contextless, and not at all brittle.
The next example shows using methods like this to build reports, which also adds in the Bruce Robertson ‘Virtual Lists’ methods. Don builds a return separated list with all the report data, an Array of all the data in name value pairs. Looks kind of like XML. Check for any errors, and then pass the array to a DisplayReport script. The beauty here is that a single report system can run any kind of report from any table with no changes to the script at all – only in what script parameters are specified. The details of the script were very involved, but each thing was well insulated, and could be understood if you focus on it for a minute, and don’t try to sit in the front row and blog when you should be paying attention instead.
‘Fold Knowledge into Data’
The last example involves syncronizing FileMaker and MySQL data. This is the most complex example, and there are some really detailed parts. It uses some ‘black box’ scripts that do the heavy lifting, but don’t need to be modified to make any changes. Instead, there’s a single master controller script that is edited if there are new fields or tables that need to be added to the synchronize method. Each new field or table is specified in exactly one place, and if it fails to work, it fails loudly and quickly, to minimize any downtime.
Program logic can be stupid and robust. Keep as many variables local as possible, instead of global.
There are some really great ideas here.
Don relies heavily on the SetParameter and ReadParameter custom functions which are available from Geoff Coffey at Six Fried Rice. These are pretty cool, and look more robust that what I usually use, which is the GetParam function from John Sindelar. Usually, I don’t use a SetParam function, but just provide name value pairs like this: context = person ; action = create ; id = 12345
Don really like OmniGraffle and OmniFocus. Loved reading the release notes they have every day that list all the bugs they fix when and why.