Most of the time I see myself creating a Golang project: be it a one-file single-purpose thing or a more complex project.
In order to facilitate that process, I try to always keep the structure the same such that there’s no need to put much thought into the process of bootstrapping a new project.
The file structure usually looks like this:
. ├── .editorconfig ├── Dockerfile ├── Makefile ├── VERSION ├── lib │ ├── foo.go │ ├── foo_test.go │ ├── something.go │ └── something_test.go └── main.go
Some things to pay attention:
editorconfigis a real deal - I use vim with
set shiftwidth=2; set tabstop=2, that is,
2as the indentation. For
tabwith 8 spaces as indentation.
be it a
clitool or a library, I always make use of a
main.goin the root so that’s it’s obvious how to fetch it -
go get -u <repo>.
Given the filestructure described above, below is the
Makefile. In this case I extracted the
Makefile from a test project I started some time ago (a “load-balancer” that makes use of
# I usually keep a `VERSION` file in the root so that anyone # can clearly check what's the VERSION of `master` or any # branch at any time by checking the `VERSION` in that git # revision VERSION := $(shell cat ./VERSION) IMAGE_NAME := cirocosta/l7 # As a call to `make` without any arguments leads to the execution # of the first target found I really prefer to make sure that this # first one is a non-destructive one that does the most simple # desired installation. It's very common to people set it as `all` # but it could be anything like `a`. all: install # Install just performs a normal `go install` which builds the source # files from the package at `./` (I like to keep a `main.go` in the root # that imports other subpackages). As I always commit `vendor` to `git` # a `go install` will typically always work - except if there's an OS # limitation in the build flags (e.g, a linux-only project). install: go install -v # keeping `./main.go` with just a `cli` and `./lib/*.go` with actual # logic, `tests` usually reside under `./lib` (or some other subdirectories). # Here we could do something like `find . -name "*" -type d -exec ...` but IMO # that's unnecessary. Just `cd`ing to what matters to you is fine - no need to # handle the case of directories that you don't want to execute a command. test: cd ./lib && go test -v # Just like `test`, formatting what matters. As `main.go` is in the root, # `go fmt` the root package. Then just `cd` to what matters to you (`vendor` # doesn't matter). fmt: go fmt cd ./lib && go fmt # This target is only useful if you plan to also create a Docker image at # the end. I have a separate `gist` with a sample Dockerfile tailored for # golang that you can check out at <TODO>. # I really like publishing a Docker image together with the GitHub release # because Docker makes it very simple to someone run your binary without # having to worry about the retrieval of the binary and execution of it # - docker already provides the necessary boundaries. image: docker build -t cirocosta/l7 . # This is pretty much an optional thing that I tend to always include. # Goreleaser is a tool that allows anyone to integrate a binary releasing # process to their pipelines. Here in this target With just a simple # `make release` you can have a `tag` created in GitHub with multiple # builds if you wish. # See more at `gorelease` github repo. release: git tag -a $(VERSION) -m "Release" || true git push origin $(VERSION) goreleaser --rm-dist .PHONY: install test fmt release
Save that content in the
Makefile file in root directory of the project, create a
VERSION file with something like
0.0.1 (semver) and you’re ready to go.
I think it’s very useful to keep a standard way of performing basic operations across multiple repositories. In my experience this reduces the friction of moving from one project to another. Having a common flow of how to build, create an image and publish a project using a Makefile has helped me in such area.
Do you think the same? What are your thoughts?
Reach me on Twitter at any time @cirowrc and subscribe to the list if you’re a Golang developer or simply likes software stuff!