Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I want to ask – I am slowly learning jQuery.

What I see is an exact example of a God Object anti-pattern. Basically, everything goes to the $ function, whatever it is.

Am I right and is jQuery really an example of this anti-pattern?

share|improve this question
9  
You're probably asking the wrong question. The right question is, "How could jQuery be satisfactorily implemented in the Javascript language in a way that doesn't require the $ function or a jQuery object. –  Robert Harvey Dec 16 '12 at 6:49
1  
I always wanted to ask this question really :). –  AnyOne Dec 16 '12 at 21:32
    
@RobertHarvey: sadly, I don't know enough about JavaScript to answer this. –  Karel Bílek Dec 17 '12 at 0:00
    
Yes (12 more characters to go...) –  Andrea Feb 18 at 10:00

4 Answers 4

up vote 50 down vote accepted

To answer that question, I'm going to ask you a rhetorical question about another structure that have similar property to the DOM elements that jQuery manipulates, that is the good old iterator. The question is:

How many operation do you need on a simple iterator?

The question can be answered easily by looking at any Iterator API in a given language. You need 3 methods:

  1. Get the current value
  2. Move the iterator to the next element
  3. Check if the Iterator has more elements

That's all you need. If you can perform those 3 operations, you can go trough any sequence of elements.

But that is not only what you usually want to do with a sequence of elements, is it? You usually have a much higher level goal to achieve. You may want to do something with every element, you may want to filter them according to some condition, or one of several other methods. See the IEnumerable interface in the LINQ library in .NET for more examples.

Do you see how many there are? And that is just a subset of all the methods they could have put on the IEnumerable interface, because you usually combine them to achieve even higher goals.

But here is the twist. Those methods are not on the IEnumerable interface. They are simple utility methods that actually take a IEnumerable as input and do something with it. So while in the C# language it feels like there are a bajillion methods on the IEnumerable interface, IEnumerable is not a god object.


Now back to jQuery. Lets ask that question again, this time with a DOM element.

How many operation do you need on a DOM element?

Again the answer is pretty straightforward. All the methods you need are methods to read/modify the attributes and the child elements. That's about it. Everything thing else is only a combination of those basic operations.

But how much higher level stuff would you want to do with a DOM elements? Well, same as an Iterator: a bajillion different things. And that's where jQuery comes in. jQuery, in essence provide two things:

  1. A very nice collections of utilities methods that you may want to call on a DOM element, and;
  2. Syntactic sugar so that using it is a much better experience than using the standard DOM API.

If you take out the sugared form, you realise that jQuery could easily have been written as a bunch of functions that select/modify DOM elements. For example:

$("#body").html("<p>hello</p>");

...could have been written as:

html($("#body"), "<p>hello</p>");

Semantically it's the exact same thing. However the first form has the big advantage that the order left-to-right of the statements follow the order the operations will be executed. The second start in the middle, which makes for very hard to read code if you combine lots of operations together.

So what does it all mean? That jQuery (like LINQ) is not the God object anti-pattern. It's instead a case of a very respected pattern called the Decorator.


But then again, what about the override of $ to do all those different things? Well, that is just syntactic sugar really. All the calls to $ and its derivatives like $.getJson() are completely different things that just happen to share similar names so that you can immediately feel that they belong to jQuery. $ performs one and only one task: let you have an easily recognizable starting point to use jQuery. And all those methods that you can call on a jQuery object are not a symptom of a god object. They are simply different utility functions that each perform one and only thing on a DOM element passed as an argument. The .dot notation is only here because it make writing code easier.

share|improve this answer
2  
A really nice answer. Thanks. –  Karel Bílek Dec 16 '12 at 6:52
3  
A decorated object that has hundreds of added methods is a great example of a God Object. The fact that it decorates a well-designed object with a reasonable set of methods is the proof you need. –  Ross Patterson Dec 16 '12 at 15:25
1  
@RossPatterson Are you disagreeing? If you are, I'd encourage you to post your own answer. I think Laurent's is good, but I'm still undecided. –  NickC Dec 16 '12 at 22:39
    
@RossPatterson I assume your comment mean that this a case where it is a God Object but it is a good thing. Am I mistaken? –  Laurent Bourgault-Roy Dec 17 '12 at 5:11
2  
@LaurentBourgault-Roy I disagree with your conclusion - I believe jQuery is indeed a God Object example. But you did such a fine job that I can't bear to downvote your answer. Thanks for a great explanation of your position. –  Ross Patterson Dec 17 '12 at 11:47

No - the $ function is actually only overloaded for three tasks. Everything else are child functions that just use it as a namespace.

share|improve this answer
15  
But it returns a "jQuery" object which contains much of the jQuery API -- and, I think, would be the "God" object the OP is referring to. –  NickC Dec 16 '12 at 0:02
1  
@NickC, even though it's an object, in that case I think it's indeed used as a namespace, just like Math. Since there's no build-in namespace in JS, they just use an object for that. Although I'm not sure what the alternative would be? Put all the functions and properties in the global namespace? –  this.lau_ Jan 12 '13 at 5:49

The main jQuery function (e.g. $("div a")) is essentially a factory method that returns an instance of the jQuery type that represents a collection of DOM elements.

These instances of the jQuery type have a large number of DOM manipulation methods available which operate on the DOM elements represented by the instance. While this could conceivably be considered a class that's grown too large, it doesn't really fit the God Object pattern.

Finally, as Michael Borgwardt mentions, there are also a large number of utility functions that use $ as a namespace and are only tangentially related to the DOM collection jQuery objects.

share|improve this answer
1  
Why doesn't it fit the God Object pattern? –  Benjamin Hodgson Feb 17 at 20:46

Benjamin asked me to clarify my position, so I edited my previous post and added further thoughts.

Bob Martin is the author of a great book titled as Clean Code. In that book there is a chapter (Chapter 6.) called Objects and Data structures, which he discusses the most important differences between objects and data structures and claims that we have to choose between them, because mixing them is a very bad idea.

This confusion sometimes leads to unfortunate hybrid structures that are half object and half data structure. They have functions that do significant things, and they also have either public variables or public accessors and mutators that, for all intents and purposes, make the private variables public, tempting other external functions to use those variables the way a procedural program would use a data structure.4 Such hybrids make it hard to add new functions but also make it hard to add new data structures. They are the worst of both worlds. Avoid creating them. They are indicative of a muddled design whose authors are unsure of—or worse, ignorant of—whether they need protection from functions or types.

I think DOM is an example of these object and data structure hybrids. For example by DOM we write codes like this:

el.appendChild(node);
el.childNodes;
// bleeding internals

el.setAttribute(attr, val);
el.attributes;
// bleeding internals

el.style.color;
// at least this is okay

el = document.createElement(tag);
doc = document.implementation.createHTMLDocument();
// document is both a factory and a tree root

DOM should be clearly a data structure instead of a hybrid.

el.childNodes.add(node);
// or el.childNodes[el.childNodes.length] = node;
el.childNodes;

el.attributes.put(attr, val);
// or el.attributes[attr] = val;
el.attributes;

el.style.get("color"); 
// or el.style.color;

factory = new HtmlNodeFactory();
el = factory.createElement(document, tag);
doc = factory.createDocument();

The jQuery framework is a bunch of procedures, which can select and modify a collection of DOM nodes and do many other things. As Laurent pointed out in his post, jQuery is something like this under the hood:

html(select("#body"), "<p>hello</p>");

The developers of jQuery merged all of these procedures into a single class, which is responsible for all of the features listed above. So it clearly violates the Single Responsibility Principle and so it is a god object. The only thing because it does not break anything, because it is a single standalone class which works on a single data structure (the collection of DOM nodes). If we would add jQuery subclasses or another data structure the project would collapse very fast. So I don't think we can talk about oo by jQuery it's rather procedural than oo despite the fact that it defines a class.

What Laurent claims is a complete nonsense:

So what does it all mean? That jQuery (like LINQ) is not the God object anti-pattern. It's instead a case of a very respected pattern called the Decorator.

The Decorator pattern is about adding new functionality by keeping the interface and not modifying existing classes. For example:

You can define 2 classes which implements the same interface, but with a completely different implementation:

/**
 * @interface
 */
var Something = function (){};
/**
 * @argument {string} arg1 The first argument.
 * @argument {string} arg2 The second argument.
 */
Something.prototype.doSomething = function (arg1, arg2){};

/**
 * @class
 * @implements {Something}
 */
var A = function (){
    // ...
};
/**
 * @argument {string} arg1 The first argument.
 * @argument {string} arg2 The second argument.
 */
A.prototype.doSomething = function (arg1, arg2){
    // doSomething implementation of A
};

/**
 * @class
 * @implements {Something}
 */
var B = function (){
    // ...
};
/**
 * @argument {string} arg1 The first argument.
 * @argument {string} arg2 The second argument.
 */
B.prototype.doSomething = function (arg1, arg2){
    // doSomething implementation of B
    // it is completely different from the implementation of A
    // that's why it cannot be a sub-class of A
};

If you have methods which use the common interface only, then you can define one or more Decorator instead of copy-pasting the same code between A and B. You can use these decorators even in a nested structure.

/**
 * @class
 * @implements {Something}
 * @argument {Something} something The decorated object.
 */
var SomethingDecorator = function (something){
    this.something = something;
    // ...
};

/**
 * @argument {string} arg1 The first argument.
 * @argument {string} arg2 The second argument.
 */
SomethingDecorator.prototype.doSomething = function (arg1, arg2){
    return this.something.doSomething(arg1, arg2);
};

/**
 * A new method which can be common by A and B. 
 * 
 * @argument {function} done The callback.
 * @argument {string} arg1 The first argument.
 * @argument {string} arg2 The second argument.
 */
SomethingDecorator.prototype.doSomethingDelayed = function (done, arg1, arg2){
    var err, res;
    setTimeout(function (){
        try {
            res = this.doSomething(o.arg1, o.arg2);
        } catch (e) {
            err = e;
        }
        callback(err, res);
    }, 1000);
};

So you can substitute the original instances with the decorator instances in higher abstraction level code.

function decorateWithManyFeatures(something){
    var d1 = new SomethingDecorator(something);
    var d2 = new AnotherSomethingDecorator(d1);
    // ...
    return dn;
}

var a = new A();
var b = new B();
var decoratedA = decorateWithManyFeatures(a);
var decoratedB = decorateWithManyFeatures(b);

decoratedA.doSomethingDelayed(...);
decoratedB.doSomethingDelayed(...);

The conclusion that jQuery is not a Decorator of anything, because it does not implements the same interface as Array, NodeList or any other DOM object. It implements it's own interface. The modules are not used as Decorators as well, they simply override the original prototype. So the Decorator pattern is not used in the whole jQuery lib. The jQuery class is simply a huge adapter which let us use the same API by many different browsers. From oo perspective it is a complete mess, but that does not really matter, it works well, and we use it.

share|improve this answer
    
You seem to be arguing that the use of infix methods is the key different between OO code and procedural code. I don't think this is true. Could you clarify your position? –  Benjamin Hodgson Feb 17 at 20:48
    
@BenjaminHodgson What do you mean under "infix method"? –  inf3rno Feb 18 at 5:32
    
@BenjaminHodgson I clarified. I hope it is clear now. –  inf3rno Feb 18 at 8:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.