Saturday, December 1, 2018

Go modules, so much promise, so much busted

Folks who follow me may know that Go is one of my favorite programming languages.  The ethos of Go has historically been closer to that of C, but seems mostly to try to improve on the things that make C less than ideal for lots of projects.

One of the challenges that Go has always had is it's very weak support for versioning, dependency management, and vendoring.  The Go team's historic promise and premise (called the Go1 Promise) was that the latest version in any repo should always be preferred. This has a few ramifications:

  • No breaking changes permitted in a library, or package, ever.
  • The package should be "bug-free" at master.  (I.e. regression free.)
  • The package should live forever.

For small projects, these are noble goals, but over time it's been well demonstrated that this doesn't work. APIs just too often need to evolve (perhaps to correct earlier mistakes) in incompatible ways. Sometimes its easier to discard an older API than to update it to support new directions.

Various 3rd party solutions, such as gopkg.in, have been offered to deal with this, by providing some form of semantic versioning support.

Recently, go1.11 was released with an opt-in new feature called "modules".  The premise here is to provide a way for packages to manage dependencies, and to break away from the historic pain point of $GOPATH.

Unfortunately, with go modules, they have basically tossed the Go1 promise out the window. 

Packages that have a v2 in their import URL (like my mangos version 2 package) are assumed to have certain layouts, and are required to have a new go.mod module file to be importable in any project using modules.  This is a new, unannounced requirement, and it broke my project from being used with any other code that wants to use modules.  (As of right now this is still broken.)

At the moment, I'm believing that there is no way to correct my repository so that it will be importable by both old code, and new code, using the same import URL.  The "magical" handling of "v2" in the import path seems to preclude this.  (I suspect that I probably need different contradictory lines in my HTML file that I use to pass "go-imports", depending on whether someone is using the new style go modules, or the old style $GOPATH imports.)

The old way of looking at vendored code is no longer used.  (You can opt-in to it if you want still.)

It's entirely unclear how godoc is meant to operate the presence of modules.  I was trying to setup a new repo for a v2 that might be module safe, but I have no idea how to direct godoc at a specific branch.  Google and go help doc were unhelpful in explaining this.

This is all rather frustrating, because getting away from $GOPATH seems to be such a good thing.

At any rate, it seems that go's modules are not yet fully baked.  I hope that they figure out a way for existing packages to automatically be supported without requiring reorganizing repos.  (I realize that this is already true for most packages, but for some -- like my mangos/v2 package -- that doesn't seem to hold true).

No comments: