Blog Archive

Home
Mentoring

This post is in our Javascript Primer series, a collections of articles aimed at .Net and back-end developers who are transition to client-side UX development.  In a previous installment, the topic of publish-subscribe design pattern was featured, and this pattern fostered loosely coupled ViewModels.  It is recommended that you read that post as well, as this edition of our primer builds on those concepts.

A basic tenant to good programming is to break down activities to small components.  Smaller functions are easier to maintain.  In many instances the information that the users are working with is best presented in logical groups, dissected so that an improper decision can never be made.  A rich user interface may force you to break a larger object into several ViewModels.  But guess what?  If you need to break information down, will also need to re-assemble this information to transmit back to mother ship to be stored in your database.

Challenges for the ViewModels

There are several challenges ahead for you if need your ViewModels to communicate, and you want to retain the agility provided to you with loose coupling.  If you recall the architecture we established with the publish and subscribe design pattern, all our “pieces” are highly independent from one another.  But we now have a complication.  Independence also means blissful ignorance.  Each ViewModel only knows how to contribute their small portions of information for glorious “mother object”.  The best it can is yield up what it has and somehow, someway, something will piece things together.

Let’s consider a code example:

We have simple project tracker that has a name, a roster of workers and a calendar that displays each workers start date.  Each tab is serviced by a ViewModel.  The “Project Info” tab shares the project name information with “Team”.  The tab “Team” shares the project team data with both the “Project Info” and the “Timeline” tabs.  This is accomplished using the publish and subscribe pattern that was detailed in this post.  You should review that post is your are unfamiliar with postaljs or with the publish and subscribe design pattern.

The challenge here is that we want a “Save” button that will easily gather the data from each tab and save it our project object.   We also want this controlling activity to be flexible and allow each ViewModel to supply the data needed without too much orchestration: in other words, we just ask the ViewModel “What do you have for a project object”, and each ViewModel fulfills its responsibility.

Pipe and Filter Pattern For Chaining Events or Commands

Many of you with a background in server side application development may recognize the pipe and filter pattern.  Simply said, it is a way to chain a set of operations that are to be performed in succession.  This diagram is a depiction of the pipe and filter:

PipesAndFilters

The “Filter” is a function that performs one thing.  Our pipe is the “orchestrator” or directory in that it will forward to each filter as ordered.

For our purposes we will continue to use postaljs as our communication mechanism.  We’ll need a pipeline that will keep track of which filter to execute and forward data to each subsequent filter of the process chain.

var pipeline = {
  index: 0,
  filters: ["edit.getViewOneData","edit.getViewTwoData","edit.finalDestination"]
 };

The property “filters” contains the names of the postaljs topics that will kick off a function.  In this case we will need 3 subscriptions that listen for items listed in the “filters” array.  Each process step, or filter, will be executed in the order that listed in the “filters” array: in this case, “edit.getViewOneData” will be executed first.  The property “index” tracks which filter is being processed.  As each filter is executed, it will increment index, then use index to access the next topic in the chain of events.  Starting off the process is accomplished in this fashion:

// Now start up the pipeline, fire off the first step that will execute the first filter
 postal.publish({
  channel: "pipenfilter",
  topic: pipeline.filters[pipeline.index],
  data: pipeline
 });

//  A sample subscription.  This will be executed first since it is listed first in the pipeline.filters array
postal.subscribe({
  channel: "pipenfilter",
  topic: "edit.getViewOneData",
  callback: function (pipeline, env) {
    fetchViewOneData(pipeline);
}
 });

//  After filter performs, it needs to call the next filter in the chain<
var fetchViewOneData = function(pipeline){
  // ... perform activities with some data

  //  To forward to next step, increment the index
  pipeline.index++;

  //  Now forward to the next filter
  postal.publish({
    channel: "pipenfilter",
    topic: pipeline.filters[pipeline.index],
    data: pipeline
  });
};

For our particular scenario with the project UX above we will have to do a few simple things:

  1. The ViewModels “ProjectInfo”, “Budget” and “Team” will need subscriptions to a “pipenfilter” channel
  2. Each ViewModel will need a corresponding filter function, so the “Team” ViewModel will get a “fetchTeamFilter”
  3. Add an endpoint in our $(document).ready section to act as a controller for the pipeline process.  Since we don’t have a controller this logic can sit here.  Naturally for cleaner production code you’ll want to be a bit cleaner and place this in a controller object.

All of the addition changes are noted with a “New pipe and filter” comment, so you can search through the Javascript to see where the changes have been made.  Most of the updates are just a few lines, and the nice thing is that the code to forward to the next filter is the same each time.  Not much exciting stuff to be seen other than incrementing the index and passing the data to the next topic.

Where No One Has Gone Before (just sayin’)

Now that you can synchronize your data, assemble it back into a proper object, you can begin your next journey.  There’s many long term benefits here that you will begin to realize.  What if you need to add an additional ViewModel, or what if you need to change which ViewModel display the groupings of data?  Without our pipe and filter solution, you would need to change a lot of things.  With what we have described here, the most that have to do is to add an additional filter name to the pipeline list and make sure that your additional ViewModel functioned properly.  The other ViewModels are left untouched.

Another benefit is also be that you can control what functions are fired while allowing the ViewModels to do their thing.  What if you had a ViewModel that published changes to other ViewModels after it finished performing calculations.  By ordering the filters in the pipeline accordingly, you can allow the ViewModels to do that hard work and be assured that all aspects of your data is up to date.  Doing more with less code means you can test and maintain this code with confidence.

This is a continuation of the Javascript Primer series where we focus on topics essential for .Net or back-end developers or who are transitioning to Javascript and client side development.  Many of the topics covered in this series will be related to producing web apps running in the browser.  Some design patterns and practices are also application to NodeJS / server-side Javascript apps as well.

Keeping IT Together

One complaint that many have when embarking on applications of medium complexity is that organizing your code is difficult; indeed, even with frameworks you can still end up with giant god object that contains all data-bindings, algorithms, helpers methods.  If you take the attitude that Javascript is a second class, toy language where you simply store jQuery animation methods and AJAX calls, you quickly end up with files that can be 3-4000 lines long!  Maintaining that is beyond torture.

A common design pattern used to alleviate this issue is the Model View ViewModel (MVVM) pattern.  The goal of MVVM is to divide up the logic of your application into UX, business logic, and data-binding activities into discrete components.  KnockoutJS is a popular framework that supports this approach.  Addy Osmani’s “Design Patterns for Javascript” defines the primary components of MVVM, and it is great primer to read if you are unfamiliar with these terms.  For our purposes:

Model will contain the data elements, such as FirstName, LastName, etc.  Essentially this is a building block for your front-end that will “model” entities such as user, customer, project, etc.

ViewModel will contain the behavior for the UI.  This can be business logic, formatting of data, and bridge the gap between data coming from a server and what is useful for the user to interactive with.  The ViewModel will also use the Models.

View will be the html document.  This will also contain the directives for what to present to the user, and will interact with the ViewModel.

We Still Have A Problem

So even with the MVVM pattern at our disposal we still have to fight bloated ViewModels.  From here out we will use a sample project for our discussion where we want to maintain project information comprised of project name, project description, and project notes, team members and a simple timeline / calendar function.  Sounds straight forward enough.  On our UI we will have a tab for grouping of information, and as information changes on a tab, we want that information available in each subsequent tab.  Again, nothing too earth shattering here.  It should look something like this JSFiddle below.  (NOTE:  For the sake of this exercise all code has been placed in the Javascript section of our JSFiddle.  You should split your code into modules so they can easily managed).

Each tab on this screen has logical groupings of information.  For the sake of argument let’s say that we decide to implement this UI with just one ViewModel for all three tabs.  For databinding we will be using KnockoutJS,  Starting out we have just one ViewModel – ProjectViewModel – that handles all updates; more specifically, we can take advantage of the data-binding facilities here, so when a team member is added, we can detect this change and automatically execute and update to the calendar.

We have three tabs – “Project Info” is pretty simple, and it uses the computed observable teamSize to display the count of the project team. You note that any changes to “Project Name” will be reflected on the “Team” tab.   The tab Team allows you to add a team member.  To support updating the calendar with the team member start date we have create subscription to the projectTeam observable array.  The tab “Timeline” has a calendar that displays the team member start date, and this is updated each time we add a new team member.  Also, any changes to the number of team members will be reflected on the first tab, “Project Info”.

Indeed this works well, since we have the advantage of one ViewModel and can benefit from easily sharing one set of data between all three tabs, But we still have an issue should we start adding more functionality and increase the properties and functions in the ProjectViewModel.  Soon maintaining the ViewModel will become difficult, and testing discrete portions of functionality will rapidly become difficult.  We need to be able to isolate or reduce the impact that the alterations made to the ViewModels have on each other.  This means adhering to the principal of “loose coupling”.

So what does it mean for us to create a ViewModel per tab?  The biggest issue now will be communicating between each ViewModel, and as always, our mantra should be “Keep it simple.  Please.  Pretty please”. So how do we achieve communicating data updates without creating three ViewModels that are still highly dependent on the others?  Our solution is to implement a subscribe and publish message architecture.  While this sounds intimidating, this simply means we will create each ViewModel with a method – a “subscription” – that will wait for a message that has the data we need.  As a corollary, each ViewModel need a way to “publish” any changes to data that occurs.

Super Simple Message with PostalJS

PostalJS is a very simple messaging framework that facilitates sub / pub messaging in a unique way.  In particular, PostalJS allows us to set up a subscription that remains “ignorant” of how the message is generated.  There is no “pre-registration processes” to map out a route between ViewModels; on the contrary, your Javascript object simply declares that will update when a subscription arrives.  This also means that several ViewModels can subscribe to an event and the publisher doesn’t care.

Here is a brief sample taken from github:

var subscription = postal.subscribe({
        channel: "orders",
        topic: "item.add",
        callback: function(data, envelope) {
            // `data` is the data published by the publisher.
            // `envelope` is a wrapper around the data & contains
            // metadata about the message like the channel, topic,
            // timestamp and any other data which might have been
            // added by the sender.
        }
    });

postal.publish({
        channel: "orders",
        topic: "item.add",
        data: {
            sku: "AZDTF4346",
            qty: 21
        }
    });

Looks pretty cool.  And simple.  So for us, our ViewModels will remain ignorant of each other, and only are aware that someone, something has sent data to it.  Another nice by product is that should one of the ViewModels fail, the impact is greatly reduced.  So should the ViewModel with the calendar fail, the other tabs could still collect data and function.  Better yet, adding new features to a ViewModel is going to be easier to achieve since we can test in isolation, and if the new features do not interrupt our sub / pub messaging, we can feel confident that new changes can be rolled into production without bringing down the entire application. Let’s look at the results, then examine the changes to our app’s architecture.

A Brave New World

If you open the Javascript tab of the JSFiddle, you’ll see that we have broken up the ProjectViewModel into 3 ViewModels:  TeamViewModel, TimelineViewModel, and of course the remants of ProjectViewModel.  We’ll take the updates on at time, focusing on the feature in the UI and work back to the code.

Project Name As before, entering the project name in the “Project Info” tab updates the title in the “Team” tab.  Same as before, the update happens when the input box loses focus.  Now let’s focus on the code.  Open up the Javascript in the JSFiddle, and you’ll see some drastic changes.  In the ProjectViewModel we have created a Knockout trigger that publishes a message:

</pre>
<pre data-language="js">_projectName.subscribe(function(newValue){

        //    Now use PostalJS to push message out
        postal.publish({
            channel: "project",
            topic: "edit.projectNameChange",
            data: {
                projectName: _projectName()
            }
        });
    });

So what we are doing here telling Knockout “Anytime there is a change to the observable _projectName, fire off a function that publishes a piece of data with the new value of _projectName”.  That’s it.  ProjectViewModel has fulfilled its responsibility and told anyone who will listen that a change has taken place.  Now find the TeamViewModel object.  Here we have a subscription that waits for a message containing _projectName updates:

</pre>
<pre data-language="js">var projectNameChangeSubscription = postal.subscribe({
        channel: "project",
        topic: "edit.projectNameChange",
        callback: function(data, envelope) {
            _projectName(data.projectName);
        }
    });

We get the data, and merely update an observable on the TeamViewModel.  It should be apparent by now that neither ProjectViewModel nor TeamViewModel “know” about each.  ProjectViewModel says “_projectName update ready” and who can handle it, does so. TeamViewModel just grabs the update, uses it.  That’s it.  The messaging works by creating a “channel” – in this case “project” – further defines the message with a topic – “edit.projectNameChange”.  This means you can a single channel that support multiple topics and narrowly define your event messages.

ProjectTeam Update Play around with the “Team” tab and add some team members with different dates.  The operates just as before.  Under the hood, the code in TeamViewModel that handles the publishing is:

</pre>
<pre data-language="js">_projectTeam.subscribe(function(){
        //    this is how postaljs publishes events
        postal.publish({
            channel: "project",
            topic: "edit.teamUpdate",
            data: {
                projectTeam: ko.toJS(_projectTeam)
            }
        });

    });

As before, we are asking KnockoutJS to watch for changes to the _projectTeam array, and when a change occurs, we publish a different message.  The portion of code – topic: “edit.teamUpdate” distinguishes this event from the previous on.  We simply take our observableArray and convert it a plain Javascript script array and throw out to whoever wants it.  If you look in both ProjectViewModel and TimelineViewModel you’ll see subscriptions that handle this topic.  This brings us to another important aspect of messaging and postaljs’ strength:  should we want to add more ViewModels that need _projectTeam updates, we only need to subscribe to the topic “edit.teamUpdate”.  We could subscribe 50 more times if we wanted.  The publisher / source ViewModel does not need any alteration, and this achieves our goal of loose coupling.

What Are The Other Benefits?


Looking at our ViewModels, you may have noticed that we are exposing less in the return statements, and with each ViewModel handling less functionality they become simpler to read and maintain.  Imagine that the needed to support 20 different data entry input boxes – one monster ViewModel would have a huge return statement.  It makes it hard to keep things straight in one “god” class.

With PostalJS and event messaging we no longer need to expose an entry point in our objects for data to be passed.  The subscriptions allow the ViewModel to handle receiving update messages internally.  A quite common scenario would be responding to an AJAX update.  With PostalJS you can avoid calls to each ViewModel when new data arrives from the server.  Simply publish to the appropriate topic and let the ViewModels respond as they need.


ActiveEngine Software by ActiveEngine, LLC.