Google Apps Script Development – Best Practices

This is an overview of the various techniques and best practices I have evolved in developing Google Apps Scripts over the years. Of course Google have got a few suggestions of their own, and there are plenty of more general JavaScript best practice guides out there, and even a few GAS onesthis one is pretty!

Get in touch now if you need any help with creating your own GAS scripts or have a look through some other free scripts and snippets.

Style

I try to keep to Google’s JavaScript style guide with a nod to Doug Crockford’s suggestions and always running it through JSHint to keep me in line! I use the simplified JSDoc GAS supports, and I won’t go into my spacing policy but I do make sure there is lots of it and try to stay consistent.

Logging/Debug Trace

I have created my own simple wrapper around the BetterLog library, which provides some synaptic sugar and adds the function name to the beginning of each trace line, something I find helpful. BetterLog allows you to easily send the trace to a separate sheet which is very useful if you’ve got handlers running in different execution contexts.

Optimising the Script

It’s mainly service calls that slow down your code (more on that here), so along with the debug trace you are already using take a look in View>Execution transcript in the script editor to see any service calls that are unnecessarily inside loops, etc.

Error Handling

The overriding principle here is to make a distinction between operational and programmer errors in the code; keep programmer errors specifics away from the user (hopefully these will all have been dealt with during development) and cleanly deal and back out from the operational errors – things caused by the outside world like user input mistakes, external resources not being available, etc. This article is more to do with developing JavaScript for Node but it’s a great article on error-handling generally.

So I make sure any calls from within event handlers (simple or installable triggers, things like a file opening, form submission, etc.) are inside a try/catch so all errors thrown can be tidily logged and re-thrown in development, and either handled or reported to the user in production.

Testing

I have tried out a few of the testing frameworks libraries available for GAS, but decided to roll my own around the underscoreGS library [link TBD]. I found QUnit for GAS too cumbersome and I’d never get around to updating it and GSUnit was replicating a lot of the functionality I’d already included with underscoreGS. So I’ve got a bit more pragmatic and create simple unit tests functions in each module if they need them and they aren’t going to be easy to test as a user; things like lower level utility functions. These individual module test functions are all called from a master test function which I’ll link  to a debug menu in the sheet or doc. The rest of the testing is done manually. My scripts haven’t yet got complicated enough to justify a completely simulated GAS environment for fully-automated testing. Although you can always develop your standalone scripts locally in eclipse, and stub-out or create emulated Google Services – but I’ve not tried that yet (I’m sure I’d read about someone doing this but couldn’t find the link).

Debug Menus

I find a dedicated debug menu in the sheet or doc can be useful to avoid having to keep going into the script editor to run functions during development.

Design Patterns

I nest private functions to avoid too much global clutter:

  function aFunction() {
    var aVariable = localFunction()
    function localFunction() {
      // Do something that isn't accessible outside this function
    }
  }

and wrap all the functionality in each script file in it’s own namespace by simply wrapping it in an object:

  var NamespaceObject = {
    publicMethod: function() {
      Logger.log('public method called');
    }, 
    publicProperty: 'some value', 
  };

  NamespaceObject.publicMethod(); // public method called
  Logger.log(NamespaceObject.publicProperty); // some value

or use the module pattern if I’m wanting to have functions private to that object:

  var NamespaceObject = (function() {
    var namespaceObject = {};
    namespaceObject.name = 'NamespaceObject';
    namespaceObject.showName = function() {
      Logger.log('name: ' + namespaceObject.name)
    };
    return namespaceObject;
    function privateFunction() {
      Logger.log('Some private stuff');
    }    
  })()

  NamespaceObject.showName(); // name: NamespaceObject
  Logger.log(NamespaceObject.privateFunction()); // TypeError

Libraries

There are a whole suite of different GAS libraries available for different purposes, I list the main ones I use elsewhere.

Exponential Backup

The Google services can occasionally fail for no apparent reason, so one interesting snippet worth mentioning is for using exponential backup to make service calls, i.e. re-trying a call at different intervals if it initially fails.

Google APIs

There are limits to the Google App functionality that is exposed via the built-in GAS Services, however more can be accessed via the Google APIs they provide for all types of web apps to use. Here’s the Drive API for example. These are a bit trickier to use as you are poking around within JSON responses, and having to carry out authorisation but the extra power can be worth it some times  – and they usually operate faster.

Bruce McPherson has created a useful library for using the Drive SDK.

Version Control/Configuration Management

Version control is not very easy to do as this point, beyond taking a copy of every version of a script and manually copying it to somewhere like Github.

You can store versions of your script using File>Manage versions… in the script editor, however these old versions can be awkward to get to.

There is a utility called GasGit which you can use to upload scripts to Github, however it is a bit awkward to set up. Or you can just develop locally and use this Node utility to sync your files to Github and the load into the online script editor for running, but things will get messy if you start making changes in the script editor as well!

Here’s a recent discussion on G+ on the subject.

 

Share