With a focus on developer happiness
I began my journey in Golang
Starting out, my biggest issues I had with Golang was the lack of tooling and the by-now infamous
GOPATH requirement. The latter is a matter of taste by Google’s engineers, but something could be done about the former.
I had been searching for tools that would allow me to replicate the ease of which I could run my Golang services in development, as I could my Node.js based applications, and I found none that fit my needs, and so I decided to create one.
It runs using Docker which solves environment and version management issues, and uses Makefiles for tooling, and it comes in the form of an image that basically contains simple shell scripts which assists in:
- Bootstrapping a project
- Live-reloading of tests and applications
- Auto-updating of dependencies
- Statically linked binary compilation
- Packaging into a scratch Docker image
I call it Go Develop and you can find it at my GitHub repository at:
What follows is a short post on what I went through, and how this project solves the problems I faced while initiating myself into the world of Golang.
- NVM for managing of Node versions
- Yarn for managing dependencies
- Nodemon for live-reloading of my application and tests
- ESLint + Prettier for automatic code formatting and live-linting
- Docker multi-stage builds for packaging and deploying applications
Boostrapping a Go Project
When it comes to bootstrapping any project, it usually comes down to a few things:
- A task runner — After going through the source codes of some projects in Go, it seemed that Makefiles were the generally accepted way to go.
- A dependency manager — Prior to Go 1.11, there was Glide, Dep and Godep. Go 1.11 introduced
go mod which seems to be the way to go.
- A way to manage versions — It seems like the generally accepted way to do this is via Git tags. Since
go mod is kind of new, I stuck with using Git tags.
- A way to release into production — The Go applications I’ve dealt with are generally cloud native, and packaging is usually done via Docker containers.
The recommended way to use Go Develop is hence via a Makefile, with an
init script that provisions a directory for development and release. It also includes scripts to bump your Git tags in a semver-compliant manner.
Managing of Go Versions
In almost every modern language there’s always the customary
x is the first letter of the language/runtime one is using). Ruby has RVM, Node has NVM, and Go has GVM. However, GVM modifies your
GOPATH. While I didn’t mind this at first, I soon encountered issues when working with different projects using the
linkthis sub-command of GVM. That’s when I began researching on the issue, and… It’s apparently an ongoing gripe of many:
Using Docker, we won’t need to even install Golang on your machine. Simply reference the version of Golang we wish to have and get started! (Go Develop begins at 1.11.2, if earlier 1.11.x versions are needed, I’ll add support for them — drop me an Issue on GitHub
As a nice side-effect, this also means you no longer need to configure
GOPATH on your local machine as long as it’s properly defined in the image.
Auto-Formatting of Code
The Intellisense works wonders when the Go Language Server is turned on and the auto-formatting by
gofmt gets the job done pretty well. I actually found it better than the ESLint + Prettier combination — but that’s possibly because Go itself enforces the formatting before it’ll compile.
Live Reloading of Application
, it’s hard to go back to manual reloads. The Golang community has it’s own offerings such as Realize
, which I went with for awhile in my professional work. However, it couldn’t run tests together with the main service, which was cumbersome if you’d like tests to be running while you write code and break things. I still had to run
go mod came about in 1.11 and it broke Realize. The live-reload wouldn’t even kick in once there was a
go.mod file. The issue is still ongoing (and it doesn’t happen just for Windows):
In Go Develop, I used
[inotifywait](https://linux.die.net/man/1/inotifywait) to watch for all
*.go files and do a build/update deps/kill/run cycle on file changes. However, this meant that it wouldn’t run on OS X or Windows, but since Docker abstracts away the operating system layer, this is a non-issue, and which is why running Go applications from a container made sense for me.
Live Reloading of Tests
Existing toolings didn’t do justice to live-reloading of tests either. GoConvey
sounded great — except I didn’t want to have to switch to a browser to view my test results. I’m more of a CLI person. GoConvey had a CLI mode for auto-reloading of tests
, however, failures would not dump the error logs to the terminal which was annoying to me.
Go Develop uses the same
mechanism to run tests as it does with the application. More info can be found in the documentation
Auto-Updating of Dependencies
Another issue I had with other live-reload tools was that after I did an
import on something new, I had to switch my terminal and install the new package separately.
While this wasn’t possible in the past because different projects used different dependency managers, the release of Go 1.11 saw the official inclusion of
go mod which seems to be the way to go (ha-ha).
Binary Compilation and Production Packaging
Most applications written in Go seem to be destined for packaging as a Docker image. In my line of work, I had to do the same. So why not build something that includes a build mechanism with batteries included?
Go Develop was written with the above in mind. Running the
build script inside the image results in a statically linked binary that can used in a scratch Docker image (a Docker image without a specified operating system), which reduces the size of the image dramatically.
If static linking and containerisation isn’t your cup of tea, Go Develop also allows you to run builds for your own operating system by providing the
environment variables. Check out the documentation on how to do this
I hope this project benefits others as it has myself — it’s licensed with the permissive MIT license so you can do pretty much whatever you want with it.
If it did help you in some way, do me a favour and star/watch the repository to indicate that you’ve found it beneficial in your developer journey. Feedback is very much welcome too (I’m still a newbie in Go and any improvements to the tooling I’ve done would help!)
You can find the Docker image on DockerHub at:
Thanks for reading!
Lastly, my team at work is expanding and if you’re based in Singapore and would like to work with me professionally, feel free to hit me up at [email protected]