Creating a new Go Project

Introduction #

If you just want to test some code, then the Golang Playground is perfect. For anything more involved, you should create a project containing your code, configuration, and dependencies.

If you still need to install the go binary, please refer to Installing Go.

The command to create a project is:

1
 go mod init <project-name>

In Go, projects are called modules. Modules ideally live in a source control repository like Github, Gitlab, or Bitbucket, which are then referred to by their complete repository name.

For example, if your git repository is github.com/gerritjvv/mynewproject, the command is:

1
 go mod init github.com/gerritjvv/mynewproject

This is the preferred way to create modules (projects) in Go and makes using modules as dependencies easy.

You will notice that the go command created a go.mod file for you.

Now you are ready to write your code:

Place the main.go file in the same directory as the go.mod file.

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
	fmt.Println("Hello World")
}

Then type

1
 go run main.go

to see the output

1
 Hello World

And that is it; you have created a Go project (module).


Anatomy of a project #

All you need to create a Go module (apart from code) is a directory and a go.mod file. The go.mod file tells Go the module name, the minimum compiler version and any dependencies the module requires.

The go.mod file, at a minimum, contains two lines:

1
2
3
module <modulename>

go <go version>

For example, if we ran go mod init github.com/gerrrittjvv/myrepo, and your compiler version was 1.21.4, the go.mod file would look like:

1
2
3
module github.com/gerrrittjvv/myrepo

go 1.21.4

Module Path (GO ROOT) #

In many programming languages, you can group your source files into packages(also called namespaces or modules). In Go, they are called packages, and modules refer to the whole library, which is made up of packages. This may be confusing if you come from Python, JavaScript, Rust, Swift, Ruby, or Haskell.

The module path or ROOT is where Go will look when one code file “imports” another one that lives in a different package. The root of a module, by default, is the folder where the go.mod file resides.

For versions of Go older than 1.11, you will need to set the GOPATH and GOROOT environment variables.

Dependencies #

The preferred way to add dependencies to a module is by using the go get command.

For example, to use the gopkg.in/yaml.v3 module in our code, we need to run the below command in the root directory of our module.

1
 go get gopkg.in/yaml.v3

This will create a require entry in our go.mod file, which will then look as below:

1
2
3
4
5
module github.com/gerrrittjvv/myrepo

go 1.21.4

require gopkg.in/yaml.v3 v3.0.1

From this moment, we can use the yaml dependency by importing it:

1
2
3
4
import (
"fmt"
"gopkg.in/yaml.v3"
)

And then refer to packages in the dependency using the last part of the path (except for any “.” suffix); here we would use yaml.<Any function or type>.

For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
	"fmt"
	"gopkg.in/yaml.v3"
)

func main() {

	type Doc struct {
		Tags []int `yaml:"tags"`
	}

	docYaml := `
 tags: [1,2,3]
 `

	var doc Doc
	// using our imported dependency from "gopkg.in/yaml.v3" to read YAML content.
	err := yaml.Unmarshal([]byte(docYaml), &doc)

	if err != nil {
		panic(err)
	}

	fmt.Println(doc)
}

Building, Formatting Testing and Linting #

Just being able to run a project isn’t enough in most cases, and soon you would want to run tests, check for errors using linters and automate running several of these commands

Building a project is best left to either a small number of automation scripts or a proper build tool. In the Go community, there isn’t one prevalent tool. The most common are Make files or Bash scripts. Below, I give an overview of the commands you need and briefly explain each.

Overview of commands

Here is a list of commands to run during a complete build, excluding the linting, which is something you need to first, choose.

1
2
3
4
5
6
go mod download
go fmt./...
go vet ./...
go mod tidy
go test./...
go build./...

Linting #

This is the easiest and most powerful productivity hack you can add to your project. Linters come in all shapes and sizes and the best is to use a lint aggregator that runs several different linters in parallel.

I am going to show you how to setup GolangCI-Lint, but you can also look at Awesome-Go-Linters, choose the linter or linters that best fit your project needs.

GolangCI - Lint #

First, install the linter by running:

1
 go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2

Execute it by running the below command from your project root directory:

1
 $GOPATH/bin/golangci-lint run./...

Apart from your linter of choice, you would want to run Go’s default linter, which is go vet ./...; for more information, see https://pkg.go.dev/cmd/vet.

In my projects, I run go vet and golangci-lint one after the other.

Formatting #

To avoid having style and formatting wars, the creators of Go have provided us with a tool that formats our code to what is considered idiomatic.

Running go fmt ./... in our module folder will search for each of our *.go source files and format them correctly. It is convenient to run this command from our IDEAs before we commit.

Testing #

Tests are in separate *_test.go files in the same folder as the code it is testing. For example, If you want to test code in binarytree.go, you would have a file binarytree_test.go, go test ./.. will see this file and run the tests inside it.

Building #

You can run go build ./... from the module directory to compile and build your code into a single binary. Before building, ensure you have all the dependencies downloaded by running go mod download.

The build sequence is:

1
2
3
go mod download
go mod tidy
go build./..

Summary #

Go provides a single " go " tool to build, test, format and manage dependencies for Go projects. Projects are called modules, and the go mod <sub> command is used to create modules and manage dependencies.

As for managing the build in a Go project, it is worthwhile to spend time on getting the project build and layout correct. Too many developers want to skip this part and go straight to the code, only to trip over a mess later.

The part I have yet to cover in this long blog post is using some standard build tools with Go. Please see Building Go for ready-to-use scripts and code.

You may also enjoy