Matt Basta

My Blog

Things That Make Me Sad in Go(lang)

Go is a pretty damn good language, and I've been really enjoying it while working on the newest iteration of Legend of Adventure. And while I've been positively titillated by the support for concurrency (and parallelism) from the get-go, it's got some rough edges that really rustle my jimmies.

Project Layout

My biggest complaint about Go is the way the compiler and other built-in tools expect you to lay your code out. Your repository is a package, and every subdirectory within it is a package. A package is like a module in Python.

The frustrating part is where your Go repositories end up. Normally, my work directory looks like this:

/opt/
    bastascript/
    blog/
    crass/
    oath/
    otto/
    panopticam/
    sublime-btype/

And of course, each of the directories up there end up containing the source of their respective projects.

Go forces you to have something that looks like this (put on your imagination goggles and pretend that all of my projects are written in Go):

/opt/
    src/
        github.com/
            mattbasta/
                bastascript/
                blog/
                crass/
                legend-of-adventure/
            robertkrimen/
                otto/

Motherfuck.

Let's be clear: I hate this. I hate everything about this. Nothing about this is good. Everything is bad.

  1. Fuck all that typing and autocompleting. That's four levels deep, compared to one.
  2. Don't remember who owns the project you want to work with? Oh well, go fuck yourself.
  3. Work with projects that are in languages other than Go? Let's have a look:
/opt/
    bastascript/
    blog/
    crass/
    oath/
    src/
        github.com/
            mattbasta/
                legend-of-adventure/
            robertkrimen/
                otto/
    sublime-btype/

What a big mess.

To save myself at least a little bit of heartache, I just ln -s /opt/src /opt so that I don't need to type src/ every god damn time. But in all honesty, this is not good. Could I just soft link all of the project folders to their proper locations? No, I couldn't because I have more important fucking things to do with my life.

What an excellent segue into my next frustration:

Relative Package Imports

So let's say you have a project that looks like this:

aggregator/
    importer.go
    downloader.go
    parser.go
processor/
    mapper.go
    reducer.go
main.go

Your aggregator wants to map and reduce the data that it's aggregating. Great. What does the import look like?

import "yourproject/processor"

And if you've got a project name like legend-of-adventure, you're stuck doing this:

import "legend-of-adventure/server/regions"

You can try import "./server/regions", but don't worry: it doesn't work ("local import in non-local package"). Great, thanks Go.

The Big Community Mess

What the above leads to is virtually everyone trying to avoid using the vanilla Go systems in order to make anything work at all.

  1. Projects that require you to add them to your GOPATH in order to compile. They do this so that packages can be imported without the project prefix.
  2. Projects that use a make.go setup to compile.
  3. Projects that change your GOPATH to their own directory to compile.
  4. Projects that use a precarious dance of Makefiles and go run'd scripts to get set up.
  5. Projects that actually use vanilla Go tools but rely on external packages that aren't using vanilla tools so you still need to do some git fiddling

I would hasten a guess that roughly three quarters of non-library Go projects use some unimaginably frustrating means of being installed. Because the vanilla tools have such an irritating, bad default behavior, the community has tried (unsuccessfully) to build their own solutions. And in doing so, everybody loses. Nothing about this has made anyone's day better.

Let's have a look at what the top community projects (that aren't libraries) do:

Project Approach
Docker Mucks with GOPATH
Lime Uses vanilla, but requires submodules
Cayley Uses vanilla
Syncthing Uses make.go approach
etcd Uses vanilla
Gogits Uses vanilla
websocketd Crazy custom makefile
nsq Unclear, but it has one hell of a gnarly Makefile

Compare this to...

Obvious Missing Features

  1. Deleting an item from a slice should require arr = append(arr[:idx], arr[idx+1:]...). How is that friendly?
  2. There is absolutely zero implicit type casting. Comparison operators could benefit from this the most. int64 and int? Can't compare them.
  3. Nested function syntax is very awkward. Why can't nested functions optionally use the same syntax as non-nested functions? We may never know.
  4. Integer math. All of the math functions (abs, floor, etc.) operate on float64s. Go needs an imath library to do anything useful with integers at all. Presently, you need to write all of your own commonly used math functions yourself.
  5. There's a distinct lack of basic data structures. set? Nope. Sugary queues or stacks? Nope. Ordered maps? Nope. Heaps? Nah. While of course it's possible to build all of these ourselves, it's not ideal. And frankly, the ones that are available as libraries in the community are mediocre at best.