Skip to content

Instantly share code, notes, and snippets.

@kevin-cantwell
Last active August 29, 2015 14:03
Show Gist options
  • Save kevin-cantwell/ed0e0795decacf1d5b7e to your computer and use it in GitHub Desktop.
Save kevin-cantwell/ed0e0795decacf1d5b7e to your computer and use it in GitHub Desktop.
Philosophy of a Go dependency management system.

Goshim: Building a Better Go Dependency Management Tool

Go dependency management is essentially non-existent; this is known. It is also a source of frustration for many in the Go community. The standard Go tools are generally awesome, but the closest thing to dependency management Go provides out of the box is that go get will prefer VCS tags corresponding to the current go version. Afaik, nobody respects (or is even aware of) this convention. This is not entirely surprising, as Rob Pike himself has said that depedency management is a problem left for the community to solve. In fact, the reason why import statements are constructed with a string argument is to allow future support for arbitrary syntactic choices in specifying dependencies. I suspect that when the compiler is fully rewritten in Go, the community will jump at the chance to submit pull requests that support package versioning. Until then, we must build tools to help us strictly define our dependencies.

Godep is one such tool. Probably the most popular. However, my experience with it has been less than ideal. For one, Godep requires you to prefix your go commands with godep. This allows it to set a temporary $GOPATH prior to executing each command. Clever, but self-centered. Only certain commands are supported and it means that any other tool that depends on $GOPATH (such as Ginkgo, for example) is not likely to play well with Godep. Godep also has a difficult workflow that can lead to a dirty $GOPATH for other projects if not carefully managed. It also seems to work best with vendoring, which is something I try to avoid in this day and age of programming.

I think we can do better with what we already have. As a ruby developer, I know that dependency management does not have to be a painful experience. Tools like Bundler, RVM, and rbenv have proven themselves as truly helpful productivity enhancers and I want a similar experience for Go.

Here are a few statements about what we should expect from a Go dependency management tool:

  1. It should be a shim. I should not need to be aware that I am executing any special code. For example, a call to go test should never need a prefix or special argument. The code in our tool should be executed implicitly by a call to any of the go executables. Shims provide a nice way to be unobtrusive without needing to hijack shell functions.
  2. It should be configurable by project. Ie: Each project's dependencies and environment should be optionally sandboxed. This can be achieved with special hidden files or directories in the project root.
  3. It should not, by default, interfere with any Go commands. If a project is not initialized with our tool, it should redirect all commands and their arguments directly to go executables and should leave environment variables alone.
  4. It should work well with others. Any other tool or script should be compatible with this tool. It should also be simple to export the modified go env calculated by the tool.
  5. It should be portable. Tool configuration should be versioned along with a project. Anyone else who has the tool installed should be able to build a go project with the exact same dependencies.
  6. It should not rely on vendoring. The idea that dependencies are a part of version control is, IMHO, not ideal. Vendoring should not be required. However, there should be some support for vendoring as not all dependencies may live in public repositories.
  7. Go version shouldn't matter. Nor should it matter if some other tool is managing the Go version dynamically.
  8. It should use go get -u to update version configuration. The go get command will need to be rewritten entirely to support version configuration. A single call to go get should respect the configs and install only the specified version to the local $GOPATH. Passing the -u flag to go get should update the configuration file with the latest version from the branch specified in the configs. This will clearly be the most complicated and error prone portion of the tool. It's unclear what compromises I will have to make in this regard.
  9. It should only be concerned with dependencies. Do one thing and one thing well. Go versioning should be handled by some other tool.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment