2012.01.11

A case against private variables and functions in JavaScript

arrr im a private, you cant access me
(not sure if the pirate image + caption was created by Zeh Fernando, he sent it to me a couple years ago, forgot to ask him…)

Another polemic subject and something that I’ve been delaying for a while, I’ll try to explain how I got to my conclusions and I’m sure a lot of people won’t agree until they experience the same problem or realize how often it may happen on a real project and specially if it does happen with a code you don’t “own” and/or can’t change without compromising future updates… The advice is mostly about JavaScript (since it’s what I’ve been coding more lately and where I think the issue is bigger) but it also fits other languages.

Not so long ago I had an opposite opinion about this subject - I would always set everything to private and only changed to protected/public if needed - try to understand what made me change my opinion and pay attention every time you find yourself “tied” or doing lots of hacks just because you can’t monkey-patch a simple function/variable.

Private variables and functions in JavaScript

Unlike Java/C#/AS3/PHP, JavaScript doesn’t have keywords for defining if a variable/function/object is private/public/protected/final/etc (acessor keywords)… But since it has closures and each closure has it’s own scope we can emulate some of these access controls, a private variable is simply a variable declared inside an “unreachable scope”. Example:

// global variable
var lorem = 'ipsum';

(function(){
    // the immediately invoked function expression (IIFE) will create a closure
    // all vars and functions inside this scope will be "private"
    var foo = 'bar';

    console.log(lorem); // 'ipsum'
    console.log(foo);   // 'bar'
}());

console.log(lorem); // 'ipsum'
console.log(foo);   // undefined

Because of this powerful and useful language feature a lot of people been using design patterns like the revealing module pattern to avoid polluting the global scope and to better organize their applications (including myself).

Private variables are usually a good thing since they avoid more problems than they cause, naming conflicts (two pieces of code using same name to store different info) can be very hard to track and it is very common to happen, that’s one of the main reasons why people use so many private variables, but like most things in life it also has it’s drawbacks and I’ll show a few cases where it can be an issue and how to avoid it.

Other languages

Java/C#/AS3/PHP have the concept of a protected class member, the protected member is like a private one but that can be overwritten by a child class. By using protected on all your members instead of using private you increase the flexibility of your code, if the user wants to change the default behavior of a method he can simply extend the class and overwrite it. The sad part is that private variables in JS can’t be overwritten, not even by child classes.

JavaScript is about monkey-patching

I saw this quote on Twitter a few weeks ago and I must agree:

Monkey patching in javascript is called “writing code.” – Paul Hummer

One of the greatest things about the language and what makes it so fun to code is that you can get very creative about how to solve certain problems, it gives you freedom enough to do to terrible and amazing things at the same time, you don’t feel as constrained as on a static strong-typed language…

Private variables are against monkey-patching and can make your code impossible to be reused/tweaked without a lot of manual work, one of the main reasons for that is because the variable is inside a scope that you can’t reach, not even if you extend the object, it’s like if all your variables and methods where private final (you can’t overwrite it by any means), and this process isn’t “scalable” at all.

Unit Testing

Another problem with private members is that it is harder to test them. I usually tend to think that private members doesn’t need to be tested since the public interface is already being tested, but sometimes that may not be the truth (think about a variable that holds state info or some property that needs to be swapped with a mock object). Exposing larger chunks of your codebase (as a pseudo-private member) may help you to increase your unit tests coverage and also to simplify the tests.

Solution

What I’ve been doing on some projects is to expose most of the methods and properties of objects that I know that are going to be reused in multiple projects (like open-source projects), if it isn’t meant to be called by other people or is subject to changes I simply start the name with an underscore (_), it’s a sign that you shouldn’t expect the function to be there forever (pseudo-private) but it allows the user to easily “hack” the original code to make it work as he want. I believe that code that is easy to edit is way more valuable than code that has lots of settings to try to fit all scenarios, there will be a always an edge case that isn’t covered or the application will be so complex/bloated that nobody will want to use it.

I’m not saying you should pollute the global scope with thousands of variables (ie. keep it as properties of an object, like if it was a namespace), but consider exposing things that you may want other people to be able to tweak/reuse, been doing it for a while and it saved me some headaches.

A real case where monkey-patching “saved the day”

I wanted to add JSON support to Syntastic Vim but JSONLint output contained multiple lines and making syntastic to understand the format was kinda tricky so I decided to do a pull request on JSONLint itself adding an option for toggling the error message format, if the method parseError wasn’t exposed on the lexer object the change could be way more complex. That’s the difference of taking 20min to release a new feature that affects 2 open-source projects (and that boosted my productivity a lot since now I can validate JSON files at each save) or taking 1 day or more or not even doing it…

A real example where private members made things more complex than needed

I wanted to generate HTML documentation for AMD-Utils based on a few markdown files that I had on the repository, just because it would be quicker to browse it, so I decided to code a simple generator that would read all the markdown files, process them and output to HTML. The only issue is that I got used to Github flavored markdown syntax and all my markdown files were written using this syntax, so I had to tweak the markdown parser a little bit to act like the way github renders the README files (it is not the same as the JavaScript preview) which means I had to do some pre-processing before showdown did “it’s magic” and also edit showdown source code to comment out a single line, yes, a single line!! Because Github doesn’t hard-wrap line breaks on README files while the JS preview does it.

If showdown exposed all the methods I could override the _FormParagraphs method or do some magic before and after the original _FormParagraphs() was called - basically convert all the line breaks into tokens before _FormParagraphs() and untokenize it afterwards - and I could keep the library as a normal npm dependency - so I could update it as long as they didn’t replaced the method functionality or renamed it - things could still go wrong but the “damage” would be controlled. It would also reduce the chance of updating the file without noticing that it had changes that diverged from the original lib (since the changes are on a separate file).

Another option would be to fork the project and add support for toggling the GFM settings, but that would take way more time than I wanted to spend and I would need to wait the change to be merged and pushed to npm (if the pull request was even accepted).

Conclusion

I’ve seen the same thing happening over and over again on many projects (in many different languages) and that’s why I’ve been favoring the “expose ALL the things” approach lately.

Notice that I still create many local variables and functions since it’s less verbose and not all code should/need to be heavily tweakable (I can edit the source code of my app as much as I want, no need to monkey-patch) but if you expect a lot of people to reuse your code please make it easier for them to patch it. You should warn people of the danger but assume they know what they are doing, we are all grown ups right?

Understand the reasoning behind a “best practice” so you can decide if it does apply to your case or not.

The goal of encapsulation is to enable a client to use an object without knowledge of its implementation. – @ploeh

@ploeh I like the exact way you phrased this, and I agree. Because encapsulation does not require *concealing* implementation details. – @ArvedSandstrom

That’s it!

Further Reading


Comments

I used to be against exposing everything but the reality is that if you want to use inheritance and reusable code this is the only way to go. Good article!

I can understand your frustration. As having to devise work arounds; not always hacks, are time consuming. This often is debated as what is practical.

But you should always strive towards best practices to prevent the global namespace pollution. The power of refactoring, is having the ability to revisit code which requires improvements in design.

Could it have been possible to insert a simple template method, which would allow descendants to override the method? yet keep it private from its utilization?

I've written a framework, and it has something like this:

In the core, I have the Inherit function..

function Inherit(child, parent) {
    var p = new parent();
    for (var method in p) {
        if (typeof child == 'function') child.prototype[method] = p[method];
        else child[method] = p[method];
    }
}

Then, I could have a parent "class":

function ParentClass() {
    var privateProperty = 'bar';
    this.publicProperty = 'foo';
    //private
    function privateMethod() {
        return 'foo';
    }
    //public
    this.publicMethod = function() {
        return 'bar';
    }
}

And the Child class would work like:

function ChildClass() {
    Inherit(this, ParentClass);
    console.log(this.publicMethod());
    console.log(this.publicProperty);
}

... It keeps both private and public intact.

@Michael you still have encapsulation since you are providing a set of methods and properties that you expect people to use and marking other members with an leading _ (eg. _myAwesomeVar)to say they shouldn't be used by regular users, you just won't block users from tweaking the internals, python does that and "nobody died because of that".

I strongly believe that hiding things unless necessary brings way more headaches than it solves. While developing AS3/PHP I probably updated my vars/fns from private to protected thousands of times and now that I'm doing JS I always find myself editing some legacy code to expose methods so I could override them, nowadays if I want the code to be reusable I "expose ALL the things" from the beginning, no more going back and forth with that crap... Information Hiding are very nice in theory but isn't exactly the best thing for code reuse / productivity. If a certain workflow/methodology causes more problems than it solves I prefer to avoid it... cheers.

@fezec "Best practices" are relative, it all depends on a series of things... I'm not saying you should pollute the global scope (name collision is too common), but I'm saying that if you want other people to inherit your classes and to be able to tweak them you shouldn't make the important methods/variables private, it is a methodology that was inherited from the Java school of thought without properly thinking about the drawbacks, I know many experienced devs that would agree that private is bad for code reuse, python for instance doesn't have private members and people still build complex stuff...

@Michael I think you misunderstood the post... try to override (or access) the private members from "inside" the ChildClass, it isn't possible since they are on an "unreachable scope"... you can't use the private members or override them, not even if you inherit the "class". PS, You don't need a "framework" for that and copying references to properties isn't the correct way of doing inheritance in JavaScript:

function ChildClass() {
    // using ctor.call(this) it will also "inherit" members added on the constructor
    ParentClass.call(this);
    console.log(this.publicMethod());
    console.log(this.publicProperty);
}
// if the ParentClass.prototype had methods/properties you could
// use Object.create() to "inherit" from it.
ChildClass.prototype = Object.create(ParentClass.prototype);

More about Object.create(), I have a slightly modified version amd-utils/lang/createObject() which also accepts some additional properties to be mixed-in the returned object. cheers.

PS: if you read Douglas Crockford article about prototypical inheritance you will see that you don't even need constructor functions, you can simple use a plain object as the prototype and use Object.create(props) as a replacement for calling new Foo(). So the ParentClass.call(this) is only really required if you are trying to mimic pseudo-classical inheritance.

Knowing how to balance things often produces better results than simply doing it by the book. Almost everything in life has exceptions, there's no point in being so strict with code.

@Miller You're right, I misunderstood. Are you saying you recommend always using public variables/functions or using them when you know it will be extended? If it's always, what becomes of encapsulation?

The framework does much more than just inheritance, but that Inherit method is one thing that is available. I will look into the call method though, thanks for that.

I thought a little bit about this post, and expand on it on my personal blog: http://blog.svpino.com/2012/01/case-in-favor-of-private-variables-and.html.

In resume, I'm not sure I totally agree with you. Going against private members is something I don't even want to think about it. Anyway, I see what's the point you are trying to make.

Thanks for the post.

Hey Miller, I think the "best practices" is a bit convoluted as a term, and I think that is what might have confused my statement. I do not disagree with you that programming needs to problem solve and you did in fact do just that.

What i am stating was the later half of my message which we did not touch upon.

"Could it have been possible to insert a simple template method, which would allow descendants to override the method? yet keep it private from its utilization?"

Design can be solved in a number of ways, in your case an easy solution was to reveal added methods.

But if the intention was for a developer to extend it then there are still designs which allows this to be possible without exposing the method entirely.

This is the idea of keeping something in the family.

Suggesting that because many experienced developers agree, is a loaded statement. Suggesting they wrote best practices is more likely to be accepted, but even if that were the case, everything must be challenged otherwise we'd get no where.

I admit private to public is a simple change. No argument here.. but is it merely the only solution.

Can't speak for JS, but in the AS/Java world, the focus on private members is an atrocity. It's causing me endless chagrin on trying to work with the Android framework, when trying to extend the original widgets - features I could add with a small change or fixes I could do with a couple of lines are impossible just because the members I need are not fucking accessible.

So thanks for the article, Miller.

I believe that code that is easy to edit is way more valuable than code that has lots of settings to try to fit all scenarios

That makes sense until it is a module that is used on large teams. My experience is that some devs will take the path of least resistance, whether it's due to lack of skill, or laziness. What may be easier for one dev could very well be a nightmare to the team in general. Exposing key variables can enable this behavior.

Locking down the expected behavior is a benefit to teams. At the same time, this could be seen as a hindrance to code sharing. But, giving one the option of hacking a pseudo-private variable doesn't help anything. Any updates to the module by the original author could break that hack, requiring rehacking.

The more transparent option is to simply fork the original module and merge the upgrades into your own as they are released. But as you suggested, it's a polarizing subject :)

I kinda like the Ruby model for this reason. All fields are private by default (and cannot be made public). Methods can be marked private pretty easily.

But Monkey Patching is still supported. Any private method can be got at if you want to, using uglier syntax. Object.send(name, arguments) Any field can be accessed from outside if you want to. Object.instance_variable_set(name, value)

So private exists and is respected. No one will accidentally use private. The default syntax will not let you get at it. But if you REALLY want to get at it, you can.

Thanks for the insightful article Miller; I think you really nailed it with Paul Hummer's quote in regards to the added flexibility that JavaScript offers the developer. In ActionScript I would have injected a factory instance into an object to handle instance creation; eg:

public function MyClient(factory : IThingyLoaderFactory) {
    _thingyLoaderFactory = factory;
}
public function loadSomething(url : String) : void {
    var myLoader : IThingyLoader = _thingyLoaderFactory.create();
    myLoader.load(url);
}

However, JavaScript give us the ability to simply mokey-patch a factory method which belongs to the class, eg:

MyClient.prototype = {
    loadSomething: function (url) {
        _createThingyLoader().load(url);
    },
    _createThingyLoader: function () {
        return new ThingyLoader();
    }
}
// Patching the ThingyLoader factory method
var client = new MyClient();
client._createThingyLoader = function () {
    return new EpicWidgetLoader();
};
client.loadSomething('http://example.org/');

I think it always comes down to playing up to the strengths of a language.

[...] A case against private variables and functions in JavaScript Tags: best practices, design patterns, javascript Comments (5) [...]

[...] A case against private variables and functions in JavaScript Tags: best practices, javascript, jquery Comments (0) [...]

I can see both sides of this argument, but what tilts me in favor of privacy by convention is the easy debugging. Checking MyApp._complexData on the console is much easier than setting a breakpoint and invoking something just to access a closure-bound variable.

Leave a Comment

Please post only comments that will add value to the content of this page. Please read the about page to understand the objective of this blog and the way I think about it. Thanks.

Comments are parsed as Markdown and you can use basic HTML tags (a, blockquote, cite, code, del, em, strong) but some code may be striped if not escaped (specially PHP and HTML tags that aren't on the list). Line and paragraph breaks automatic. Code blocks should be indented with 4 spaces.