This blogpost/screencast walks through some of the aspects involved with baking a website like Best In Class, looking at the source code and demoing the backend.
Some time ago I generally described the process of baking Best In Class and afterwards released the source code. At present I hear and see many questions relating to Web Development which could be answered by reviewing the sourcecode for Best In Class (primarily admin.clj and templates.clj). So to save you guys the trouble of having to install the entire site yourselves, I've prepared a small screencast. If you want to hang around after the screencast, there's a general talk about baking below.
Best In Class - The tour from Lau Jensen on Vimeo.
The old Best In Class was PHP driven. On every request that came in PHP would look into a database and fetch content, menus, comments etc, mix it with HTML and serve it. PHP is quite fast at doing this, but it still took so much time that during traffic spikes the site would becomes unresponsive and the backend nearly unuseable. I actually received a few emails from my hosting provider asking if everything was OK, because the app was tearing up the disks. Although it should be said, that back then I used to blog twice a week pretty consistently, which obviously puts more stress on the server than the sporadic posts that I find time for nowadays.
So talking about scaling a simple blog seems silly - Unlike an application a blog should just sit there and serve its pages without any need for special scaling initiatives right? Right! So here's how to do that:
The old site (or any Wordpress/Drupal/Typo3 based site) actually used 2 databases. First there was a MySQL backend which contained all of the information about the site in an easily accessible format (SQL). Then secondly, once that was compiled a second version existed of the fused data and HTML. Why not just leave out the first database and simply rely on the second, the filesystem?
Like comments, twitter updates, etc. But if you simply update the HTML file atomically instead of adding more data to the database, that will effectively give you the same result as using a backend SQL. This works well for comments, footers, headers etc. For something like a Twitter stream, simply write some Javascript to fetch it in the browser. One example is my comment box. It needs to be dynamic but the page which fetches it doesn't. Its simply brought in via Ajax from the Moustache backend. All that Moustache needs to know is who's calling, so thats baked into each page as well:
(defsnippet post "blogpost.html" [:body :> any-node] [{:keys [title body thumb date comments link]}] [:h1#title] (content title) [:img#thumb] (set-attr :src (str thumb-prefix thumb)) [:div#pubdate] (content date) [:a#addcomment] (set-attr :href (str "/cmt/url=" link)) [:div#post] (append (html-snippet body)) [:div.comment] (clone-for [{:keys [author email date comment]} comments] [:div.author] (content author) [:div.date] (content date) [:div.message :pre] (content comment)))
The line which selects [:a#addcoment] matches any links (a tags) with the id 'addcomment' just like CSS and then sets the href. Once you get used to the prefixed colons, this reads and acts exactly(!) like CSS selectors and its all performed automatically whenever I call this template.
I received a certified beatdown in #clojure from a fellow who was very protective of his data, juding that simply relying on the filesystem was an incredibly dangerous way to go. My oppinion is, that all disks will eventually crash. The time of the crash is determined by the disks usage and SQL is heavier on Disk I/O than a static site. Second, usually what matters in these situations is your backup routine and your failover - Best In Class can in its entirety be backed up using rsync, can you say the same about an SQL database? Bottomline, the filesystem is completely safe and even an SQL database needs a working filesystem beneath it. In fact I'd say by simply using the filesystem as your database, you've removed a point of failure and reduced the complexity of your application.
When I reworked Best In Class I just knew that I was unhappy with the current setup and its performance, so after evalutating my options I decided to spend a few days on reworking the site using Enlive - There has been zero regrets. It was a fast rewrite and much of the time was spent writing a conversion routine for exporting all of the old blogposts from Wordpress to the new format. I decided to put all of the source online, so that an ambitious Clojure hacker moving from any kind of blogging platform could find some useful snippets. Also, did you know that Enlive lets you completely separate presentation from code? There is zero code in the HTML and zero HTML in the code, so I could work out the entire design in HTML upfront and just inject data using the CSS selectors.
Even if performance wasn't an issue, this would still be an optimal way to go in many cases. You can forever say goodbye to database maintenance, updates, heavy backup routines etc. The entire site is stored neatly in a folder which is ready to be tarballed or rsynced to a backup location - And the entire site can be reployed using nothing more than rsync - Truly an easier life.
The Moustache backend is usually the part of Best In Class that I tweak the most, adding features here and there. The wonderful thing about a completely static site, is the fact that I can restart the backend at runtime without any users being affected. Only in the rare situation that a user hits the 'Add comment button' in the exact same moment that I'm restart will somebody notice and I haven't received any complaints yet.
Best In Class is faster than ever. And as a bonus - Did you notice how fast the admin panel came up? When I enter that URL all of the stats are compiled at that moment, and it takes about 1 second. The old PHP solution (which admittedly did a little more statistics, but not a lot) would take so long that sometimes my request would time out. If you want to see how it's done, the source code is still on: Github.
Lau Jensen is the founder and owner of Best In Class a danish consultancy company which specializes in Clojure development.
Lau is also one of the instructors of driving the Conj Labs initiative. If you would like to be notified once new blogposts are published, you can follow Lau on Twitter.