You are viewing the Articles in the Object Oriented Design Category

Organizing Require JS Dependencies

When developing large scale web applications leveraging RequireJS, at times, even the most highly cohesive of modules will require quite a few other modules as dependencies. As such, maintaining the order of these dependencies can become somewhat tedious. Fortunately, RequireJS provides a means of simplifying how modules may define dependencies for such cases.

Ordering Dependencies

If we are to consider how a typical module definition specifies dependencies, it becomes clear that one must ensure each module dependency name and it’s corresponding definition function argument have been listed in the same order:

In the above example, jQuery, Underscore and Backbone are specified as the modules dependencies as a dependency names array passed as the first argument to define(). Once all dependencies have been loaded, the modules definition function is invoked; with each dependency passed in the same order in which they were defined in the dependency array.

From both a design and client implementation perspective, this one-to-one correlation between dependency ordering and definition function argument ordering makes perfect sense, of course, for it would obviously be extremely confusing otherwise. In general this is rarely a concern, though when a module has many dependencies it can become cumbersome.

Adding Dependencies

The necessary side effect of the dependency/argument ordering is that as other dependencies need to be added, time must be spent ordering and re-ordering dependencies if one takes care to group dependencies categorically in order to improve readability (e.g. models…, collections…, views…, etc.).

For example, consider the following:

If we were to decide that this module also needed, say, Handlebars, we could simply add the new dependency to the end of the dependencies array, and then just add it to the end of the factory function’s arguments as follows:

While the above approach will certainly work, it fails to aid in readability as Handlebars is grouped with the application specific dependencies – the Model and Collection, as opposed to being grouped with the module’s framework dependencies. This may seem like a trivial detail, however, considering code is typically read many more times than it is written, it makes sense to organize dependencies as they are added in order to save ourselves and others time in the future when viewing the dependencies.

And so, ideally a team would have an established pattern of grouping dependencies in some kind of logical order. For example, framework specific dependencies could be listed first, followed by application specific dependencies etc. This ordering could be as simple or complex as a team collectively decides, though I would recommend keeping it generally simple.

With this in mind we could improve the above example as follows:

Organizing Dependencies

If we are to consider the above example as being somewhat typical, then it becomes rather clear that with each new dependency added we will likely have to repeat the ordering process. Again, while this may seem insignificant, it can easily lead to exceptions being thrown if any dependencies are out of order.

Fortunately, RequireJS provides a simplified CommonJS wrapping implementation, or Sugar syntax, which can be used to solve such issues. This sytax (which will feel natural to those who use Node) allows one to simply provide a module’s definition function to the module’s define call, and specifiy require as a single argument, as follows:

Using this pattern, we can refactor the above example to be more easily managed as follows:

With this pattern of dependency mapping it becomes much easier to add and remove dependencies as needed, with the added benefit of reading much more naturally. This pattern also feels more familiar as it is similar to import directives in other languages.

Conclusion

Managing module dependencies in RequireJS is quite simple and becomes even simpler when leveraging the Sugar syntax described above. When doing so, it is important to keep in mind that this syntax relies on Function.prototype.toString(), which, while having good support in most modern browsers, does not provide predictable results in certain older browsers. However, as the documentation states, using an optimizer to normalize dependencies – such as the very powerful RequireJS Optimizer – will ensure this approach works across all browsers.

As a general rule of thumb, I typically use the Sugar syntax approach when there are more than 4-5 dependencies and have found it has simplified managing dependencies in modules rather nicely.

Decoupling Backbone Modules

One of the principle design philosophies I have advocated over the years, especially through various articles on this site, has been the importance of decoupling. And while I could go into significant detail to elaborate on the importance of decoupling, suffice it to say that all designs – from simple APIs to complex applications – can benefit considerably from a decoupled design; namely, with respect to testability, maintainability and reuse.

Decoupling in Backbone

Many of the examples which can be found around the web on Backbone are intentionally simple in that they focus on higher level concepts without diverging into specific implementation or design details. Of course, this makes sense in the context of basic examples and is certainly the right approach to take when explaining or learning something new. Once you get into real-world applications, though, one of the first things you’ll likely want to improve on is how modules communicate with each other; specifically, how modules can communicate without directly referencing one another.

As I have mentioned previously, Backbone is an extremely flexible framework, so there are many approaches one could take to facilitate the decoupling of modules in Backbone; the most common of which, and my preferred approach, is decoupling by way of events.

Basic Decoupling with Events

The simplest way to facilitate communication between discreet modules in Backbone is to have each module reference a shared event broker (a pub /sub implementation). Modules can register themselves to listen for events of interest with the broker, and modules can also communicate with other modules via events as needed. Implementing such an API in Backbone is amazingly simple, in fact, so much so that the documentation provides an example in the following one liner:

Essentially, the dispatcher simply clones (or alternately, extends) the Backbone.Events object. Different modules can reference the same dispatcher to publish and subscribe to events of interest. For example, consider the following:

In the above example, the Users Collection is completely decoupled from the UserEditor View, and vice-versa. Moreover, any module can subscribe to the 'users:add' event without having any knowledge of the module from which the event was published. Such a design is extremely flexible and can be leveraged to support any number of events and use-cases. The above example is rather simple; however, it demonstrates just how easy it is to decouple modules in Backbone with a shared EventBroker.

Namespacing Events

As can be seen in the previous example, the add event is prefixed with a users string followed by a colon. This is a common pattern used to namespace an event in order to ensure events with the same name which are used in different contexts do not conflict with one another. As a best practice, even if an application initially only has a few events, the events should be namespaced accordingly. Doing so will help to ensure that as an application grows in scope, adding additional events will not result in unintended behaviors.

A General Purpose EventBroker API

To help facilitate the decoupling of modules via namespaced events, I implemented a general purpose EventBroker which builds on the default implementation of the Backbone Events API, adding additional support for creating namespace specific EventBrokers and registering multiple events of interest for a given context.

Basic Usage

The EventBroker can be used directly to publish and subscribe to events of interest:

Creating namespaced EventBrokers

The EventBroker API can be used to create and retrieve any number of specific namespaced EventBrokers. A namespaced EventBroker ensures that all events are published and subscribed against a specific namespace.

Namespaced EventBrokers are retrieved via Backbone.EventBroker.get(namespace). If an EventBroker has not been created for the given namespace, it will be created and returned. All subsequent retrievals will return the same EventBroker instance for the specified namespace; i.e. only one unique EventBroker is created per namespace.

Since namespaced EventBrokers ensure events are only piped thru the EventBroker of the given namespace, it is not necessary to prefix event names with the specific namespace to which they belong. While this can simplify implementation code, you can still prefix event names to aid in readability if desired.

Registering Interests

Modules can register events of interest with an EventBroker via the default on method or the register method. The register method allows for registering multiple event/callback mappings for a given context in a manner similar to that of the events hash in a Backbone.View.

Alternately, Modules can simply define an “interests” property containing particular event/callback mappings of interests and register themselves with an EventBroker

For additional examples, see the backbone-eventbroker project on github.

Persisting Backbone Collections

Backbone.js provides a light-weight, extensible API which focuses primarily on general structure, and the utility of that structure, without requiring a rigid adherence to specific patterns or prescribing certain design philosophies. This focused approach affords developers a significant level of flexibility which can prove to be essential to the success of many modern client side web applications – especially when considering the challenges surrounding the ever changing landscape of the web.

Naturally, it follows that such flexibility imparts additional responsibility on the developer. In my experience with architectural frameworks in general, and Backbone in particular, many times this kind of trade off can be quite preferable.

Extending Backbone

As mentioned above, Backbone implements the essential building blocks necessary to provide general structure within an application. If a feature is needed which is not provided by default, by design, Backbone allows for easily extending the core APIs in order to implement additional features as needed. In fact, developers are encouraged to do so.

Perhaps a good example of this can be found in the need to persist collections in Backbone; that is, interestingly, while the Backbone Model API implements a default save method, the Backbone Collection does not provide a similar API for explicitly saving the models within a collection; that is, saving the collection itself. This feature may have been left out intentionally as part of an initial design decision, as there are some complexities to saving an entire collection as a general use-case; such as saving deltas, propagating saved state to models within the collection and so forth; or, perhaps it simply may have been an oversite. Regardless of the reason, in certain scenarios it can be useful to save an entire collection rather than saving each model individually – fortunately, given the flexibility of Backbone, writing an extension to implement this feature is quite simple.

The PersistableCollection

As a basic solution for saving a Backbone Collection, I wrote a general abstraction – PersistableCollection, which extends Backbone.Collection, implementing a default save method.

The PersistableCollection API is quite simple in that it essentially just implements a proxy which wraps the collection in a Backbone Model, and ensures there is only one proxy created per collection. The url and toJSON methods, respectively, of the proxy Model reference the url and toJSON methods of the collection to which the proxy is bound. You can either extend PersistableCollection or generate a proxy for an existing collection via the static createProxy method. Examples of each follow.

Using a PersistableCollection

A PersistableCollection can be instantiated and used directly, just like a Backbone.Collection:

Extending PersistableCollection

You can extend PersistableCollection and simply invoke save to persist the models in the collection:

Creating a proxy for an existing collection

An existing collection can be saved by creating a proxy for it:

The PersistableCollection can be used as a general extension for saving entire collections based on the representation of all models within the collection. If you are interested in extending it to account for more specific use-cases, you can simply override the default save implementation as needed.

You can find the gist for the source and spec here.

Testing Handlebars Helpers with Jasmine

For some time now, I have primarily been using logic-less templating solutions as they allow for a greater separation of concerns in comparison to many of their logic-based counterparts. By design, the decoupling of logic-less templates imparts greater overall maintainability in that templates become considerably less complex, and therefore, considerably easier to maintain and test.

Handlebars, my preferred logic-less templating engine, simplifies testing even further via it’s elegant Helper API. While Handlebars may not be the fastest templating solution available, I have found it to be the most testable, reusable and thus, maintainable.

Custom Handlebars Helpers

Since Handlebars is a logic-less templating engine, the interpolation of values which require logical operations and/or computed values is facilitated via Helpers. This design is quite nice in that template logic can be tested in isolation from the context in which it is used; i.e. the templates themselves. In addition to the common built-in Block Helpers, custom Helpers can easily be registering in order to encapsulate the logic used by your templates.

Registering Custom Helpers

Registering Custom Helpers is as simple as invoking Handlebars.registerHelper; passing the string name of the helper which is to be registered, followed by a callback which defines the actual helpers implementation.

Consider the following custom Helper example, which, given a string of text, replaces plain-text URLs with anchor tags:

(Gist)

As can be seen in the above example, custom Handlebars Helpers are registered outside the context of the templates in which they are used. This allows us to test our custom Helpers quite easily.

Testing Custom Helpers

Generally, I prefer to abstract testing custom Helpers specifically, and test the actual templates which use the Helpers independently from the Helpers. This allows for greater portability as it promotes reuse in that common custom Helpers (and their associated tests) can then be used across multiple projects, regardless of the templates which use them. While one can test Handlebars implementation code with any testing framework, in this example I will be using Jasmine.

Essentially, testing Custom Helpers is much the same as testing any other method. The only point to be noted is that we first need to reference the helper from the Handlebars.helpers namespace. Ideally this could be avoided as, should the namespace happen to change, so, too, will our tests need to change. That being said, the probability of such a change is unlikely.

Using the above example, in a Jasmine spec, the enhance helper can be referenced as follows:

Then we can test that the helper was registered:

We can then test any expectation. For example, the enhance helper should return a Handlebars.SafeString. We can test this as follows:

The enhance helper is expected to replace plain-text URLs with anchor tags. Before testing this, though, we should first test that it preserves existing markup. In order to test this use-case, we first need to access the return value from our custom Helper, we can do this by referencing the string property of the Handlebars.SafeString returned by our Helper:

Finally, we test that our enhance Helper replaces URLs with anchor tags using the above techniques:

(Gist)

We now have a complete test against our custom Helper, and all is green:
Custom Helper Spec
Note: The above Spec Runner is using the very nice jasmine.BootstrapReporter

And that’s all there is to it. You can fork the example at handlebars-helpers-jasmine.

Jasmine matchers for Sinon.JS

Lately I have been finding myself writing custom Jasmine matchers which wrap the Sinon.JS API as a convenience. After repeating this process quite a few times I took a step back to see if there was a similar solution already available.

After a brief search, I quickly came across jasmine-sinon which, to my surprise, provides a very similar matcher API to that which I had began implementing. This library really is quite nice as it essentially provides matchers for all common Sinon.JS spies, stubs and mocking use-cases. I am sure jasmine-sinon has saved many developers a lot of time by not having to write their own custom matchers as it has for me.

And so, if you are using both Jasmine and Sinon.JS, and find yourself writing convenience matchers to simplify Sinon.JS integration, jasmine-sinon is an excellent addition which compliments both and is certainly worth considering.

Function Overwriting in JavaScript

Whether intentional, or simply a by-product of it’s design, Javascript, being a dynamic language, allows for a level of expressiveness which most any seasoned programmer would come to appreciate. Javascript naturally provides the ability to implement some rather intriguing and quite unique patterns; one of which is the ability to overwrite a function at runtime.

Function Overwriting

Function Overwriting (also known as “Self-Defining Functions” or “Lazy Defining Functions”) provides a pattern which, as stated above, allows for overwriting a function’s definition at runtime. This can be accomplished from outside of the function, but also from within the function’s implementation itself.

For example, on occasion a function may need to perform some initial piece of work, after which, all subsequent invocations would result in unnecessarily re-executing the initialization code. Typically, this issue is addressed by storing initialization flags or refactoring the initialization code to another function. While such a design solves this problem, it does result in unnecessary code which will need to be maintained. In JavaScript, perhaps a different approach is in order: we can simply redefine the function after the initialization work has been completed.

A possible candidate use-case for Function Overwriting is Feature Detection as, detecting for specific feature support in the Browser typically only needs to be tested once, at which point subsequent tests are unnecessary.

Below is a basic example of implementing Function Overwritting in the context of an abstraction of the HTML5 Geolocation API.

Considerations

Since functions are objects in Javascript, it is important to keep in mind that if you add a property or method to a function (either statically or via the function’s prototype), and then overwrite the function, you will have effectively removed those properties or methods as well. Also, if the function is referenced by another variable, or by a method of another object, the initially defined implementation will be preserved and the overwriting process will not occur. As such, be mindful when implementing this pattern. As a general rule of thumb, I typically only implement Function Overwriting when the function being redefined is in a private scope.

Concluding Thoughts

As you can see, Function Overwriting provides a convenient facility for optimizing code execution at runtime. There are many use-cases for dynamically overwriting functions and, where appropriate, they can certainly provide value in terms of performance and code maintainability.

Below you can find an example which demonstrates two basic Function Overwriting implementations. Simply load the page and add some breakpoints in Firebug to test the execution paths; both before and after overwriting each function occurs, or you can simply view the source.
Example