I Rewrote my Blog in Go
Streamlining from Django to Go. Here's what happened
Wow, this hit Hacker News front page! Thanks for all the encouraging feedback; I added some thoughts and clarifications to the bottom of the post for those who asked.
The short version
The full story
As part of my recent interest in learning Golang, I decided it would be a good idea to rewrite the IronZebra blog that, funnily enough, was itself the result of my venture to get acquainted with Django three years ago. The Revel framework looked like a good fit for this, and I decided to give it a go.
Overall, the experience was great. I had become familiar with the basics of Go before through writing a bunch of solutions to Euler problems, and this provided a good enough knowledge baseline for building a site in Revel.
I skimmed through the Revel docs to see how things like URL-routing work, and decided to plug mgo into it as an interface to my Mongo database. mgo is an excellent driver for MongoDB, and working with it was a breeze except for one or two surprises where the syntax deviated from the normal MongoDB structure. For one, the FindOne
method was dropped for a chained combination of Find
and One
:
collection.Find(bson.M{"title": title}).One(&result)
Regarding Revel: Revel’s code reload is nice, and I like the way it simplified URL routing by allowing you to edit a well-structured text file which then gets compiled into Go code before serving the site. It’s a good solution to a problem that might have looked much more ugly had it been done only in Go. The one downside to Revel at the moment (although this is on the wishlist) is that it only ships with the default Go template language. Documentation on this isn’t all that good, and I felt like it doesn’t solve website templates nearly as well as Jinja2 or Django templates. The template inheritance, for example, seems clunky and I ended up with files containing only closing html tags – ugly. Maybe I should have read the documentation more closely, but I wanted to iterate fast and get things done. Plugging in your own template system is surely also possible, but for a first-time exploratory project this prospect seemed like a bit much.
I spent most of the time creating the admin functionality for editing and creating new posts. The admin section allows for markdown input (using blackfriday) and logging in with a bcrypt-encrypted password that gets stored in a user collection in Mongo. To give you an idea, here’s what the admin editor looks like:
The results
The speed improvement was staggering.
As differences between the two versions go: Both for the old Django site and for this Revel-based Go site, I never did anything along the lines of caching - no static page generation, no memcache, no groupcache - you can call it laziness, but either way, it makes for a more fair comparison between the two now. Secondly, I am now loading less static assets. I removed the Disqus comments and the many many lines of CSS from the old site and replaced it with only a couple of lines of CSS alongside a CDN-hosted copy of Twitter Bootstrap. Finally, the Go site is deployed to a free instance of Heroku and the MongoDB hosted on a developer version of Mongolab, while the old Django site was hosted on a Webfaction shared server. All these things influence the validity of a direct speed comparison between the two versions, but the speed improvement is nevertheless too overwhelming to attribute only to these small changes. And in fact, many of these changes might even have negatively impacted the speed of the new version in exchange for saving on the monthly bills.
But the end result: pages that load up to a 100 times faster on average, according to Google’s Webmaster Tools. Search traffic has also been steadily increasing this last month, possibly influenced by Google giving higher weight to sites that load really fast.
If you are interested in using this yourself or contributing, or even collaborating on making this into an open blog-engine written in Go - send me a ping on Github - this project is open-source and on there in its entirety. Enjoy!
Edit on 15 August 2013:
Afterthoughts
This hit Hacker News front page yesterday and it seems like this humble post started somewhat of a flame war in the comments section. I decided not to jump in, especially since I couldn’t really provide experimental answers to their very valid questions while 500 visitors were hitting the site every minute. Regardless, I also received so much encouraging feedback, emails and tweets; thanks all!
I hope to offer some small clarifications:
A lot of folks on HN commented on the Disqus removal. I’m afraid the graph was only for the time Googlebot took on average to download the HTML. I mentioned the removal of Disqus in the post, but that wouldn’t have a significant impact on this graph’s page load time, as others also later pointed out in the comments.
Yes, the old site was incredibly slow. Anything would be better. That’s part of the reason I rewrote it. I never spent any time making it efficient, which is why I didn’t even have caching. It was also hosted on Webfaction, which is, in my eyes, the most likely source for the slowness. If your Webfaction app is not in memory right now, it seems to take an incredibly long time to load it back in. User Jgrubb also wisely pointed out how much of a difference switching servers can make. He’s right, those graphs look mightily similar!
All this said, I think a lot of folks missed the point of this post, if there was any point at all :) I didn’t mean to imply “Go, and nothing but Go, made my blog 100x faster”. I meant to just say: “I rewrote this blog in Go, streamlined a bunch of other things, and now it’s 100x faster, yeay.” I realize that the graph was suggestive of the first one, my apologies for that.
There are good reasons for writing a blog from scratch and not using some existing solution for serving static files. One, learning. Two, fun. Three, a blog engine of this kind is like the “Hello World” of web applications. It covers a lot of the common things you’ll normally need to do in a bigger, product-oriented web application. Basic GET and POST, user login and database connections. Proving that it’s easy to write a CRUD blog like this is an early exploratory exercise in determining whether it would be easy to write larger-scale applications that scale.
And hey, after all is said and done, the Go-based IronZebra blog survived being posted on the front page of Hacker News on a free Heroku instance (pretty well at that, never even taking long to load), all without caching. If this were still Django, and still hosted on Webfaction, I don’t believe it would have been the case. That’s all I’m saying :)
I also added some more details in a presentation on slideshare - I’ll be presenting this in Tokyo tomorrow, drop by if you can!