Skip to content

Instantly share code, notes, and snippets.

@esmooov
Created August 2, 2011 15:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save esmooov/42eaa55f4261c41355e9 to your computer and use it in GitHub Desktop.
Save esmooov/42eaa55f4261c41355e9 to your computer and use it in GitHub Desktop.

Frontpages are hard

Managing the frontpage of a news site is hard. On the shoulders of the frontpage editor is a chaotic mantle of demands. His layout must pithily narrativize the news of the day. It needs to command a hierarchy giving serious stories gravity and suggesting that that cat slideshows and cleavage are put on the frontpage outside the sagacious decencies of the editors -- "Hey, we can't help it. An ALGORITHM put them there." The frontpage needs to seem constantly in flux or readers will complain that the site seems staid, dead. It also needs to look good, attract new readers, make old ones feel at home and perform a host of other duties.

Fortunately, we have completely inadequate tools for this. As I mentioned in the last nerd blog post, our bleeding edge solution was to have a bunch of numbers that corresponded to positions on the frontpage. Then we would meticulously match them up with a manifest of dropdown menus and headlines. Of course, we had to create new entries for this matchmaking in a separate blog from our main one. These other entries housed our clever bon mots and frontpage pictures. How did we get well-fitting headlines, nicely harmonious pages? How did we do this quickly? How did our editors not go crazy in the hideous tedium and isolation of being the only initiate capable of keeping our shambling golem of an index on its two feet? We didn't, it took forever, and a lot of people became TPM alumni.

Though truly sad, TPM was not unique in our plight. Having seen the CMSes of several other leading news sites, I can assure you, dear reader, the problem is widespread. Oceans of tabs, forms, fields, dropdowns and other - less standard - UI elements struggle to hang together as tongue-depressor-and-glue abstractions of frontpage news. This complexity makes it difficult to tell stories - how can you focus on the holistic page when you are concentrating on the minutiae of the analog. These wayward interfaces make simple design tasks like weeding out widows and orphans a chore. Their analytic overheard burn out editors.

We needed a better solution.

If it ain't Baroque ...

This was the inspiration behind the frontpage app that we have been developing since January and has been in production since the beginning of July, Baroque. The spec for the app was simple and guided by three principles: the idea of play, little or no abstraction, and a small learning curve.

First, design -- though grounded in the rigors such as geometry, history, and philosophy -- needs the freedom of play to work. This is why we sketch. By being able to easily test alternatives and oscillating between choices, we can drive a line through complicated problems of presentation, of story telling. We knew that Baroque had to allow for immediate feedback of changes without any ad-hoc "preview" functionality.

That is to say, Baroque had to allow editors to edit on the page, not some isomorphic list of numbers of positions. To change a headline, you would click on the headline on the real frontpage and type. To drop a picture you would drag a picture onto the page where you wanted it to go. To this end, Baroque would have to be mostly formless.

Finally, Baroque would have to be easy to use. Luckily, reducing the analytic overhead, pretty much accomplishes most of this goal. However, we had to keep in mind that key commands needed to be kept to a minimum. No one should have to memorize any kind of schema. No one should have to internalize the idea that this list in my dashboard of named sections correlates to a three column frontpage in some detailed mapping.

This is what we made:

<iframe width="560" height="349" src="http://www.youtube.com/embed/2ADKEHAaf_Y" frameborder="0" allowfullscreen></iframe>

The implementation

Inspired by the fantastic Aloha editor we decided that the editor would be a Javascript application, integrated tightly with the DOM largely through the contentEditable attribute. For those of you who are unfamiliar, contentEditable is an HTML5 feature that allows users to click on text to directly edit it in the DOM without inputs or textareas. Why hasn't this become a landmark feature? It's implementation is erratic across browsers. How exactly do newlines and spaces render out? How tightly should key commands be bound to the contentEditable? What are the implications of, say, italicizing text? Though products such as Aloha have made great strides in standardizing this behavior, fully cross-browser rich text editing is still in a weird state. Luckily, Baroque is in-house software. All of our editors have to use Chrome. Easy.

The application is built within the fantastic Backbone.js framework. Every story and photo asset have their own models. There is also a model and view created for every el in the DOM that is editable. When a story or photo view is dropped over a container view, the container model becomes associated with the story or asset model. There are, then, functions such as splice and exchange that allow containers to shift around and trade their models. This is to allow editors to easily move stories down the page as the day goes on and the stories get older. Furthermore, the editors can easily experiment with different arrangements of stories, photos and headlines to maximize page impact.

While the building of models and views for the stories and assets was easy -- we simply just pull them down from our database or cache, replicate the needed parts of their schema, and fill in a template -- it was more difficult to build the models for the containers. How would our editor know which h1 would correspond to what part of the container's model? How would we be able to easily add more and different containers slots for, say, a breaking news bar or a related stories section?

To this end, Baroque parses data attributes written in to the page template. It generates the appropriate mapping between model and view and makes the rendering function based on the template. This will look something like this (in haml):

.storywrap{:data => {:collection => "containers", :position => 3}}
  %h2.eyebrow{:data => {:element => "eyebrow"}}= story["eyebrow"]
  %h2.headline
    %a{:href => story["link"], :data => {:element => "headline,link:href"}}= story["headline"]

What this says is: this is el number three, part of the containers collection. It's eyebrow header element should be populated by the "eyebrow" attribute of its model, the anchor element of its headline should be populated by the "headline" attribute. This headline's "href" attribute should be populated by the "link" attribute.

As you can see, the template fills these in, server-side at render time. Why do we need this if the Javascript is going to render it over? This same template is the one used when Baroque actually bakes our frontpage. The only difference is that neither the editing interface nor the editing javascript will be included. One template, two different ways of rendering depending on whether you are viewing -- as our readers do -- or editing -- as our editors do.

This template parsing works with a very simple grammar. The data-element attribute is a list of mappings. If just a single name is given with no punctuation, Baroque will replace the contents of that element with the value associated with that name in the model when rendered. If a colon is included -- as in "link:href" above -- this is read: render the link attribute into the href attribute of this el. Finally if a pipe character appears -- as in "asset_link|background-image" -- this is read: render the asset_link attribute into the background-image css property of this el. We simply, then, tie the change event of the model to render event of the containers with which it is associated and no matter how or where we change the model, all the corresponding container views will be updated. This is a core paradigm of backbone.

Once we are done all of our editing, Baroque serializes a list of containers and their associated models and sends it up to the server. There it is stored in a Redis hash along with the five previous versions of the frontpage to allow for easy rollback. Depending on whether or not we click the publish "immediately" button, our Ruby rendering program will either bake out a new frontpage right away or after the specified delay. We use Resque to manage the publish queue and God to make sure the whole thing stays alive. Once rendered, our server rsyncs the new frontpage to all of our app servers.

Shortcomings

So far Baroque has been working great. Other than a few bugs and having to write a few publish hooks, we haven't had any problems - knock on wood. Our editors produce pages twice as quickly, balance headlines with ease, and most importantly, understand how the page will work long before any preview or publish. However, the path here was anything but. We experienced a torrent of annoying bugs - mostly related to newlines and character encoding. We will go into in more detail in our next post. However, I hope you enjoyed this overview of how our new system works and I hope you will ask questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment