Go

Special file, package, and directory names in Go

One of the recurring questions people new to Go ask is, how to lay a project out on disk, that is, they want to know how to arrange the files and directories in their project the ‘Go’ way. One of the strengths of Go, and possibly a weakness too, is that the rules for arranging your project are very open.

The simplest absolute rule in Go is that a directory can only contain one package.

A directory can have a second package, but, that second package can only be the _test sister of the first package in the directory. That is, you can only have example and example_test in the directory. There is nothing preventing a developer placing sub-directories within that directory, but those sub directories must adhere to the single package name per directory (you may reuse package names, because the path is different, but that is really bad practice).

Packages

Main package

If the project is meant to provide a compiled binary, then the project must have a main package, and within that package there must be a func main(){} (main function).

The main package cannot be imported, not even by a corresponding main_test package, and there are no rules on the file names that make up the main package.

Documentation package

Files in the documentation package will not be tested or compiled.

Directories

CMD directory

There is a de facto standard to put the main package for a project into a cmd directory. It’s not required, but it does help people unfamiliar with a project to quickly find the main package.

Vendor directory

From Go 1.5 onward a directory named vendor included with a project allowed a project to be distributed with external dependency packages. Most go tools will not look in a vendor directory.

Testdata directory

The testdata directory will be ignored by the go tool, and go help test says that the directory named testdata is intended to hold ancillary data needed by tests, which, in practice, means almost anything can be placed in the directory, but convention dictates that that anything be test related.

Internal directory

The internal directory prevents packages in sub-directories from being imported from outside a the project. The usage of such a directory is such that the sub-packages are intended to never be imported by people creating tools that wish to make use of this project.

Files

Files with names starting with “.” or “_”

A file name that starts with a period “.” or underscore “_” is ignored by Go tools, and are therefore not tested or compiled.

Build constraints

Go allows files in a package to be built for a specified target, but ignored for other targets. This is achieved with a comment in the first line that lists the conditions under which a file is included in a package. The constraints can describe an operating system, architecture, a Go version, a compiler, CGO support, or any other requirements for a target system. eg.

// +build !linux

Other

There is only one other package, directory, or file naming convention, which isn’t enforced by anyone, but should be, and isn’t Go specific in any way. Generic names such as tools, utils, common, etc are tempting, but should never exist. The name has next to no meaning (and the whole point of naming is to convey meaning to other developers, including future you).

Taking all of these rules into account, it’s clear that there is a lot of freedom available for project layout. It’s best not to overthink things. Create directories that group together packages for easy discovery. If your project has several interfaces that it exposes (REST, gRPC, etc) that other developers will need to find to be able to interact with your project, then make a directory that holds them all and name it appropriately.

If a developer thinks of all the packages within a project being created as libraries that the main package is going to draw together for the application, it makes a lot clearer how to layout the project.

Published:
comments powered by Disqus