Version 1.0 of the Ackbar Blog Engine
I'm pleased to announce today the 1.0 release of the Ackbar blog engine which powers my site. I think Ackbar is maturing into a genuinely useful piece of software, especially when you consider the fact that anyone can host an instance of it for free on Google App Engine. Honestly, though, I primarily wrote it for fun. I was motivated by Rob Conery's blog post about how programmers should build their own blogs, in much the same way that Jedi build their own lightsabers. I'm a sucker for Star Wars, it turns out, hence the name of the framework. I'd like to spend the rest of this post looking at the result. If you're impatient, just go look at the code.

The Basic Architecture
Ackbar is a Clojure lisp application running on Google App Engine. It relies primarily on the Ring, Compojure, Enlive, and Appengine-Magic libraries to go about its daily business. My original intention was to just build on top of Compojure, since I was assuming that it was a full-stack framework like Rails or Django. In fact, Compojure is about 250 lines of code which mostly serves to create nice request routing syntax. In fairness, a lot of the stuff that was in Compojure has been factored out into Ring (Clojure's version of Rack/WSGI) and other libraries. Enlive happens to be the go-to choice for templating, and it accomplishes it in a somewhat unusual way. Basically, you start with an HTML file. You then give Enlive a bunch of CSS selectors and functions to run when the selectors match, and Enlive transforms the file into the desired content. There's no templating language to speak of. Crazy!
Performance
I'm somewhat concerned about performance. App Engine isn't exactly the speediest service in the entire world, and I'm doing somewhat intensive database queries when you load the page. App Engine also isn't "always on", so if nobody's visited my site for a while, they might be waiting for an instance to warm up, which can take quite a while. I'm sort of hoping that if I get more RSS subscribers (hint hint), their clients will ping my site often enough to keep App Engine running instances for me. We'll see.
I've also gone ahead and followed the "memcache everything" strategy (possibly the most important performance lesson I learned working at Facebook). This had a positive impact on the site. It also gave me an opportunity to illustrate the power of Clojure. Here's a lisp macro I wrote in the process of implementing memcache:
(defmacro memcache "Takes a memcache key and an s-expression that will evaluate to something serializable. If the key exists in memcache, returns the value under the key. Otherwise, evaluates the s-expression and caches it under the key." [memcache-key value] `(if (mc/contains? ~memcache-key) (mc/get ~memcache-key) (do (def value# ~value) (mc/put! ~memcache-key value#) value#)))
If you don't know much lisp, I wouldn't try overly hard to understand what's going on here. Basically, one of the simplest ways of using macros is to treat them as a sort of "template language" for lisp code generation, and that's what I'm doing here. If I wrap a database query in (memcache "key" (ds/query ...)), it will only perform the query if the key isn't already in memcache. This effect would be possible to achieve with a callback function, but lisp syntax makes it much more natural. The callback function approach is certainly possible in python, but the App Engine documentation still suggests that you repeat some boilerplate for checking memcache all over your code. I think this illustrates the advantages of lisp quite nicely.
Subscription
RSS was one of the later features I added, and it ended up being pretty easy (That's what the first S in "RSS" is there for, after all). Enlive handles XML reasonably well, but it doesn't handle namespaces or CDATA. This would be a problem for replicating Wordpress-style RSS, which uses both. Luckily, it's totally possible (and, I think, expected?) to just put the entire blog post in the description tag of your feed, using escaped HTML, which somewhat confusingly gets converted back into real HTML by the RSS reader. After getting everything set up, it's just a matter of plugging the result into feedburner, an awesome service (now owned by Google) which will syndicate the feed in a bunch of different formats, including email. It's much better than just linking to raw XML, especially since Chrome throws up when you link to an RSS feed.
File Uploads
I decided to implement file uploads to the App Engine blobstore API as part of Ackbar. It wasn't in my original plans, but file hosting is kind of nice to have. It lets me embed images into blog posts, like this:

That particular image, in fact, illustrates probably the most terrible part of the Ackbar engine right now. After you upload a file, you get this screen, where you have to manually type in the filename. Yes, it really is that lame. I'm going to continue trying to solve this problem in a better way, but it's actually a bit tricky. You see, I just shove the file off to the blobstore API and wait for it to give me a "blob key" so I can get it back. When App Engine is done saving the file, it does an HTTP POST to a callback URL I specified. This POST contains the blob key, but it sure doesn't contain the filename. So I have no really easy way of knowing what file we're talking about when a blobstore upload completes. The "Name File" thing is my temporary fix while I try and figure out why nobody else thinks this API is totally insane.
The Future
So, software projects are never done, but Ackbar is now working well enough for me to be able to call it "1.0". Obviously, I'll keep polishing it and adding features. One thing that it doesn't support that's a noticeable omission is a comment system. I haven't really figured out what I want to do about this yet. I kind of feel that blog comments are pretty useless. I'd much rather people discussed my blog posts on Reddit or Hacker News than on my site, after all. Still, it's sort of expected. I'll have to think about it. Overall, I'm quite pleased with the results so far.
If you liked this, you should click here to subscribe for regular updates