Chapter 1 - Web UI Component Architectures

If this was 2007, and you mentioned the term “web component”, something having to do with some kind of Java J2EE standard might come to mind. Apparently you could even get some kind of certification as a “web component” developer from Sun Microsystems. Now the term is in the process of being redefined as Java’s heyday as the web development language of choice is long over.

The “component” part of “web components” is well understood in the software development community. A definition pulled from Wikipedia describes a software component as “a software package, a web service, a web resource, or a module that encapsulates a set of related functions (or data)”. Another description from Wikipedia on component based software engineering:

Component-based software engineering (CBSE) (also known as component-based development (CBD)) is a branch of software engineering that emphasizes the separation of concerns in respect of the wide-ranging functionality available throughout a given software system. It is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. This practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software.

http://en.wikipedia.org/wiki/Component-based_software_engineering

Some of goals (benefits) of a software component as described above are that they be:

  • Reusable
  • Portable
  • Consumable
  • Consistent
  • Maintainable
  • Encapsulated
  • Loosely coupled
  • Quick to implement
  • Self describing (semantic)

Web Components are an emerging set of standards from the W3C to describe a way to create encapsulated, reusable blocks of UI presentation and behavior entirely with client side languages- HTML, JavaScript and CSS. Since 2006 or so various JavaScript widget toolkits (Dojo, ExtJS, YUI, AWT) have been doing this in one form or another. ExtJS inserts chunks of JavaScript created DOM based on widget configurations, the goal being to minimize the amount JavaScript a developer needs to know and write. AWT does the same, but starting from the server side. The Dojo toolkit adds the advantage of the developer being able to include the widgets declaratively as HTML markup. Other widget frameworks like YUI and jQuery UI required their widgets to be defined configured and included in the DOM imperatively. Most of these toolkits use a faux classical object oriented approach in which widgets can be “extensions” of other widget. All of these toolkits have drawbacks in one form or another.

Some drawbacks common to most first and second-generation JavaScript frameworks

  • Excessive code devoted to DOM querying, setting up event bindings, and repaints of the DOM following certain events.
  • Hard dependencies between the DOM html and JavaScript application code that requires maintenance of application logic in a dual tree fashion. This can be quite burdensome for larger apps and make testing difficult

One common denominator of these drawbacks is poor separation of concerns and failure to follow established design patterns at the component level.

Front-end design patterns have become well established at the application level. The better application frameworks and UI developers will apply these patterns including, but not limited to, Model-View-Controller (and its variants MVVM, MVP) separation, mediator, observer or publish and subscribe, inversion of control or dependency injection. This has done a tremendous job establishing JavaScript as a programming language to be taken seriously.

What is often overlooked, however, is that these same patterns are applicable at any level of the DOM node tree, not just at the page (<html>, <body>) level. The code that comprises the widget libraries that accompany many frameworks often has poor separation of concerns, and low functional transparency *.

The same can be said of much of the front-end code produced by large enterprise organizations. The demand for experienced front-end developers has far outstripped supply, and the non-technical management that often drives web-based projects has a tendency to trivialize the amount of planning and effort involved while rushing the projects toward production. The engineers and architects tasked with these projects are typically drafted against their will from server application environments, or cheap offshore contractors are sought. The path of least resistance is taken, and the resulting web applications suffer from code bloat, minimum quality necessary to render in a browsers, bad performance, and non-reusable, unmaintainable code.

In 2009 an engineer at Google, Miško Hevery, was on a UI project that had grown out of control with regards to time and code base. As a proposed solution he created in a few weeks what would eventually become AngularJS. His library took care of all the common boilerplate involved in DOM querying/manipulation and event binding. This allowed the code base to be drastically reduced and the engineers to focus specifically on the application logic and presentation.

This new JavaScript framework took a very different approach than the others at the time. In addition to hiding the DOM binding boilerplate, it also encouraged a high degree of functional transparency*, TDD or test-driven development, DRY meaning don’t repeat yourself and allowed dynamic DOM behavior to be included in HTML markup declaratively.

*For a discussion on functional or referential transparency see http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)

One of the most useful and powerful features of AngularJS are directives. AngularJS directives are a framework convention for creating custom extensions to HTML that can encapsulate both the view and behavior of a UI component such as a site search bar in a way that can limit external dependencies, as well as, providing for very flexible configuration parameters that any application or container level code may wish to provide.

The AngularJS team state that using AngularJS is a way to overcome the primary shortcoming of HTML, mainly that it was designed for static presentation not dynamic, data driven interaction and presentation- a key feature of today’s web. Because HTML has not evolved to provide dynamic presentation, JavaScript frameworks have risen to fill the gap, the most popular being jQuery.

jQuery gives us common boilerplate code for querying the DOM, binding and listening for user or browser events, and then imperatively updating or “re-painting” the DOM in response. This was great when web applications were simple. But web applications have grown very complex, and the boilerplate code can add up to thousands of lines of source mixed in with the actual application logic.

AngularJS removes the boilerplate, thus allowing JavaScript developers to opportunity to concentrate solely on the business logic of the application, and in a way that hard dependencies to the DOM are removed.

1.0 Basic comparison of jQuery and AngularJS


<!-- as a user types their name, show them their input in real time -->
<!-- the jQuery IMPERATIVE way -->
<form name="imperative">
  <label for="firstName">First name: </label>
  <input type="text" name="firstName" id="firstName">
  <span id="name-output"></span>
</form>

<script>
// we must tell jQuery to 
// a) register a keypress listener on the input element
// b) get the value of the input element in each keypress
// c) append that value to the span element
// and we must maintain HTML string values in our JavaScript
$(function(){
    // boilerplate: bind a listener
    $('#firstName').keypress(function(){
        // boilerplate: retrieve a model value
        var nameValue = $('#firstName').value();
        // boilerplate: paint the model value into the view
        $('#name-output').text(nameValue);
    });
});
</script>

<!-- the AngularJS DECLARATIVE way -->
<form name="declarative">
  <label for="firstName">First name: </label>
  <!-- the next two lines create the 2-way binding between the model and view -->
  <input type="text" name="firstName" id="firstName" ng-model="firstName">
  <span>{{firstName}}</span>
</form>

<script>
// As long as AngularJS is included in the page and we provide some 
// declarative annotations, no script needed!
// The input is data-bound to the output and AngularJS takes care of all 
// The imperative boilerplate automatically freeing the developer to 
// focus on the application.
</script>

AngularJS directives can be used to create re-usable, exportable UI components that are quite similar to the maturing W3C specification for Web Components. In fact, the AngularJS team intends for it to evolve towards supporting the new specification as browsers begin to support it.

A full section of this text title is devoted to discussion of Web Components, but for context here is the introduction from the W3C draft:

The component model for the Web (“Web Components”) consists of five pieces:

  1. Templates, which define chunks of markup that are inert but can be activated for use later.
  2. Decorators, which apply templates based on CSS selectors to affect rich visual and behavioral changes to documents.
  3. Custom Elements, which let authors define their own elements, with new tag names and new script interfaces.
  4. Shadow DOM, which encapsulates a DOM subtree for more reliable composition of user interface elements.
  5. Imports, which defines how templates, decorators and custom elements are packaged and loaded as a resource.

Each of these pieces is useful individually. When used in combination, Web Components enable Web application authors to define widgets with a level of visual richness and interactivity not possible with CSS alone, and ease of composition and reuse not possible with script libraries today.

See http://www.w3.org/TR/2013/WD-components-intro-20130606/ for the full introduction. Another key standard on the horizon for ECMA 6 is Object.observe(). Any JavaScript object will be able to listen and react to mutations of another object allowing for direct two-way binding between a data object and a view object. This will allow for model-driven-views (MDV). Data binding is a key feature of AngularJS, but it is currently accomplished via dirty checking at a much lower performance level. As with the Web Components specification, AngularJS will utilize Object.observe() as it is supported in browsers.

Key Patterns in UI Component Development

For a UI component such as a search widget, social icon box, or drop down menu to be re-usable it must have no application or page level dependencies. The same example from above can illustrate this point:

1.1 Basic comparison of jQuery and AngularJS


<!-- as a user types their name, show them their input in real time -->
<!-- the jQuery IMPERATIVE way -->
<form name="imperative">
  <label for="firstName">First name: </label>
  <input type="text" name="firstName" id="firstName">
  <span id="name-output"></span>
</form>

<script>
$(function(){
    // Notice how we must make sure the ID strings in both HTML
    // and JavaScript MUST match
    $('#firstName').keypress(function(){
        // boilerplate: retrieve a model value
        var nameValue = $('#firstName').value();
        // boilerplate: paint the model value into the view
        $('#name-output').text(nameValue);
    });
});
</script>

<!-- the AngularJS DECLARATIVE way -->
<form name="declarative">
  <label for="firstName">First name: </label>
  <!-- the next two lines create the 2-way binding between the model and view -->
  <input type="text" name="firstName" id="firstName" ng-model="firstName">
  <span>{{firstName}}</span>
</form>

<script>
// Because AngularJS hides the boilerplate, no DOM string references to maintain
// between HTML and JavaScript
</script>

In this example the need to keep the ID reference strings synced between HTML and code results in the business logic of the function being tightly coupled to the containing page. If the ID used in the HTML template happens to change perhaps when attempting to “re-use” the code in another area of the application, the function breaks.

Most experienced UI developers would consider this to be a bad programming practice, yet large enterprise web applications or web front-ends tend to be riddled with it- some to the degree that maintenance and upgrades are more costly in time and money then just starting over.

At the most basic level, this is an example of tight coupling between model and view, or between UI component and the containing page. For “high quality” UI components, meaning those that accomplish the goals listed earlier, the UI component should not know about anything outside of itself such as the page HTML. The component should provide an API for injecting the data and configuration in to it as its only source of dependencies, and a component should never have to communicate directly with another component when it performs some action. The component should perform a discreet business function for the application, and it should keep its own concerns separated for easy maintenance.

The following software design patterns applied to component development can help insure higher quality components.

MVC, MVP, MVVM, MVwhatever

For simplicity I’ll refer to MVC, model-view-controller, to illustrate this concept. The term MVC has become somewhat polluted due to excessive miss-use by marketing professionals, and there is much debate over correct definitions that can be applied to front-end development.

However, at a high level, the pattern refers to keeping a clean separation between the code in an application or component for the view or user interface presentation, the controller or the business logic, and the model or the data representation. Clean refers to limiting interdependencies between the three layers. Code written in this fashion is easier to maintain and upgrade, as any layer can be changed without affecting the rest of the code.

An in depth discussion of MV* and other front-end design patterns are beyond the scope of this book, but are very important to understand thoroughly. For in-depth treatment of the key patterns, I recommend Addy Osmani’s book Learning JavaScript Design Patterns - O’Reilly Media, Inc.

We will talk about MV* as implemented in AngularJS directives in the next chapter.

Dependency Injection (IOC)

Dependency Injection or Inversion of Control (IOC) became popular with the Spring framework for Java. In Java applications prior to the advent of Spring, the norm was to run the application in a very “heavy weight” container such as JBOSS. By “heavy weight” I am referring to an application that included the code and libraries for every common enterprise dependency the application might need. Application level dependencies were made available to any function by direct reference because they might be needed at some point.

The reality was that many of these enterprise application dependencies often went unused in the application. Regardless, the memory footprint of the JVM required to run these applications inside these enterprise containers were in the hundreds of megabytes to gigabyte range.

One of the primary goals of the Spring Framework was to “invert control” of the application from the container to the application itself by allowing the application to pick and choose loading only the dependencies it knows its going to need. This is typically accomplished, in part, by passing in the dependency references directly as function parameters. The benefits of this approach were multi-fold but two that stand out were massive reduction in code and memory required to run the application, and code that had a much higher degree of referential transparency which translates directly to higher maintainability and testability because outside references do not need to be changed accordingly or mocked for testing.

1.2 Dependency Injection in JavaScript


<script>
/* Assume this code is run in a web browser. This function has a hard dependency\
 on its containing environment which is a webbrowser. If the global reference fo\
r console is not found or if it does not have amethod  called "log" then we get \
a fatal error. Code of this nature is difficultto maintain or port. */
function containerDependent(){
    // console is a hard, global dependency - not good
    console.log( 'a message' );
}
/*This function has its dependency explicitly injected by the calling function. \
$log can refer to the console.log, stdout, /dev/null, or a testing mock. This fu\
nction is much easier to maintain and move around. It has a much higher degree o\
f functional or referential transparency. */
function dependencyInjected( $log ){
    $log('a message');
}
</script>

The same benefits of dependency injection apply to JavaScript and are a characteristic of functional programming style. AngularJS and its directives make heavy use of dependency injection as the preferred way of declaring what the outside dependencies for any directive might be.

Observer and Mediator Patterns

The observer pattern or a minor variant called publish and subscribe or Pub/Sub. Is a method of indirect communication between UI components. Since “high-quality” UI components should not know about what exists and what’s happening outside of themselves, how can they communicate significant events in their lifecycle? Similarly, how can a component receive vital information necessary to it’s functioning if it cannot reference another component directly?

The solution is for a component to shout about what is does blindly, and to listen in the same way. This is one of the most fundamental patterns in front-end development. Setting up a listener for an event, and invoking a function in response to the event with some information about the event is how the JavaScript we write can respond to mouse clicks, key presses, scrolling, or any custom event that might be defined. It is also fundamental for reacting to future events such as when an AJAX call returns some data (Promises and Deferreds).

By itself, the observer pattern is quite useful. But components that are designed to perform some type of business logic, can get polluted with event handling code.

This is where the Mediator pattern becomes useful. A mediator is a function or component whose job it is to know about the other components and facilitate communication between them. Mediators often act as event busses – listening for events and invoking other functions in response to such events.

Figure 1.0 Diagram of the Mediator Pattern

Module Pattern

The Module pattern in JavaScript in its most basic form is a self-executing function that:

  • Provides variable scope encapsulation
  • Imports any dependencies via function parameters
  • Exports it own functionality as a return statement

1.3 Basic Module Pattern Implementation


<script>
var MyModule = ( function( dependency ) {
    var myScopedVar = dependency || {};
    return {
        //module logic
    };
})(dependency);
</script>

Variable scope encapsulation (functional scope) is the only current way to prevent variable declarations from polluting the global namespace causing naming collisions- a epidemic among inexperienced front-end developers.

Dependency injection via function parameter is how we avoid hard coded outside dependencies within the function or module which can reduce its maintainability and portability.

Returning a function or object that encapsulates the business logic of the module is how we include the modules functionality and make it available in our library.

This describes the basic module pattern in JavaScript, but in practice libraries have taken this pattern and extended it to provide common APIs, global registration, and asynchronous loading. See CommonJS and AMD.

http://www.commonjs.org/

http://requirejs.org/docs/whyamd.html

Loose Coupling of Dependencies

These patterns are all key players in creating loosely coupled, modular front-end code that may function as a reusable UI component. AngularJS and AngularJS directives arguably employ these patterns in its UI component building blocks better than any other framework to date, and is one of the reasons for its immense popularity. The AngularJS framework API has provisions for defining discreet views, controllers, and data objects all encapsulated within a directive, which can be configured and invoked with simple declarative markup.

1.4 AngularJS Directive Skeleton


<!---- define the directive -->
<script>
    myLibrary.directive('searchBox', ['serviceDeps', function factory($_ref){
        return {
       //view
            template: '<div class="x-search-box">' +
                '<form ng-submit="submit()">' +
                '<input ng-model="searchString" type="text"' + 
                'id="x-search-input" ng-focus="focus()" ng-blur="blur()">' +
                '<div class="x-sprite-search" x-click="submit()"></div>' +
                '</form>' +
                '</div>',
            //controller
            controller: function(deps){
               //business logic here
            },
            //data
            scope: {},
            link: function postLink(scope, elm, attrs) {
                    var config = attrs.config;
            }
        };
    }]);
</script>

<!---invoke the directive -->
<search-box config=""></search-box>  

Summary

In this chapter we discussed UI components, some key attributes of high quality UI components, the key software design patterns that make these key attributes, and brief introductions to the new W3C Web Component specification and how we can model Web Components using AngularJS directives today.

In the next couple chapters we will dive deeper into AngularJS’ implementation of these key patterns in its directive API with a practical example.