SidekickJS's blog

Closures for class/module privacy considered harmful

Using closures for class/module privacy is a bad idea: hard to extend, test, tool and read.

Closures are a fantastic tool when used for the right things. They’re perfect for functional code but they’re awful for reinventing classes or modules.

To consider why, let’s look at a module using a closure for privacy:

var SomeModule = (function() {

  function privateFunction() {
  }
  function publicFunction() {
    privateFunction()
  }

  return {
    publicFunction: publicFunction
  }

})()

We have a single public function, and an inaccessible private function implementing it.

Extension

Imagine your want to slightly alter the behaviour of this module - a quick patch, a modification - all very common.

No luck. Even if you only wish to change the behaviour of the public function you can’t as it references the private variable. Though you have a reference to the public function its reference to privateFunction is contained in a scope your redefinition cannot access:

SomeModule.publicFunction = function() {
  // new behaviour
  privateFunction(); // won't work - not in scope
}

You’re stuck - it’s impossible to get at local variables in a scope you’re not in.

Our only option is to alter the source, and now you have a patched version of the library to maintain. Quick REPL experimentation where we swap out a method is impossible. This also completely rules out inheritance to sub-type a constructor. Open for extension? Not at all.

Testability

You can’t get at the private methods or variables while testing. This makes mocking the functions or setting variables to test states a non-starter.

Equally you can’t write unit tests for the private methods themselves. Some argue that only public APIs should be exposed to test, but this is not something to be dogmatic about. If you’ve got a tricky interaction between a few private functions it’s very helpful to be able to test them!

This pattern has crippled a core strength of Javascript: the easy unit-testability inherent in prototypical object system. Being able to swap out functions as easily as overwriting it is laughably easy compared to the gymnastics in languages with classical inheritance - why lose this benefit?

Readability

Modules written in this pattern are always unique looking, even for Javascript which lacks any standardisation around definitions. There’s no neat package of functionality for readers to parse - you have to read the manual, imperative construction of a type rather than a declarative definition. At least prototypical type definitions, or one of the many ‘classes in JS’ libraries, are easily read.

Tooling

Just as humans will have to learn how to parse your code, so too will your tools. For example, an auto-completer will have a tough job working out what your hand-rolled module/class is, and how to autocomplete it.

True privacy is a bad idea in OO

The goal of totally inaccessible private variables* is a bad one. You cannot know ahead of time how someone else will want to modify your code - perhaps for performance, future compatibility or to add functionality.

A common argument for true privacy is that it’s more secure. Obviously there’s no real security in client-side code as anyone malicious can access any part of your code via the debugger. It is only in very limited cases - for instance hosting untrusted code - that this justification for privacy holds.

Alternatives

The ideal is a way to communicate that something is private and not to be relied on without preventing unforeseen modification by your code’s users. One way is simply to prefix it with _ - like Python:

var MyModule = {
  publicFn: function() { this._privateFn() },
  _privateFn: function() {}
};

If you’d like to make it more awkward - and dangerous things like relying on implementation details should be awkward - use something invalid for .property access like {"-private":x}. This’ll have to be accessed via module["-private"].

Now it’s easy to extend, test and tool - even with modules mixing in the code as we’ve referenced it on this not the module’s name. It’s still clear which parts are internal.

Where closures shine

Closures are great for creating functional tools like memoization, state machines or clearing up boiler-plate:

function after(n,cb) {
  var calls = 0;
  return function() {
    if(n === calls) return;
    calls += 1;
    if(n === calls) cb();
  }
}
var allDone = after(2,finished);
somethingAsync(a,allDone);
somethingElseAsync(b,allDone);

This is neat. It’s atomic: a unit of functionality you either want as a whole or don’t. If you want different functionality you’d just write a new function. There is no need to access its internals to unit test. It’s more cleanly implemented than an OO equivalent. And it’s idiomatic in a language with higher-order functions.

There are lots of great examples of closure-based privacy to create functional tools: e.g underscore.js, Promises* or for removing boiler-plate in D3.

Closures for functions, objects for OO

Closures are powerful enough to implement object-orientation as anyone who has read their SICP will know. However: just because you can implement modules and classes with them doesn’t mean you should. Javascript has a very usable object system that the JS engines have optimised for.

Embrace JS’s dynamic nature for testable, readable, idiomatic code!