Andrew is a UI developer at 99designs.

Andrew's articles

  1. Thinking in Components

    Web Components, React, Polymer, Flight — all are intended for building interface components. This is a different toolset from the big MVC and MVVM frameworks, and requires a different mindset when planning how you’ll implement your interface. While I still use models like MVC for server applications, I’m a dedicated convert to the benefits of a component approach for interface development. In this article I’ll outline how thinking in components differs from thinking in MVC and implement that approach in a real-world example.

    In my mind, the headspace for MVC design is “How do I model my business domain? How do I model the processes of interacting with that domain? How do I model the interface to facilitate those processes?”. It is my opinion that this headspace does not facilitate good component design. In fact it’s the polar opposite for how you should be thinking when you set out to break down an interface into composable components. At best you’ll end up with micro apps. At worst you’ll build God components. The last thing you want to do is model your business domain as components. What you should aim to model is the smallest abstract sections of interaction you can describe.

    Designing for Re-Use

    Instead of “How do I make this dismissible alert panel?”, ask yourself “If I was adding new HTML elements to facilitate this interaction, what would they be?”. I find this leads to components which are safely distanced from the business domain and inherently the most re-usable in different contexts.

    As another example, don’t make a Type-Ahead Help Search component that be used everywhere you want to allow searching the Help system, make a suggestive text input component that knows about the interactions involved in providing input suggestions. Then make a Help Search API data component that knows how to receive requests for data, interact with the Help Search API and broadcast results. Now your suggestive text input’s tests don’t need any mocking of APIs, and when you’re asked to add suggestions to a “tag” field, you can drop in your existing suggestive text input component, wire up a simple data component that talks to the tag API, and done!

    Practical Example – “Project List”

    For a concrete example, lets take a look at implementing a simple interface as isolated components. The following mockup is an extraction from 99designs 1-to-1 Projects system. While the UI has been drastically simplified, the JavaScript we’ll build up to is production code from our site at the time of writing. Here is the wireframe:

    Wireframe

    What we have is navigation between three lists of projects — Active, Drafts, and Archived. Each project has an action that can be performed on it — archiving an active project, deleting a draft, or re-activating an archived project. In app design thinking we’d start modeling a project and giving it methods like “archive” and “delete”, and a “status” property to track which of the three lists it belongs in. Bringing that line of reasoning to component design is exactly what we want to avoid, so we’re going to concern ourselves only with the interactions and what is needed to facilitate them.

    At the core of it we have an action per row. When that action is performed we want to remove the row from the list. Already we’ve shed any Project-specific domain knowledge! Further, we have a count with how many items are in each list. To restrain the scope of this article, we assume each page to be generated server-side, with the tab navigation causing a full page refresh. As we don’t need to force dependance on JavaScript, our action buttons will be form elements with submit event handlers that will asynchronously perform the form’s action and broadcast an event when it’s complete.

    Here’s some HTML for a single project row:

    [html]

  2. Need sticker designs for XYZ Co.

    View


  3. [/html]

    I’ll be using Flight to build our components. Flight is currently our default JS component library at 99designs for the reasons I outlined in my previous SitePoint JavaScript article.

    Here’s our AsyncForm component for handling the form submission and broadcasting an event:

    [js]
    define(function(require) {
    ‘use strict';

    var defineComponent = require(‘flight/lib/component’);

    function AsyncForm() {
    this.defaultAttrs({
    broadcastEvent: ‘uiFormProcessed’
    });

    this.after(‘initialize’, function() {
    this.on(this.node, ‘submit’, this.asyncSubmit.bind(this));
    });

    this.asyncSubmit = function(event) {
    event.preventDefault();
    $.ajax({
    ‘url': this.$node.attr(‘action’),
    ‘dataType': ‘json’,
    ‘data': this.$node.serializeArray(),
    ‘type': this.$node.attr(‘method’)
    }).done(function(response, data) {
    this.$node.trigger(this.attr.broadcastEvent, data);
    }.bind(this)).fail(function() {
    // error handling excluded for brevity
    });
    };
    }

    return defineComponent(AsyncForm);
    });
    [/js]

  4. Using GNU Make as a Front-end Development Build Tool

    The popularity of CSS preprocessors like Sass, and task runners like Grunt have made a build process an accepted part of front-end development. There’s no shortage of options or opinions in the task-runner/build-tool space, with the most popular being Grunt and Gulp. I write a decent amount of JavaScript at work and in personal projects, […]

  5. Flight is the Right Choice for Your Existing Website

    At the beginning of 2014 I’d never even considered using Twitter’s Flight JavaScript component framework, yet here I am unequivocally stating that it’s the right choice for your existing website, which I probably know nothing about. I’d better explain myself while you ready your pitchforks for the comments section.

    Let Me Paint You a Picture

    Flight is what Twitter is made with. Flight doesn’t get much press because its specialty isn’t fancy single page app demos with data binding, but for real world web apps built on primarily server-side codebases. Its design is entirely, and solely, components and events. There are no instance variables. There is no magic. Data components fire events to broadcast data, while UI components listen to data events and in turn fire their own UI events.

    Flight components are exceptionally decoupled, in no way “take over” your page (unlike Angular’s ng-app), and are by their decoupled nature very easy to test, to migrate to/from, and to refactor. The cognitive load of inheriting maintenance of existing Flight components or refactoring existing components is dramatically lower than what is possible with Backbone or Angular and you don’t end up leaking or duplicating domain logic into your app like you do with Backbone or any JS framework which includes models.

    Why Flight?

    Your team has been working on a website for a few years. It’s primarily driven by a server-side technology — Ruby, PHP, Python, .Net — and that’s where you’ve solved the real domain-specific problems. Many of these solutions are the reason for your site’s success. Along with these server-driven features, you’ve continually added more JavaScript enhancements for improved interaction, snappier interfaces, that sort of thing. Maybe it started as jQuery spaghetti gluing together other people’s plugins. Maybe there’s some jQueryUI in there or Backbone, Angular, or Ember that performs well enough in their isolated corners of the site.

    As these enhancements age and multiply, you start to notice a disturbing trend. While your business logic primarily lives on the server-side with its test suite and QA tooling (RIGHT?!), more and more is having to be replicated in the JavaScript layer. You don’t want to double up, but you have logic in your UI now and it needs to make the right decisions. Similarly, the custom components and formatting helpers you have accrued on the server need to be replicated on the client side to turn your API responses into correctly formatted views.

    So now you’re at a crossroads. Do you continue down this path, replicating logic across two codebases and risk them getting out of sync, or do you decide to refocus your energies on an API-backed “thick client” approach with one of the big JavaScript application frameworks?

    What about a third option – one that allows you to avoid rewriting your core business logic and view layer while giving you an extremely loosely coupled, lightweight JavaScript methodology that is highly testable, easy to understand and refactor, and most importantly allows to you gradually move from your mishmash of existing JavaScript features. What if this same alternative was just as easy to migrate away from if you one day decide it’s no longer the right fit, all the while allowing you to easily innovate by getting new ideas in front of your users quickly and with confidence that they’ll work as intended?

    Option three sounds good to me. So how does Flight propose to deliver these lofty promises?

  6. Social Bookmarking vs. Visual Clutter

    Some of our recent blog posts have ended up on the front page of Digg and del.icio.us, garnering a massive influx of traffic. Traffic spikes to webmasters are like the first taste of candy to a child — once you’ve had that taste, you want more, more, MORE!. Ahem. You get the picture. Following this, […]

  7. The Day Digg Ate Itself

    It’s been an interesting 24 hours for the darling of user-driven content, digg. Upon removing an item regarding the discovery of the processing key that unlocks AACS copy protection (used in both HD-DVD and Blu-Ray discs), digg was overwhelemed by a flood of angry users, submitting and digging more stories containing the now-legendary hexidecimal string. […]

  8. Losing REST over Ajax Errors?

    All too frequently, I see Ajax examples where the response is handled like this: (pseudo-code used for demonstration purposes) xhr.onreadystatechange = function() { if ( xhr.readyState == 4 ) { if (xhr.status == 200) { // Process returned data (eg: Parse XML). // Check status of result depending on custom/ad-hoc error detection. // — most […]