Posts tagged Single Responsibility Principle

Designing APIs is no walk in the park. In many instances, when your API becomes popular, it can be difficult or even impossible to change. Whether it’s a programming language or framework, a good API makes a world of difference for developers who use it.

Needless to say, an API needs to be simple. But what’s equally (or more) important is for an API to be simple to get started with. The point is, you need to have a low barrier to entry for new users. jQuery, as opposed to other JavaScript frameworks, does a fantastic job of allowing new developers to, not only become immediately productive with the framework, but also get excited about JavaScript development in general.

However, when not accompanied with good design principles, simplicity may lead to anti-patterns. For instance, the main strength of jQuery is perhaps one of its major weaknesses. The “kitchen sink” jQuery’s overloaded main method violates the single-responsibility principle of API design. It also violates another characteristic of good APIs; Self-documentation, though I’ll write a separate post on that at a later time. Consider the following use of jQuery’s main method below:

Obviously this function has multiple, vastly different responsibilities at this point. So, it’s best to actually separate out the responsibilities into different, self-documenting functions. And while jQuery appears to be overloading the function, it actually isn’t as there is no inherent overloading in JavaScript. After taking a deeper dive into the source code of jQuery, what’s actually happening is that jQuery is validating the arguments/parameters of the $(argument); call to determine which execution path to take. Here is what’s happening in (simplified) pseudo-code:

If argument is a “string”, then

check if argument is a selector and execute path

check if argument is html (regex) and execute path

If argument is an HTML Node, then execute path to wrap in jQuery object.

If argument is a function, then the “callback” path is taken for DOMReady.

This obviously increases the complexity of the code due to the presence of different execution paths. Thus, the maintainability of the code becomes a problem. Additionally, this impacts testing negatively as there are 7 different scenarios that could go wrong within the same function as opposed to one and only one. It is no surprise that jQuery has one of the highest cyclomatic complexity measures of most JavaScript frameworks out there. See image below (less is better).