Moving to a JavaScript Application Architecture

Preface

From 2003 to 2011 I became a pretty decent ActionScript developer. Starting with single frame movies then to fully structured MVC applications.

With my team, I’d spent a lot of time looking at two powerful frameworks   Cairngorm and RobotLegs. I really liked RobotLegs, and being my first introduction to dependency injection – was really intrigued.

I ended up writing my own framework based on RobotLegs called Nori. It was pretty slick – mediators, contexts, mapping, Signals, views and tons of interfaces (any DI system has). I only used it for a few projects before a career change and a transition to consulting and design / prototyping.

Fast forward a few years and I’m trying to break into coding again with JavaScript. I’d done a fair bit of JS dev in 2000-3, but really hadn’t paid much attention to it since then.

Holy shit!

I have a lot to learn.

Writing my own …

Over the past two years, I’ve spent (too much) time looking for a starting point – Angular, React, ExtJS, Ember, Dojo, etc. I didn’t have a project so I just cycled around in this framework limbo.

Then I found a project. Time to get realz …

My team needed a gallery to showcase our work and provide simple case studies to prospective clients. I’d build something similar to this before, in haXe, that was based on Microsoft’s Pivot experiment. I decided to recreate it but with more of a Pinterest influence.

The front end would be a fluid, responsive JavaScript application that also worked on our primary browser, IE9. It would also scale to mobile phones and be accessible though our corporate GOOD app.

The back end would use SharePoint lists. SharePoint is a decent backend for database challenged teams in big companies and it also comes with a “free” content maintenance system.

I couldn’t waste time researching frameworks anymore, and I had a strong desire to actually learn the language, so I decided to writing my own. My basic task list is/was:

  1. How the hell so I set this up and what build system do I use?
  2. How do I architect this thing? How can I best create class/subclasses and implement the command pattern?
  3. How do I create a global event system (pub/sub) system with command mapping?
  4. What’s cutting edge? FRP, Reactive programming and RxJS!

The project started in November as a part-time/between-other-work project. I’m wrapping up the front end now with the back end still to go. My purpose for this post, is to document my thought process and hopefully solicit some feedback on my approach.

Here’s a break down of what I’ve learned and done over the past few months. I know that it’s nearly useless without screen shots (source code on GitHub) but I’m working on that.

The project source is available on GitHub.

Project setup and build options

No respecting front-end dev writes HTML or CSS anymore. Attending Meet Ups around Charlotte, I saw how people were using Sass and Jade tempting. I have give the credit to the talented Tessa Harmon for introducing these to me at a Charlotte Front-End Developers meeting.

Both of these preprocessors resonated with me as being a much more efficient way to produce CSS and HTML – variables and mixins, oh my! The biggest challenge is working with these in a typically Windows based corporate environment. Lucky, I was able to get a Mac at work. I’ve been developing prototypes with Jade and Sass for a few years at this point with the excellent CodeKit app. On the Windows side, Prepros looks like a great alternative.

I’ve found the indented syntax style of Sass to be the best fit for me. Not only does it go very well with the style of Jade, it’s saves a ton of typing. The fewer braces and semicolons you need to worry about, the better.

I’d seen Grunt but hadn’t used it. Reading articles. like this one from Chris Coyier, really simplified the concepts. It was pretty easy to get it all up and running and enabled a much simpler build process than I was able to achieve with CodeKit. So I have SASS + Jade processing, CSS linting, CSS minification, JSLinting, JS concatenation + minification and live reload all working well.

Being able to work with JavaScript in a modular way, split across many files, is a critical workflow feature. I was used to splitting up my classes in to single files and I was able to preserve that with this process thanks to these tools.

Other libraries

I went back and forth on jQuery. On one hand, the efficiencies gained by utilizing it’s selector and DOM manipulation engines cannot be underestimated, but on the other – I wanted to learn how to do this on my own. In the end, I decided to use it, it just saves too much time.

Having to support IE9 meant that CSS animations were not possible. While developing in Flash, I relied heavily on the awesome GreenSock animation platform and with a JS version available, it was a no-brainer.

I’d struggled a bit with the view styling. Do animations count as “style” (CSS) or functionality (code)? I didn’t have a choice in this situation, but now I’m firmly on the side of code – the control and possibilities presented by JS animation libraries over CSS is too much to ignore.

To handle HTML templating, I compared Mustache.js and Underscore.js. Mustache provided a nice single purpose solution, but Underscore did all I needed it to plus provided a ton of additional functionality that I might need later on. So I went with it.

What’s next

  • Clean up my CSS classes by implementing the BEM system
  • Optimize my Grunt file.
  • Learn more about git and GitHub

OOP / classes, subclasses / structure / commands

I came from a strongly classed development environment. So naturally I wanted to recreate that in JS. But JS doesn’t do classes but it does do objects. I couldn’t use ES6 because of IE9.

Finding way to create namespaces was key and paired with the revealing module pattern, made for a great solution. I implemented the approach Kenneth Truyers documented for my application.

I do have a few global objects, for utility classes, but generally my application structure is:

All of the major parts of the app (bold, above) are constructed like this:

APP.createNameSpace('APP.AppController');
APP.AppController = function () {

// private var
// private methods

return {
// public api
};
}();

These are effectively singletons.

Commands

Both the Cairngorm and RobotLegs frameworks handled the heavy lifting of controller duties in commands. The separation of core functionality outside of the controller made extending the app very simple. Command classes are single responsibility, small and have access to all of the actors in the application.

My commands have a single entry point, an execute() method, that takes one object parameter for passing in data. In my framework, commands are only invoked in response to an event. For every command there is a corresponding event that is published from somewhere in the application. This is discussed in the Events section below.

In my current implementation, they’re synchronous, but I can see needing asynchronous in the future as I’m loading data from sources.

Pattern for subclasses – commands and subviews

To implement commands and sub views, I had to seek an alternate class/object creation pattern. Creating multiple instances of objects with the module pattern isn’t entirely straightforward. Although there are several methods of extending new objects with the properties of an existing object (jQuery’s extend(), etc.), the private methods of the closure aren’t readily accessible in the subclasses. Composition would be been a way to handle this, but I choose a different approach.

I discovered Eric Elliot’s Fluent JS talk on prototypal OO. His StampIt pattern was just what I was after, but I wanted a more accessible approach. I stumbled on an article by Jake Lucas which described a method just like Eric’s, but broke it down so that it was easier for a noob, like myself, to understand.

Using commands as an example, I have this as the abstract command class

APP.AppController.AbstractCommand = {
  state: {},

  methods: {

    app: APP,
    appController: APP.AppController,
    appModel: APP.AppModel,
    appView: APP.AppView,
    eventDispatcher: APP.EventDispatcher,

    execute: function(data) {
      console.log('Abstract command executing with data: '+data);
    }
  },

  closures: []
};

And then I create a new command instance by using a factory method to create a new object and then override the execute method of the new command

APP.createNameSpace('APP.AppController.ItemSelectCommand');
APP.AppController.ItemSelectCommand = APP.AppController.createCommand(APP.AppController.AbstractCommand);
APP.AppController.ItemSelectCommand.execute = function(data) {
  
// new implementation

};

A few disadvantages for this approach:

  1. Alternate coding style compared to the modules
  2. Lots of boilerplate to create the objects

What’s next

  • I’m not entirely satisfied with my approach on commands and subviews. I want to look at other ways to subclass modules.
  • Look at ES6 transpilers so that I can leverage these features now.

Event system (pub/sub)

A publish/subscribe system is key for maintaining loose coupling between components of the application. For my app, I wanted to create a global system similar to the EventDispatcher in AS3.

When I last coded AS3, I was heavily using Robert Penner’s Signals implementation over native events. His approach won me over especially consider the fragility of the “magic strings” naming of event types. They were easier to work with and implement than native events. There is a JS port of it that I initially used, but later decided that it wasn’t worth the additional overhead.

Looking to simplify my approach, I found a great example from Michaël Duerinckx on his blog. It demonstrated exactly what I needed and was straight forward. I created an object APP.Events.Events that stored all of my event strings as constants.

Generally, I’m using events to invoke an instance of a command class – there is 1:1 relationship – the APP.Events.ITEM_SELECT event has a corresponding APP.Controller.Command.ItemSelectCommand associated with it. This mapping is handled by an EventCommandMap class.

I had implemented a command mapping solution in my Nori AS3 framework that was based on Joel Hook’s Signal Command Map for RobotLegs and Omar Gonzalez’s for PureMVC. I greatly simplified my original approach and with some helpful hints from a friend, had it working with my EventDispatcher.

In the controller, commands are mapped like this:

mapCommand(APP.Events.ITEM_SELECT, APP.AppController.ItemSelectCommand);

And trigged like this (‘id’ being wrapped in an object and passed to the command’s execute() method):

_eventDispatcher.publish(APP.Events.ITEM_SELECT, id);

The command map handles determining what command class should be instantiated and executed.

What’s next

FRP!

Future State: FRP, Reactive programming and RxJS

Functional programming is the current hotness in JavaScript. Honestly FRP is still kind of a dark art to me, but it’s clearing up thanks to excellent articles explaining the concepts, libraries like RxJS from Microsoft and tutorials from Netflix.

While I’m not ready to architect a reactive application, I am using Array methods forEach, map, filter, etc. pretty heavily. There are some performance issues with these, but it’s completely worth it for code readability. I’m only dealing with up to hundreds of objects so I’m not likely to see these in my current implementation. But it does make filtering my data more sane:

function filterProperties() {
  _filterProperties.forEach(function(filter) {
    var props = [];
    _data.forEach(function(item) {
      if(item.hasOwnProperty(filter.filter)) {
        var itemPropVal = item[filter.filter];
        if(typeof itemPropVal === 'string') {
          props.push(itemPropVal);
        } else if(itemPropVal instanceof Array) {
          props = props.concat(itemPropVal);
        }
      }
    });
    filter.data = ArrayUtils.unique(props).sort();
    filter.menuData = getDataFormattedForMenu(filter.data);
  });
}

I’ve implemented RxJS for some events – primarily execution environment: browser, mouse, touch, etc. The pure simplicity of this approach is really cool. Just cool.

_itemOverStream = Rx.Observable.fromEvent(_containerEl[0], 'mouseover')
  .filter(filterForMouseEventsOnItems)
  .map(getMouseEventTargetID)
  .subscribe(function (id) {
    selectItemByID(id);
  });

I need to delve deeper in to this, replacing my events and turning my classes into RxJS emitters.

Wrap up

So that’s been my learning path for the past few months. I’ve omitted a few dead-ends and research for brevity (ha!). I still have the back end of this to work though, but I’ve a similar setup at another company so it shouldn’t be that difficult.

I’m going to write a few more posts on various aspects of this – my view components and looking at AMD/CommonJs or WebPack.

If you made it this far, please comment! I’m seeking advice on my approach and rationale.

Thanks for reading.

3 Comments

  1. You weren’t kidding Matt, this is a pretty massive post. Lots to digest.

    Thoughts:

    * On jQuery: if you don’t need it but like the convenience of the syntax, try Zepto (http://zeptojs.com/). Uses the same syntax, no support for anything older than IE9. If you’re truly going all-out on “app-iness”, esp with React/Flux, Angular, or similar, you prob wouldn’t need jQuery anyway.

    * On modularity: yes, but here is where you cross the line from ‘traditional’ JavaScript to ‘modern’ JavaScript — aka the kind of stuff the computer science majors came up with when they realized they were stuck with JavaScript on the front end. Personally I find it too overwhelming, and in many cases the code becomes overly complex despite the intent to keep it conceptually simple via ‘classes’. 10 files and 500 lines of code to do something that VanillaJS can (sometimes) do in one file and 200 lines of code (50 if you use jQuery! LOL). This was one of the big arguments between the ActionScript guys who were pushing for ECMAScript 4 and their detractors. (As you no doubt recall, ECMAScript 4 was partially derived from Adobe’s work in AS3, but ultimately scrapped in favor of a simpler approach in ECMAScript 5.) I’m kind of torn, because I see where the new generation is headed and it’s powerful stuff (React is a great example), but it’s so much more complex than the old days. What happened to the days of opening a text editor and being able to code an entire site by hand without any extra stuff? No preprocessors, build systems, template engines, etc. Basically it seems all the stuff we used to handle server-side has been pushed to the client.

    * On Underscore: I prefer lodash (https://lodash.com/). Started as a drop-in replacement for Underscore, with significant size and performance improvements. Lodash is pretty awesome.

    * On templating: It all depends what you’re trying to achieve, what your company is comfortable with, and what you prefer in terms of front end/back end relationships and code style. React and Angular are really meant for single-page apps like Facebook and Gmail. I don’t think they’re appropriate for company websites or (most) e-learning courses. (I’m sure someone will prove me wrong.) Deciding on a templating system also means deciding how you want to split the load between front and back end systems. Do you want to do most of the work on the front end or back end? If you choose front end, what data are you comfortable sending? E.g., wouldn’t be a big deal if it were a marketing site or personal web site, but if a quiz for an e-learning course were handled completely on the front end, it would potentially expose answers. If you choose back end, which server system plays nicest with your template system? Node? PHP? ASP.Net?

    One of my biggest concerns for the templating engines is accessibility. Same as when ajax first popped on the scene… ajax-based pages can be accessible, but it takes care. Same for the other systems. Don’t make assumptions.

    FWIW, we use a sprinkling of Handlebars in our latest e-learning course interface.

    * On pseudo-namespacing in JS: I used to do it heavily, modeled on the YUI system, but have slowed down recently. Some suggest keeping namespacing to a minimum — in JS, a namespace is really just a nested object. Deeper namespaces require more work by the JS engine to query the nested objects. Probably not as big of a deal nowadays with the amazing JS engines in today’s browsers, but food for thought. The most common practice is to wrap everything in self-executing anonymous functions to keep the global space clean. But this has drawbacks for debugging. You just can’t win!

    * On Grunt: I think it’s a pretty awesome tool, but I will be trying Gulp soon. Have heard it’s much simpler to set up. Both work well with SublimeText packages and NPM.

    * In general: All of these things are cool and kind of fun, but I ask myself: how long will they stick around? Which ones are just a flash in the pan? There are soooo many libraries out there. I standardized on MooTools a decade ago and now they’re toast. It’s fun when you’re doing a personal project, but for a company project, it’s very intimidating. And the landscape seems to change from month to month. I don’t know if it’s possible to stay fluent in (let alone keep abreast of) the latest stuff anymore.

    When picking a system for a work project, I would ask: Can anyone else at your company support/decipher it if you’re not available? Will you be working in a team? If so, does the team have the same interest/excitement about the selected technologies, or will they be resentful it’s being dropped in their laps? Does the library you’re using have a significant global community and active presence on GitHub (or wherever it’s hosted)?

    Speaking of GitHub, I’m not a big command-line guy, so I use Tower (www.git-tower.com). Really great. And they have excellent Git tutorial videos on their site, check it out.

    Speaking of personal projects, I’ve been using Node with ExpressJS for one of my personal projects. Pretty cool combination. I think you’d like it if you haven’t already tried it.

    Whew, that’s a long comment. Thanks for the post, it’s fun to chat about this stuff.

    Reply

    1. Wow! Thanks Philip, great comments …

      1. Zepto – from the site and StackOverflow, it doesn’t look like it’s supports anything <=IE10. I'm going to spend time to day and work all of the jQuery out of my system. I'd been putting this task off, so I'm going to pick it up now. I think I can chunk it up between meetings over the next few days. 2. Modularity / pseudo name spacing - I haven't read much about module approaches yet so I'm just working with the module patter and nested object name spaces. This still "feels" like working with AS3 classes. Still vanilla JS with no libs... I don't know if something like AMD, CommonJS will work for me really - for the kind of projects that I'd have at work, I don't think I'd ever need a module from the community (Bower, etc.) I do need to separate the parts I intend to be reusable into another name space and break dependancies - that'll be good enough for now. 3. Lowdash / templating - I've heard of it before and I'll check it out! My JS file is way too big now, after I remove jQuery, I'll take a hard look at this. All that I'm using it for is client side templating and if Handlebars significantly smaller, I can see using it. My use of templating is for dynamic content - generating the menus and grid of items from the data. 4. Grunt / Gulp - This is one of the hard thing about breaking in to this community - TOO MANY CHOICES! :) There is too much volatility with the frameworks to really pick one long term. If you're in an agency, there isn't much risk to pick the framework of the week and try it out, but making the decision in a company, where it will have an impact for years is difficult. That's a big reason why I went the plain JS route. WebStorm is an excellent IDE, should give it a go if you haven't. I has JS inspection, analysis, completion and support for Grunt and GIT built in. I set the project up with the GitHub GUI app and pointed WebStorm at the repo - you can push changes up to it with a few clicks in the IDE. It's really slick. We only have two JS developers on our team (including me!), so I'm trying to do things in a way that makes sense.

      Reply

Leave a Reply