Thoughts on writing webapps in Go
When it comes to writing webapps, Go seems to have a lot going (ha!) for it – a straightforward concurrency model; simple compile-and-go deployments; and a standard library with all the proper networking primitives. That being said, it’s a relatively new language and the ecosystem doesn’t quite feel there yet. Below are some thoughts I had after developing DrDebber, a debian-repo-as-a-service. tl;dr: patch together a microframework with Gorilla and an ORM of your choice (I settled on gorp).
The basics
The net/http package in go’s standard library will go farther than, say, python’s equivalent, although that’s not saying much – it’s functional enough to be dangerous but has some rough edges. URL routing, for example, is a bit too basic. URLs are matched simply on prefix and don’t support variable binding – instead of e.g. /frobnicate/:id
, routes look like /frobnicate/
and we’re stuck parsing out the ID in the handler. Fortunately Gorilla is almost a drop-in replacement and works pretty much how you would like it: we can specify routes like /frobnicate/{id:[0-9]+}
and use the time we saved dealing with parsing to go get a sandwich or something. Gorilla can also route based on HTTP method, which is a feature that’s strangely absent in net/http.
For templating, text/template is similarly decent but has a few weird corners. For instance, only one parameter can be passed to a sub-template. That one parameter can be .
, which means the entire context, but we’re still stuck not being able to augment with any additional parameters computed in the parent template. The documentation is also a little unclear on exactly how to create a group of templates that can reference and extend each other: the most straightforward way is to parse everything with ParseGlob/ParseFiles and execute/include templates by their name which is given in a {{define temp-name}}
directive at the top of each file.
The ORM
There are a few different ORMs out there: I ended up going with Gorp. Gorp is basically a thin veneer over straight SQL – so thin you can see right through it:
db.SelectOne(&user, "select * from users where handle = ?", handle).
user.flavor = "delicious"
db.Insert(&user)
This obviously isn’t really an ORM so much as a slightly nicer interface to the underlying db object: the win here is not having to deal with row and cursor objects. This is decent enough for my needs but I could certainly imagine needing something a little more substantial at some point.
The annoying stuff
And finally there’s the remaining 20% that will take 80% of the time – a basic CRUD admin interface, password reset emails, 500 handlers, and so on. We’re out of the domain of micro-frameworks here although I’m not so sure there are any real options yet. There’s Revel but I’m not sure it’s going into that Django-y/Rails-y direction.
The awesome stuff
Deploying a statically linked binary with no dependencies is awesome. Writing straightforward code and avoiding callback hell is awesome. Spawning one main process instead of one worker per CPU is awesome. Basically all of the ancillary details you need to deal with in say python or node are gone – it’s a breath of fresh air.
Have any experience yourself? Let me know what’s up – I’d love to hear what other people are doing!