Abstracting services with closures

You probably all use cache service, property services and maybe some others too. Abstracting away which one you are using so that your code doesn't need to bother about the details can be a good thing because it leads to less errors, but more importantly if you decide to change to a different service you can do that without needing to change your main code.

Property service as a setting

Most of my apps have a namespace in which everything to do with the app settings are held. Adding a few items to manage the getting and setting of a property service means i don't have to pollute the rest of the code with the mechanics of which type of store I'm using. 

My settings contain a section like this. In this example I'm using the Script properties store, and converting to and from objects if necessary
... more settings,
    props: {
      store:PropertiesService.getScriptProperties(),
      get: function (key) {
        var r = this.store.getProperty (key);
        try {
          var ob = r ? JSON.parse(r) : null;
        }
        catch (err) {
          var ob = r;
        }
        return ob;
      },
      set: function (key , ob) {
        return this.store.setProperty (key , JSON.stringify(ob));
      }
    },
.. more settings

Using

Elsewhere in my code if I want to read or write to the property service, I don't need to know anything about how it's done, and can change the store or even the entire service by simply changing the settings, without disturbing the code that uses it.
ns.settings.props.set (key , value);

and
var value  = ns.settings.props.get (key);

Using a closure

Of course you could just write a couple of functions to set and get properties to abstract them away too, but this approach seems an altogether more appropriate one. Hopefully you'll see in a moment why. 

What we're doing here, although it's not that obvious, is to leverage JavaScript closures. So let's do that a little more overtly. 

First we create a function that makes an object with methods, and to which we pass the service to use. Because of how closure works, the value we pass as service when the object is created is 'remembered' as part of the function.
function makeService (service) {
    
    return {
      store:service,
      get: function (key) {
        var r = this.store.getProperty (key);
        try {
          var ob = r ? JSON.parse(r) : null;
        }
        catch (err) {
          var ob = r;
        }
        return ob;
      },
      set: function (key , ob) {
        return this.store.setProperty (key , JSON.stringify(ob));
      }
    };
  }

So we can create a service like this
var scriptProps = makeService (PropertiesService.getScriptProperties());

and later on, invoke it like this.
scriptProps.set (key, value)
and
var value = scriptProps.get(key)

But... you can also use exactly the same function to create another service, with the same methods, that writes to the User properties instead.
var userProps = makeService (PropertiesService.getUserProperties());

Of course you still need to keep these somewhere, so I'll modify my original settings like this
... more settings,
    props: {
      script: makeService (PropertiesService.getScriptProperties()),
      doc: makeService (PropertiesService.getDocumentProperties()),
      user: makeService (PropertiesService.getUserProperties())
    },
.. more settings

Now I can entirely change my property service source - add exponential backoff everywhere, maybe use cache or perhaps a database service simply by modifying my one makeService function.

For more like this, see Google Apps Scripts snippets. Why not join our community , follow the blog, twitter, G+ .You want to learn Google Apps Script?

Learning Apps Script, (and transitioning from VBA) are covered comprehensively in my my book, Going Gas - from VBA to Apps script, available All formats are available now from O'Reilly,Amazon and all good bookshops. You can also read a preview on O'Reilly

If you prefer Video style learning I also have two courses available. also published by O'Reilly.
Google Apps Script for Developers and Google Apps Script for Beginners.



Comments