this space intentionally left blank

June 12, 2013

Filed under: tech»web

Outward Vectors

I'm happy to say that Weir is now in a beta-ready state. You'll need a server capable of running NodeJS and PostgreSQL (for now), and you'll need an OPML file to populate the feed list (Google Takeout will accomodate you nicely with a subscriptions.xml if you're fleeing Reader). But if you pull from the repo and then follow the instructions in the readme file, everything should be in a good-enough state to fetch, read, and mark stories as read. Feedback would be awesome.

The front end for Weir is written using AngularJS, because it's supposed to be great for rapid development and I'm all about failing fast on this project. Indeed, getting the client-side application up and running has gone very quickly, but Angular itself takes some adjustment, especially if you're used to other JavaScript frameworks.

I'm not convinced that this is a bad thing. Predictions are a mug's game, but I suspect that future libraries are going to look a lot more like Angular than its competitors. Before I can explain why, we have to first look at the way client-side JavaScript has been traditionally organized, and then see how Angular works differently.

JavaScript MVC libraries, from Backbone to Ember, find themselves confronted with a language that's very different from the languages where Model-View-Controller philosophies evolved:

  • JavaScript has no privacy, and (until recently) no getters and setters. Between the two, it's hard to know if a given object has changed since the last redraw.
  • The DOM is not designed to be strongly linked with JavaScript data structures.
  • Multi-level inheritance of values is fine, but inheritance of behavior is a mess.
Despite these quirks, libraries are still designed as if JavaScript was similar to SmallTalk. They work around the differences by using manual getter and setter functions on Model classes, registering for DOM events inside View classes, and retemplating using templates when one or the other is changed.

This works--and is certainly a million times better than writing jQuery spaghetti code--but it's not what you'd call "clean." For example, here's some code written in an imaginary (but typical) library, just to update a simple list view: var Song = new Vertebrae.Model.extend({ title: { value: "" }, listens: { value: 0 }, file: { value: "" }, starred { value: false } }); var SongView = new Vertebrae.View.extend({ render: function() { var model = this.get("model"); var el = this.get("element"); el.find(".can-template").html( templates.song(model.toJSON())); var rev = model.get("review"); el.find(".cannot").val(rev); } });

That is a lot of boilerplate just to display a song (and it doesn't even include the templates, or loading the actual data). Heavy object classes are necessary so that the framework can be notified of changes--hence all the extend and get calls, as well as the awkward way of defining default values. In places, we can at least use templates, but we're still having to place them manually into the DOM. It's like a terrible parody of Java's worst bits glued onto jQuery.

In contrast, Angular uses regular JavaScript objects, written with normal JavaScript syntax, for its models. There are no getter or setter functions, unless you really want them: change an object, and if it is attached to the $scope variable, it will be scanned for changes automatically. And while you're not discouraged from using inheritance, you're not really encouraged to do so, either. Angular uses prototypal inheritance to manage values under the hood, but its developer-facing APIs tend to bear more resemblance to AMD or CommonJS modules. It feels like JavaScript, in other words.

On the other hand, Angular is all about augmenting HTML: although templates are available to ease re-use, an Angular page actually gets marked up using custom tags and attributes, then compiled and linked into components that respond instantly to the application's backing data. This is very forward-thinking--in fact, it's not dissimilar from the Extensible Web Manifesto, and I can dig that--but it definitely comes across as "magic" the first time that you use it. After years of logic-less template engines being popular, Angular stakes out a very different position.

Normally, I'm not a fan of magic in programming: it's hard to debug what you don't understand. In this case, the novelty of Angular's approach--and its undeniable effectiveness--overcame my skepticism, to the point where it's really grown on me. Using Angular makes me much more aware of the boilerplate that's required by the traditional MVC frameworks I use in my day job. Simple tasks require less code, and I don't feel like I'm fighting my way through thick layers of abstraction.

If there's a place where Angular still feels awkward, it's anything to do with the DOM. Angular will let you get access to elements of your page, but only reluctantly--it would really prefer that you only alter your model data and let the DOM react. Most of the time, this is fine: the less page manipulation I have to do, the happier I am. But there are some times when it is inevitable, such as when I'd like to perform deferred image loading, and those are definitely the ugliest parts of Weir's client code so far.

But here's the rub: if the web ecosystem teaches us anything, it's that you can always make a simple framework faster and more powerful, but people won't use an API that's clumsy and tiresome (see also: jQuery vs. pretty much everything else). Yes, DOM manipulation isn't great in Angular--they'll have to write some new directives, to cover the edge cases and holes. Yes, the object polling that Angular does is kind of scary, but browsers will add features like Object.observe() to make it faster overnight. Meanwhile, nothing's going to make those heavy Model and View classes any more fun to use.

There has been (and still is) a lot of time in the JavaScript community spent trying to make it work like something more familiar. That's how you end up with Coffeescript, or YUI, or all these MVC frameworks. Those projects have a place, and there are certainly times when I want something familiar, but it's also good to see tools (like Angular, Node, or D3) that are built around JavaScript weirdness. There hasn't been an oddball language with a profile this high in a long time, so let's shake things up while we've got the chance.

Past - Present