Meet Handlebars.js

In making this blog I ended up using Yehuda Katz' Handlebars.js for templating. It has some intersting features I'll introduce here, but arguably dilutes Mustache's basic philosophy somewhat.

I found Handlebars to be a powerful extension to Mustache but I want to note up-front that it quite possibly isn't the best option in every case. Certainly if you need implementations outside of Javascript it's not (yet) for you, however I'm also aware that the extra power added comes with a potential cost: you can certainly undo many of the benefits of separating logic and template.

With that note in place. I'll introduce the library.

Why Handlebars?

Yehuda has already outlined his rationale for creating Handlebars so I won't go into too much detail here. The important goals can be summed up as:

I encourage you to read his article for a lot more detail and explanation of those points but we'll crack on for now.

I won't cover all the features here. You can read them in the documentation. For now I want to highlight the power (and possible danger) of helpers.

In the case of my static site generation system, my main goal was to have a very thin layer of logic on top of simple content-with-meta-data files with some simple naming conventions. I wanted flexibility in the templating system so that I could generate menus or listings of content without writing extra code for each case.

With Mustache, this flexibility had to happen in the view layer and so became a little clumsy to express in a general and extensible way the data sets required for any page.

It turned out to be much neater and require a lot less "magic" code to be able to make the templates a little more expressive. Helpers were the key.

Helpers

Handlebars adds to Mustache the ability to register helpers that can accept contextual arguments. Helpers are simply callbacks that are used to render {{mustaches}} or {{#blocks}}{{/blocks}}. They can be registered globally or locally in a specific view. We'll use global registration here to keep examples clearer.

Here's a basic example of a block helper that could be used for rendering list markup.

<h1>{{title}}</h1>
{{#list links}}
    <a href="{{url}}">{{name}}</a>
{{/list}}

Here's the context used

{
    title: 'An example',
    links: [
        {url: 'http://example.com/one', name: 'First one'},
        {url: 'http://example.com/two', name: 'Second one'}
    ]
}

And here is the list helper definition:

Handlebars.registerHelper('list', function(links, options){
    var html = "<ul>\n";
    for (var i = 0; i < links.length; i++) {
        html += "\t<li>" + options.fn(links[i]) + "</li>\n";
    }
    return html + "</ul>\n";
});

When you compile this and render with the context data above, you would get the following output:

<h1>An example</h1>
<ul>
    <li><a href="http://example.com/one">First one</a></li>
    <li><a href="http://example.com/two">Second one</a></li>
</ul>

You can read similar examples in the documentation which have much more complete explanations of the details here but the basics should be clear:

With that very brief overview example, I want to move on to more interesting examples. If you want to read more about the specifics about what happened there then I'd encourage reading the block helpers documentation.

Helpers for Content Selection

Before I continue, I need to acknowledge that what follows breaks everything you know about MVC separation of concerns. I know. Bear with me for now.

My site generation system builds the site files based on filesystem naming conventions. For things like the blog home page I wanted to show the 5 most recent blog posts.

Internally the system reads the whole content file structure and builds an in-memory model of the content. Each directory has two indices: one for all articles with a date in the file name (most recent first) and an index of all other article files in alphabetical order. You can then get the object representing that directory and list the articles in either the date-based or name-based index.

For convenience, I developed an internal API that made this easy using "content URLs" for example Content.get('/p/?type=date&limit=5') which will return the most recent 5 dated articles in the /p/ directory.

From there it is pretty simple to be able to make a block helper that allows templates like this:

<ul>
{{#pages '/p/?type=date&limit=5'}}
    <li><a href="{{url}}">{{title}}</a></li>
{{/pages}} 
</ul>

Next and Previous

But listings aren't the only case this is useful. On the bottom of each blog article I have links to next/previous articles (if they exist) and these need the URL and title of the neighbouring items in the dated index.

I did this with another couple of block helpers. The blog template looks a bit like this:

<h1>{{title}}<h1>
{{{content}}}
<footer>
    {{#prev_page}}
        <a href="{{url}}">&laquo; {{title}}</a>
    {{/prev_page}}
    {{#next_page}}
        <a href="{{url}}">{{title}} &raquo;</a>
    {{/next_page}}
</footer>

The helper itself uses this which is the current context (in this case the main blog article being displayed). It then looks up in the content index the article's parent directory, and locates the previous or next item in the index relative to the current one. It then calls options.fn with the neighbouring article object as context.

Pushing the Boundaries

From here there is a lot of grey areas you could probe with this powerful construct. For example, let's assume you have different modules of your app rendering themselves and then being combined by some layout controller and rendered into a layout.

What if you wanted to have the module's external CSS or JS requirements actually defined in the template that really has the dependency. Right off the bat, I'll say I can't think of a real reason you'd want this and not have it taken care of outside of the templating layer, but…

You could have a helper for ensuring the correct CSS is loaded up-stream in the template like:

{{add_css 'widget.css'}}
<div class="widget">
    ...
</div>

And then have the helper defined such that it adds the arguments passed to the layout controller and returns nothing to be rendered.

Then the layout rendering might link those CSS assets in the head.

You're right. This is almost certainly a bad idea. I mention it because it was something that occurred to me for a second before I recognised that is was an example of probably dangerous usage. When you get the hang of a powerful concept like this it's easy to start seeing every problem that can be possibly solved with it as a good candidate.

As with all powerful programming concepts and libraries, there are many things you can do with Handlebars helpers that are really bad ideas. Hence my note of caution at the start.

Conclusion

I'm quite happy with the extra power Handlebars has given me in this context. But I'm certain that with the extra power comes the inevitable responsibility. It is certainly possible to write crazy and unmaintainable code if you get too creative with helpers without thought.

The examples here are probably not best practice for an MVC web-app context. But here in a site generation script with an already in-memory content model, it allowed me to extend the expressiveness of the system without hard-coding a lot of specific logic for different cases in the model layer.

Handlebars.js has many more features than I have touched on here. Check it out. It may just be what you are looking for if you really like Mustache's philosophy but have a need (and the discipline) to make more expressive helpers.

Fancy New Blog

Same poor content, new styling (and backend)

I made my blog a few years ago as a way to learn Rails and after a year in which I posted only two new articles of very low value, I got inspired to give it a revamp.

This article is a long-and-yet-brief overview of the changes..

Design

The style just suits my tastes better. When I made the last version, I was much more focussed on learning Rails and the aesthetics of the site became somewhat secondary. I was inspired by some beautiful and elegant sites I've seen recently and this design was the result (for now). I have dreams of adding beautiful imagery and other fancy things to some articles too, but we'll see.

Fonts are from Google's Webfonts rather than TypeKit's free plan because there is much more freedom without fees. I also get to download the fonts I use here for offline use.

Technology

I went back to basics for this. Since I made the last version of this blog, my tastes in tech have changed a bit. I've come to value simplicity and efficiency more and more. Having a full Rails stack, web servers, proxies, database, user authentication, SSL certificates etc. suddenly seems like a really ugly solution for what is essentially a simple, static site only updated by me.

So this site is a static site.

After I finished a lot of the work on this new system described below, I came across an article from a friend of mine about his CMS solution. It turns out he had a lot of the same ideas and he does a great job of expressing his rationale for moving away from Wordpress-like apps for CMS. I link to that now to save you from more clumsy words from me repeating many of the same things less eloquently.

Managing Static Content

So this site is just HTML files served by good old Apache. Nginx probably would be my first choice on a dedicated server but I'm enjoying my current stay on Webfaction and this is the most appropriate configuration here.

Managing a static site by hand is so 1990s, clearly we can do better than that.

There are actually a bunch of great static CMSs out there that would have been great, Jekyll (Github Pages), Statamic (Commercial) and Kirby being the main ones I came across. Typically, I ended up building my own for no terribly good reason other than it being a good excuse to learn something and end up with exactly the features I need.

The site generation is done by a Node.js app. The content is managed through the file system with a simple naming scheme allowing for articles to participate in ordered indices. For example, if the file name begins with a YYYY-MM-DD date format then it will be added to a newest-first by-date index for that directory. More on these indices later.

The content files themselves are then simply Markdown files with yaml-front-matter to add some meta-data to each. Meta-data typically includes the title (so it can be re-used for page title and in listings/RSS) and a template file to use to render that page.

Templating uses Handlebars which is Mustache with a little more flexibility. This extra flexibility becomes really useful in conjunction with the content indices I mentioned before. For example, all the posts on this blog are dated files in the /p/ directory. To generate the listing on the front page of the site I just need to make a static page called /index.md with meta-data assigning a template that does something like:

{{#pages '/p/?type=date&limit=5'}}
    <article>
        {{> blog_post_body.mu }}
    </article>
{{/pages}}

And my custom pages helper can go and find the date index for the /p/ directory and pull out most recent five articles.

As well as being defined per file in YAML front matter, meta-data defaults for a whole directory can be set in a defaults.yml file (e.g. all blog posts use the same template so it is declared once in /p/defaults.yml) and these defaults are inherited through the content directory hierarchy.

There is another special content file naming convention for specifying RSS feeds (e.g. /blog.rss.yml -> /blog.rss.xml) where the feed meta-data and an internal "content URL" like the one in the template example above are used to generate an XML RSS feed.

Finally, any files that are not .md or .yml in the content directory are copied directly (symlinked) into the final public document root, so that all static assets like images, JS and CSS can be kept versioned with the rest of the content and the entire document root is managed by the generator script.

Publishing

Content is edited through file system and kept version-controlled in a git repository along with the templates and (currently) the node app that generates the site.

I installed a post-update hook in the git repo on the web-server that automatically checks out HEAD and re-runs the generation script. So I can deploy changes by editing files locally, committing, and then running git push production.

I have toyed with the idea of building a web interface for editing. In fact I did have a working prototype using EpicEditor and a node.js REST API (using restify) for editing in an earlier version of the system. But, having settled on the simplicity of fully version-controlled content and no daemons or security to worry about on the server, I'm sticking with local edit and git-push deployment for now.

I am using Mou to write this right now with instant, correctly-styled preview. It works really well, especially when tied it into Sublime Text 2 which I am using to edit the rest of the templates and js files.

Conclusion

I like it. It's been fun to think about and build and has lots of potential for future tinkering.

I may even stick a skeleton version of the site with generation scripts etc. on github although I doubt anyone could have a real desire to use this over one of the more widely used and much better-tested options I listed above.

Now I just need to try to focus on producing some interesting content…

PHP Arrays (Again)

I have mentioned PHP array inefficiency a few times on this blog.

Discussing it at work today someone linked me to a much more thorough review of the topic that is interesting and readable.

I'm finding myself so much more interested in this level of stuff than the typical PHP programmer which I guess is why I spend my free time playing with other, generally statically typed, languages...

Moving Data and Telling People About It

I published an article for work on our recent database migration that I was involved with.

It was an unorthodox approach which seemed to work well for this particular dataset and hardware/time constraints but certianly not perfect. Some interesting discussion followed.

I'm also secretly quite proud I got a mention on highscalability.com's weekly roundup. Thanks Todd!

Catch Up

I've not posted for ages. So here is a summary of a bunch of stuff I've been looking at for fun.

Machine Learning

First up, after finishing the MIT Introduction to Algorithms lectures, I was excited to hear about Stanford's free computer science courses. They are full, taught and (machine) assessed university modules for free! I'm studying Machine Learning and I am really impressed with the quality of the teaching. Thanks Stanford.

There is of course speculation that this is a trial for a new paid remote service. To be honest I feel the quality of the course I've done would be worth paying for if they could find a way to acredit something as a real qualification without proper human assessment.

C++ Experiments

Following on from my experiments with LevelDB, I have played around with creating a C++ gossip implementation based on Cassandra's using ZeroMQ. I spent a lot of time getting a really basic grasp on the intricacies of threading vs event driven style + message passing etc. Ended up with multiple processes on same machine (different ports) gossiping and effectively sharing cluster state. Didn't get around to implementing the full phi accrual failure detection for machine/up down inference and I'm sure the code would need to be torn apart and re-written for anythign resembling real use, but a good learning exercise.

I've now moved on to fiddling about with on-disk data structures. So far I'm mostly just learning. I've read through the specs for SQLite's db file and some articles on CouchDB's Copy-on-write B-tree (not to mention LevelDB/Cassandra's LSM trees). I've also read Acuna's paper on Stratified B-Trees which is all really interesting stuff. Not quite sure what I want to implement now but I may start with trying to get a basic block and free-list allocator working. Just the experience of actually working with C++ and "real" algorithms is fascinating for me, a lowly PHP developer.

In summary then, I'm still doing loads of geeky computer stuff, just forgetting to write about any of it.