Refining Modern Web Development



Semantic Web Component Design: Radios, dropdowns, and tabs are the same thing

Early on in the rewrite of Appuri's portal that we started on after having a designer and development team from the MVP, and in our transition from Angular to Knockout, I was looking around at different widget / web component libraries and what I could leverage that would fit the designer's use cases and style, as well as a clean design.

One thing that always drove me nuts about our previous UI was a mismash of different components doing the same thing. We had ui-select2, ui-select from the Angular UI team, angular-multi-select for some multiselect cases, and a custom directive for radio-like toggle boxes.

Each control offered some little feature that another didn't (except ui-select2 which was just in code we didn't get around to refactoring yet). Why is this? All of them are trying to do the same thing on a higher semantic level: The user needs to pick an one (or more) options from this fixed set of options. How that looks is a styling concern.


Angular's module system fails at tracking dependencies properly

Angular, being a framework with a lot of solutions to a problem, forces users to use modules - a very good thing. However, rather than letting users choose their module and package system (RequireJS or Browserify or Webpack for loaders and AMD vs CommonJS vs Harmony for module formats), it brings in it's own module format, without a loader.

Defining a module looks like this

var module = angular.module('fruit-stand', ['raspberries', 'strawberries', 'apples'])
// define what the module is or has by calling methods on it

it also includes a dependency injection component, because, uh, that's what they use in Java so JavaScript needs one too, because modules can't be scoped or replaced in a dynamic, interpretted language right? Nevermind. Well here's how it works:


The 4th aspect in JavaScript MVC frameworks

Of the many JavaScript frameworks out there, they all have one core priciple - to structure your code in a Model-View-Whatever style:

  • Model: Your data as an object
  • Controller/ViewModel/Presenter/Whatever: the business logic of your app
  • View: The HTML templates for your app

    But after using a few (Knockout, Angular, Ember, and Backbone) I've noticed there's a forth component. It's the widgety type of logic - logic that isn't about your business, but extents the browser functionality - that cool datepicker, color picker, an awesome visualization with D3, maybe a 3D flip switch intstead of a checkbox. That stuff that is a DMZ to the DOM - Knockout's bindingHandlers, Angular's directives, and Handlebar helpers. They aren't about how you map your view model / controller to the DOM, but about extending the functionality of the DOM.

    Why call this out? Well frameworks don't exactly agree on this terminology. With Knockout and Angular, the view is HTML, as they use DOM-based templating. In Ember, Backbone, and other string-based templating languages, they often refer to the view as a piece of JavaScript, and templating is separate. Really the template should be called the view in their world, and the view is this 4th aspect, the widget aspect. Knockout and Angular have their bindingHandlers / directives that extend their templating functionality, which are much more analogous to Ember/Backbone/Batman/etc views.

    Why is this important? Keeping selector strings out of your controllers and view models is vital for the separation of concerns and tesability. Keeping this 4th aspect as the DMZ to the DOM helps to separate these concerns. Say you do have a complicated problem to solve in your app, and you come up with a cool way to visuallize it. You could put it all in one module... but now what happens when you release it and users don't like that widget and they want something more traditional? It will be harder to pull it out. Or the opposite where that widget is really awesome and you want to use it elsewhere... now lots of work to pull the business logic out. Let those two evolve independently and they grow and improve much more rapidly.