Go Style Guidelines
This guide describes how to structure Go projects within our monorepo and outlines some best practices for writing Go code.
It is not meant to be comprehensive and should rather supplement established patterns and best practices. A good reference for the latter is Google's Go style guide. We try to explicitly document instances in which we intentionally break with this style guide.
Project Structure
To simplify buliding, testing etc. all Go projects in the monorepo should follow a similar layout. A simple example could look as follows:
my-project
|- Makefile
|- go.mod
|- go.sum
|- cmd
| |- server
| | `- main.go
| `- cli
| `- main.go
|- foo
| `- foo.go
|- internal
| `- bar
| |- doc.go
| |- something.go
| |- something_test.go
| |- some_other_thing.go
| `- some_other_thing_test.go
`- testsintegration
|- test_main_test.go
`- server_test.go
Aspects of this are explained in the following subsections.
Makefile
We use shared Make rules for all Go projects so you don't have to write these from scratch every time. Thus your Makefile should likely only contain the following unless you have some very special needs that can't be generalized:
include $(LYC_PATH_REPO_ROOT)/make/go.mk
go.mod
The "tidyness" of go.mod should be verified automatically, other than that:
-
Include
lyceum.technologyin your module name, e.g.lyceum.technology/my-project(also note that we use hyphens, not underscores). -
If you want to use our shared
daedalusGo library (adjust the relative path to the correct location):
require (
...
lyceum.technology/daedalus v0.0.0
)
replace lyceum.techology/daedalus => ../daedalus_go
Binaries, Public and Internal Packages
- Place binaries to build under
cmd. If using our shared Make rules, it is not required to add any additional.gitignorepatterns. - Create a directory per package that you want to make available to other projects (more likely than not you will have none of these)
- Place all other packages under
internal. - Package names should contain neither hyphens nor underscores and directory names and packages names should match exactly
- Place package doc comments in a
doc.gofile. An exception being packages that contain only a single file. In this case it's okay to give the file the same name as the package directory and omitdoc.go, e.g.foo/foo.goabove.
Integration tests
Place all integration tests (any that require external components such as test
containers) in a testsintegration (and thus a testsintegration package).
These must not run when running go test with -short. To achieve this
you can use the following minimal test_main_test.go template:
package testsintegration
import (
"flag"
"log"
"os"
"testing"
)
func TestMain(m *testing.M) {
flag.Parse()
if testing.Short() {
log.Println("Skipping integration tests in short mode")
os.Exit(0)
}
os.Exit(m.Run())
}
Naming Conventions
Aside from following typical Go conventions please note the following when naming things (variables, functions etc.) in your code:
- Name boolean-returning functions so that they naturally read as predicates;
Prefer prefixes such as
Is,HasorCan. For example:IsActive(),HasChild(),CanRetry(), ...