I knocked up a little project this weekend to help extract blog entries from a serendipity blog and format them up to work with the Hugo blogging engine. Partly because I’ve gotten sick of battling making python work smoothly on Windows, partly because Hugo is written in Go, and partly because I’ve been looking for an excuse to write something in Go, I decided to write it in, well Go. And because I love having Opinions, I jotted down my thoughts about Go based on a first aquaintance.
Things I Liked
This is something that has, for me anyway, become more, rather than less important. I split between Windows and Linux systems in my day-to-day (and professional) life. For many languages and runtimes the answer to “how do I use this” basically boils down to “spin up a VM” if you aren’t running, at a minimum, a POSIX userland, and ideally a real Unix.
That, for me, is a huge pain in the arse.
What’s interesting is that small projects of the sort I wrote can be a great way to surface portability problems. This is because if you are both lazy in the right way1 and humble, you will look to achieve your goals by using someone else’s excellent code rather than re-inventing the universe yourself, as so many programmers love to do.
For s9y2hugo I’m pulling data from a DB and writing it to the filesystem: pulling data from a DB is often an excellent test of genuine portability. It’s the sort of thing where you so often discover that while the language and runtime you’re using are in-theory portable, the libraries you’ll need to do anything require native code, at which point you’ll be throwing your hands up in frustration, because getting a working runtime involves so much pain it’s easier to install a VM. Not that running Linux necessarily helps with that2.
For Go, however, my experience was refreshingly straightforward: everything I needed from the standard library Just Worked, and the external pg driver installed and ran just as well on every platform with Go3. That’s huge for me. It’s light years ahead of trying to work in Ruby (just don’t), Perl, and a bit better than Python. And, obviously C/C++/etc. It’s about as easy as Java, except writing Go is nicer than writing Java for me.
Templates, Because It’s 2016
I was impressed with the standard templating system. It’s pretty simple once you get your head around it, and powerful enough that unlike, say, Python, there isn’t a proliferation of templating options. This is very good, because for glue-type tasks (which makes up a chunk of Go’s systems programming target) being able to quickly and easily format output is a win. And having one canonical choice makes life easy4.
It’s not just that life is too short for malloc(), it’s that humans are objectively bad at memory management. A significant number of security vulnerabilities, perhaps even the majority down the years, come down to poor memory management. The most recent high-profile browser hacking competition, for example, had something like 80% of the winning entries rely on a double-free that could be exploited; this isn’t particularly unrepresentative.
People are bad at memory management. I’ll say it again because it’s that important. Somewhere north of 99% of programmers shouldn’t be doing memory management. There’s no good excuse for it
Decent String Handling
Go is C-like, and developed by some of the Big Giant Brains behind C and Unix, and one of the things they’ve learned from is the disaster that C-style string handling turned out to be. How many critical vulnerabilities in code over the years have been down to the many terrible ways to read and copy strings around in C? Slightly fewer than memory management, perhaps, but plenty nonetheless. And since dealing with text is, it turns out, one of the main tasks programmers end up doing (at least as much as dealing with numbers, maybe more), having some sane, idiot-proof ways of doing those things is kind of important.
Batteries Generally Included
This is the general case of the string handling and templates I mentioned: Go was developed this century, and it shows in the best ways. Of course there’s a standard way of reading command line input as part of the core. Of course there’s a standard database framework. Of course there’s standard templating for common output formats. Of course there’s a framework for serialising and deserialising data from a variety of formats (even if it’s a bit verbose). The things you’d expect to be built-in based on the 40 years since C was developed are there. We’re not pretending “creating Internet servers” or “outputting HTML” or “interacting with databases” are exotic add-ons.
The compiler offers useful hints as to why my code isn’t working, second only to Perl in their usefulness. I appreciate this.
Things I Didn’t Like
Go eliminates needing semicolons every line, but having gotten used to Python saying, “fuck it, formatting matters” and using that to eliminate swathes of pointless brackets and sigils, but Go seems kind of bloated. What’s irritating is that the Go community take a strong stance that code must be passed through
go fmt before being contributed to projects. If you’re going to enforce the idea that code must look like the output of
go fmt for layout (spacing and so on), why not just go full Python and make it significant?
Go’s iterations collapse down to ‘for’ loops but it honestly feels like the use of things like the
range construct to implement the equivalent of a
foreach equivalent are the hobgolins of a small mind.
One Last Thing
Thanks to Maire, who wrangled children for most of a day so I could actually get some code written.
- That it so say, the productive kind of laziness that inspires you to spend a bunch of time coding up some automation for a task, rather than manually doing the same thing over and over again by hand. ↩
- Thanks to the combination of the big-ball-of-mud model of many Linux distros with the mess of dependencies in many dynamic languages you can find it somewhere between difficult and vein-poppingly infuriating to have multiple projects using nominally the same framework on the same OS install. I abandoned Rails as a couple of different upgrades to software required not merely multiple copies of Rails installed, but multiple copies of the Ruby interpreter. In parallel. None of which were supported by the distro. Life is too short. ↩
- Except Debian, of course, because Debian sneers at the idea you want versions released any time in the last few years; Debian stable supports go 1.0. This is about as useful as Linux 1.2. ↩
- Choice is good, except when it isn’t. When people spend more time bikeshedding shades of pink in their templating language, for example, than using it… well, that’s why VB and PHP programmers have built half the Web with the tools available while bitter nerds squabble over which hydra-headed combination of “real” languages, libraries, and pointless re-implementations thereof should actually be popular. ↩