Skip to content

Introduction

ChrisRus edited this page Nov 15, 2013 · 25 revisions

Object Namespace Manager (ONMjs) is a framework for building complex, decoupled, data-driven web applications using the Model-Store-Observe-Feedback-Signal (MSOFS) design pattern.

In essence, ONMjs is a generic object factory that leverages an external, developer-supplied, data model declaration to create, destroy, address, and manage instances of your data objects at the behest of your application at run-time. Unlike traditional object-oriented design approaches that encourage the encapsulation of data and the functions that operate on that data in classes, ONMjs encourages that these concerns be separated in order to promote the development of modular applications partitioned into discrete subsystems that depend only on your data model, and on ONMjs to affect inter-subsystem communication.

ONMjs supports the declaration of simple objects, hierarchical objects, extensible object collections, and even recursively-declared object structures using a simple ECMAScript object syntax. This provides considerable flexibility allowing for a wide range of potential uses.

Conceptually, this facility is similar to JSON Schema insofar as both technologies provide a means to declare the structure, and properties of JavaScript object hierarchies. However, ONMjs is not nearly as powerful (or nearly as complex) as JSON Schema and differs insofar as ONMjs data model declarations are typically annotated with arbitrary, application-specific meta-data that is passed through to your application logic that uses it, along with the actual data, to establish the context necessarily to present, transform, mutate... your data as required by your application.

ONMjs was created specifically to aid in the development of complex single-page HTML 5 client applications and derives from ongoing efforts to create a software modelling workbench akin to a CAD program in the browser that is based on a data model comprising dozens of complex linked objects, dozens of modes, and hundreds of interdependent views and must all be managed in client-side application logic to produce, ultimately, a big JSON string. Your problem does not need to be nearly so vexing to derive benefit from using ONMjs however.

The library comprises a small collection of objects (required) that may be used alone, or in combination with other libraries.

Additionally, ONMjs bundles a small collection of optional "Observer" plug-in routines that leverage ONMjs and the Knockout.js MVVM framework to provide a generic (as in data model independent) client UI. These are intended primarily as advanced examples but can be used directly in your own client code, or as the basis for writing your own "Observer" plug-ins.

Quick Facts

Download: http://onmjs.encapsule.org/

Benefits

Leveraging ONMjs in your web application saves time:

  • Reduces the friction inherent in team/parallel development:
    • Decouples application data and the meta-data that describes it.
    • Decouples application data and application logic.
    • Decouples application logic subsystems from one another.
  • Reduces complexity and defect rates.
  • Simplifies functional and unit testing.
  • Mitigates some of the risk of unanticipated design and feature changes.
  • Fosters re-use of your software intellectual property across products.

How It Works

ONMjs is based on a design pattern called Model-Store-Observe-Feedback-Signal (MSOFS) that borrows and blends concepts from many classic design patterns. The MSOFS moniker is a mnemonic intended to make it easy to remember the architectural structure of ONMjs-powered applications so that you can apply it effortlessly during the design phase of your project. See also: MSOFS Design Pattern

Lets dive right into code and see how MSOFS manifests as a collaboration between your application logic and the ONMjs library.

See also: Live ONMjs Examples on JSFIDDLE

    /* M O D E L */

    /* ONMjs requires that you model your data by creating a simple Javascript object. */
    simpleContactDataDeclaration = {
        jsonTag: "contact",
        ____label: "Contact",
        ____description: "Contact data objects are used to store a single person's information in an address book.",
        namespaceProperties: {
            userMutable: {
                name: {
                    defaultValue: ""
                },
                email: {
                    defaultValue: ""
                }
            }
        };

    /* Initialize ONMjs' run-time data model. */
    var contactDataModel = new ONMjs.Model(simpleContactDataModel);

    /* S T O R E */

    /* The model is just meta-data. We want actual data! Create an ONMjs store bound to your run-time model. */
    var contactDataStore = new ONMjs.Store(contactDataModel);

    /* O B S E R V E */

    /* Applications that leverage ONMjs react to signals alerting them to changes in ONMjs-managed data. */
    var simpleReactor = {
        callbackInterface: {
            onNamespaceUpdated: function(store, address, observerId) {
                /* De-reference the data using the context passed to us by ONMjs. */
                var dataActual = store.openNamespace(address).data()
                /* It's not uncommon for Observers to affect "feedback" (i.e. mutating the data). Here we just pop an alert. */
                alert("Contact data has been updated! The new contact is: " + dataActual.name + " (" + dataActual.email + ").");
            }
    };

    /* Inform ONMjs that we want to monitor data changes to the 'contactDataStore'. */
    var observerId = contactDataStore.registerObserver(simpleReactor.callbackInterface, simpleReactor);

    /* F E E D B A C K */

    /* All ONMjs-managed data is addressable. Create an address that references the 'contact' data object. */
    var contactAddress = ONMjs.address.CreateFromPath(contactDataModel, "contact");

    /* Now that we have an address, we can get at the actual data. */
    var contactNamespace = contactDataStore.openNamespace(contactAddress);

    /* The 'contactNamespace' variable is a reference to an ONMjs.Namespace object. Deference the actual data. */
    var actualContactData = contactNamespace.data()

    /* Write some new data into the contact data. */
    actualContactData.name = "Chris Russell"
    actualContactData.email = "[email protected]"

    /* S I G N A L */
                
    /* Okay - we're all hooked up. Let ONMjs know we're done updating the data. */
    contactNamespace.update()

Executing this code will create an alert dialog box:

Contact updated alert

Admittedly this is a lot of code to write to accomplish something that is actually trivial. What you need to understand however is that this dumb example demonstrates the generic MSOFS pattern which can be applied over and over again to divide huge problems into little problems that can all be addressed using variations of this simple example.


Copyright (C) 2013 Christopher D. Russell