I’ve recently started a love affair with Go, much to the disgust of some of my coworkers. One of the best things about using Go is how ridiculously fast your work cycle becomes when compared to other languages, such as Erlang and Elixir. Simple things that require a tremendous amount of work are a non-issue in Go, which ultimately helps you get to market faster.
However, a common complaint about Go is package and dependency management. There are no shortages of community developed package managers for Go, but in general I don’t think a package manager is really needed so long as you structure your work correctly.
Short and simple, here’s what works the best:
code/ <--- This is your GOPATH, but you don't ever need to set it. Keep reading.
bin/
pkg/
src/
make/
Makefile
tools/
.git/
.gitignore
Again, keep it simple and just do
GOPATH=/path/to/code go get -u github.com/...
All new projects should live in code/src/<project_name>
. In each project folder, create a Makefile and include the following in it
include ../make/Makefile
This one is a bit tricky, but with the magic of Bash and Make, you can make life pretty easy. In code/src/make/Makefile
, paste the following
export GOPATH = $(realpath $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))/../../)
export GOBIN = ${GOPATH}/bin
export APP = $(shell basename "$$PWD")
build::
go build
go install
run::
../../bin/$(APP)
test::
@mkdir -p $(GOPATH)/tests/
@echo 'mode: set' > coverage.txt && go list $(APP)/... | xargs -n1 -I{} sh -c 'go test -covermode=set -coverprofile=coverage.tmp {} && tail -n +2 coverage.tmp >> coverage.txt' && rm coverage.tmp
@go tool cover -html=coverage.txt -o $(GOPATH)/tests/$(APP).html
@rm coverage.txt
package::
GOOS=linux GOARCH=amd64 go build -o ../../bin/$(APP).linux
GOOS=darwin GOARCH=amd64 go build -o ../../bin/$(APP).mac
%::
@:
.PHONY: test
Now any project that includes this file (as noted in the section above) will work with Make. For example
cd code/src/someProject
make
make run
make test
It’s important to note this setup automatically sets your GOPATH, you do not need to set it in your bash profile, and is 100% portable across folder locations and OS’s.
Speed and simplicity of management.
Consider working in a large environment where many people will write many different libraries. Every time you want to make a change to a library, you need to commit your code in some other repository, push that code, pull it back down to your Go project, compile, etc. If you have a bug in your new code, you’ll have to do it all over again. Making many small changes? Good luck.
With this setup, you commit the whole tree, and just focus on what you need to do: edit your code. Need to make a change to a dep? Then do it and recompile. The next time you push and merge, your changes will be available to every app within your organization.
As an added bonus, the next time Github is DDOS’d, your work flow won’t be disrupted, assuming you’re not using Github as your primary repository (you’re not, right?).
Enjoy.