From a comment I wrote on the Coding Guidelines page before the Proposals section existed:

One guideline I've advocated in the past that might fit here is this:

Don't pass commands (to functions and scripts) as parameters. If you want to be able to call on two different operations, write two different functions or scripts.

For example, the syntax for Tom Robinson's UUID function is "UUID ( type )", where "type" specifies whether to use version 1 (timestamp and MAC address) or version 4 (random numbers) of the RFC 4122 standard. I suggest that this would be better written as two functions, "UUID.v1" and "UUID.v4".

Here's why. FileMaker's main selling point to developers is that it's faster to work with than just about any other development platform out there. There are several ways FileMaker accomplishes this, but I think the most unique is what I call "the palette of available commands." In an Edit Script window, every script step you can use in a script is listed on the left. In Specify Calculation dialogs, every field, operator, and function you can use in the calculation is listed in the top of the dialog. If you don't know exactly what you're looking for, it's still right there; you don't have to look it up unless the name of a function isn't enough to tell you what it does (which is a separate problem).

For every function or script that takes a command as a parameter, the name can't be enough to tell you what it does; you have to go look up what the enumerated acceptable values are. That's time I could spend sipping margaritas on the beach. By splitting UUID ( type ) into UUID.v1 and UUID.v4, both options are now visible in the palette of available commands built in to FileMaker.

One possible exception to this might be commands that take boolean values. The meaning of a "suppressDialogs" parameter for a script is reasonably obvious.

What does everyone else think?

This is proposed as a best practice.

  • No labels

2 Comments

  1. Anonymous

    I think that generally it's a good idea to avoid options, but doing so would duplicate code in many cases, and the UUID function by Tom Robinson is a good example. The function takes one of four values for it's argument, "1", "1h", "4" or "4h". The code used for "1" or "1h" is almost identical, but eliminating the option would require two separate functions that share most of the source code.

    As an alternative, in cases like this, where having two custom functions for similar functionality that differs by an option, I just create additional functions that call the master, so in addition to a UUID function I have UUID1, UUID1H, etc. that simply call the UUID function with the appropriate parameter.

    Chuck Ross

    1. Having separate interdependent functions is something I also do sometimes do, but I do it so that the "master" functions still don't accept options as parameters. I do this by figuring out all the work a family of functions have in common, putting the common functionality in a "master," and putting all differences from that common functionality in the "option" functions. To continue with the UUID example, I'd have UUID1 as an independent function, then UUID1H would call UUID1 to get the essentially data, but UUID1H would be responsible for adding hyphens. UUID4 and UUID4H would have the same relationship. This offloads some of the complexity from the "master" to the "option" functions, and the master function is still easy to use by itself.

      That said, I choose not to do this for the particular case of UUID functions. Duplicating code isn't necessarily a bad thing. In these situations, we each have to choose a balance between the DRY Principle (http://en.wikipedia.org/wiki/Don't_repeat_yourself) and Occam's Razor that suits our needs. (My interpretation of Occam's Razor as applied to programming is "minimize dependencies," not "use shorter code.") The goal of the DRY Principle is to make code easier to maintain by minimizing the number of places to make the same change. The less you intend to change a given piece of code, the less important this is relative to other concerns. If I'm working on a piece of code that I intend to be highly portable — code that can be applied to many circumstances without modification — I'm more concerned with making it easy to install and transfer than easy to modify. If I expected it to need frequent modifications, it wouldn't be very portable. One way to make things easy to install and transfer is to minimize dependencies; if I only want to use UUID4H in a solution, why should I have to copy the code supporting the UUID1 function, too? (This hints at another value of duplicating similar-but-distinct functionality: specialized code can be better optimized.) In the case of UUID functions, I think the portability concern overwhelms the maintainability concern, so I keep the functions as independent as possible, even at the cost of duplicating substantially similar functionality.