I began my journey in Golang a few months ago when I decided that JavaScript was getting a little too unwieldy for my liking. TypeScript solved some problems but it made JavaScript as verbose as Java. Anyhow, I have been writing JavaScript for close to half a decade and I thought it’d be nice to learn a different language with a different mental model and development paradigms.
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:
I call it Go Develop and you can find it at my GitHub repository at:
zephinzer/golang-dev_Contribute to zephinzer/golang-dev development by creating an account on GitHub._github.com
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.
For reference as to the environment I’m trying to replicate, I use the following tools with JavaScript to improve my productivity:
When it comes to bootstrapping any project, it usually comes down to a few things:
go mod
which seems to be the way to go.go mod
is kind of new, I stuck with using Git tags.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.
In almost every modern language there’s always the customary xVM
(where 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:
Leave the $GOPATH alone please · Issue #189 · moovweb/gvm_I don't want my $GOPATH changed when I switch to a different version of Go. $ go version > go version go1.4.3…_github.com
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.
Like many who work on web-related software, I call Visual Studio Code my choice of IDE, and it already had a surprisingly decent plugin, just search for “go” in your marketplace!
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.
After using nodemon
, 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 test
manually.
Then 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):
Cannot do `--run` with go1.11 using go mod under windows. · Issue #217 · oxequa/realize_directory: -- main.go -- go.mod main.go: package main import "fmt" func main() { fmt.Println("hello") } start realize…_github.com
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.
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 inotifywait
mechanism to run tests as it does with the application. More info can be found in the documentation.
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).
With Go Develop, the use of go mod
is enforced which simplifies issues that other dependency managers face such as version selection. go mod
also includes backward compatibility with other dependency managers which convinced me it was the choice to go with.
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 GOOS
and GOARCH
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:
Docker Hub_Edit description_hub.docker.com
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] (: