aboutsummaryrefslogtreecommitdiff
path: root/_content/doc/modules
diff options
context:
space:
mode:
authorEli Bendersky <eliben@golang.org>2023-09-19 05:05:06 -0700
committerEli Bendersky‎ <eliben@golang.org>2023-09-19 15:56:02 +0000
commitdf06bf701ca8577b93466ec2fe313e75662887b6 (patch)
treec3807c5e66693a4e8488a9cbf8ea540ee3fccf9f /_content/doc/modules
parentfeb9e77f0d94038e38181bdfcd6514a2d118c563 (diff)
downloadgo-x-website-df06bf701ca8577b93466ec2fe313e75662887b6.tar.xz
_content/doc: add guide for organizing a Go module (project layout)
Change-Id: I2092a70e0be3dbbd08d0b13c4bd4bd073a504cde Reviewed-on: https://go-review.googlesource.com/c/website/+/529415 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Diffstat (limited to '_content/doc/modules')
-rw-r--r--_content/doc/modules/layout.md288
1 files changed, 288 insertions, 0 deletions
diff --git a/_content/doc/modules/layout.md b/_content/doc/modules/layout.md
new file mode 100644
index 00000000..90196e25
--- /dev/null
+++ b/_content/doc/modules/layout.md
@@ -0,0 +1,288 @@
+<!--{
+ "Title": "Organizing a Go module"
+}-->
+
+A common question developers new to Go have is "How do I organize my Go
+project?", in terms of the layout of files and folders. The goal of this
+document is to provide some guidelines that will help answer this question. To
+make the most of this document, make sure you're familiar with the basics of Go
+modules by reading [the tutorial](/doc/tutorial/create-module) and
+[managing module source](/doc/modules/managing-source).
+
+Go projects can include packages, command-line programs or a combination of the
+two. This guide is organized by project type.
+
+### Basic package
+
+A basic Go package has all its code in the project's root directory. The project
+consists of a single module, which consists of a single package. The package
+name matches the last path component of the module name. For a very simple
+package requiring a single Go file, the project structure is:
+
+```
+project-root-directory/
+ go.mod
+ modname.go
+ modname_test.go
+```
+
+_[throughout this document, file/package names are entirely arbitrary]_
+
+Assuming this directory is uploaded to a GitHub repository at
+`github.com/someuser/modname`, the `module` line in the `go.mod` file should say
+`module github.com/someuser/modname`.
+
+The code in `modname.go` declares the package with:
+
+```
+package modname
+
+// ... package code here
+```
+
+Users can then rely on this package by `import`-ing it in their Go code with:
+
+```
+import "github.com/someuser/modname"
+```
+
+A Go package can be split into multiple files, all residing within the same
+directory, e.g.:
+
+```
+project-root-directory/
+ go.mod
+ modname.go
+ modname_test.go
+ auth.go
+ auto_test.go
+ hash.go
+ hash_test.go
+```
+
+All the files in the directory declare `package modname`.
+
+### Basic command
+
+A basic executable program (or command-line tool) is structured according to its
+complexity and code size. The simplest program can consist of a single Go file
+where `func main` is defined. Larger programs can have their code split across
+multiple files, all declaring `package main`:
+
+```
+project-root-directory/
+ go.mod
+ auth.go
+ auth_test.go
+ client.go
+ main.go
+```
+
+Here the `main.go` file contains `func main`, but this is just a convention. The
+"main" file can also be called `modname.go` (for an appropriate value of
+`modname`) or anything else.
+
+Assuming this directory is uploaded to a GitHub repository at
+`github.com/someuser/modname`, the `module` line in the `go.mod` file should
+say:
+
+```
+module github.com/someuser/modname
+```
+
+And a user should be able to install it on their machine with:
+
+```
+$ go install github.com/someuser/modname@latest
+```
+
+### Package or command with supporting packages
+
+Larger packages or commands may benefit from splitting off some functionality
+into supporting packages. Initially, it's recommended placing such packages into
+a directory named `internal`;
+[this prevents](https://pkg.go.dev/cmd/go#hdr-Internal_Directories) other
+modules from depending on packages we don't necessarily want to expose and
+support for external uses. Since other projects cannot import code from our
+`internal` directory, we're free to refactor its API and generally move things
+around without breaking external users. The project structure for a package is
+thus:
+
+```
+project-root-directory/
+ internal/
+ auth/
+ auth.go
+ auth_test.go
+ hash/
+ hash.go
+ hash_test.go
+ go.mod
+ modname.go
+ modname_test.go
+```
+
+The `modname.go` file declares `package modname`, `auth.go` declares `package
+auth` and so on. `modname.go` can import the `auth` package as follows:
+
+```
+import "github.com/someuser/modname/internal/auth"
+```
+
+The layout for a command with supporting packages in an `internal` directory is
+very similar, except that the file(s) in the root directory declare `package
+main`.
+
+### Multiple packages
+
+A module can consist of multiple importable packages; each package has its own
+directory, and can be structured hierarchically. Here's a sample project
+structure:
+
+```
+project-root-directory/
+ go.mod
+ modname.go
+ modname_test.go
+ auth/
+ auth.go
+ auth_test.go
+ token/
+ token.go
+ token_test.go
+ hash/
+ hash.go
+ internal/
+ trace/
+ trace.go
+```
+
+As a reminder, we assume that the `module` line in `go.mod` says:
+
+```
+module github.com/someuser/modname
+```
+
+The `modname` package resides in the root directory, declares `package modname`
+and can be imported by users with:
+
+```
+import "github.com/someuser/modname"
+```
+
+Sub-packages can be imported by users as follows:
+
+```
+import "github.com/someuser/modname/auth"
+import "github.com/someuser/modname/auth/token"
+import "github.com/someuser/modname/hash"
+```
+
+Package `trace` that resides in `internal/trace` cannot be imported outside this
+module. It's recommended to keep packages in `internal` as much as possible.
+
+### Multiple commands
+
+Multiple programs in the same repository will typically have separate directories:
+
+```
+project-root-directory/
+ go.mod
+ internal/
+ ... shared internal packages
+ prog1/
+ main.go
+ prog2/
+ main.go
+```
+
+In each directory, the program's Go files declare `package main`. A top-level
+`internal` directory can contain shared packages used by all commands in the
+repository.
+
+Users can install these programs as follows:
+
+```
+$ go install github.com/someuser/modname/prog1@latest
+$ go install github.com/someuser/modname/prog2@latest
+```
+
+A common convention is placing all commands in a repository into a `cmd`
+directory; while this isn't strictly necessary in a repository that consists
+only of commands, it's very useful in a mixed repository that has both commands
+and importable packages, as we will discuss next.
+
+### Packages and commands in the same repository
+
+Sometimes a repository will provide both importable packages and installable
+commands with related functionality. Here's a sample project structure for such
+a repository:
+
+```
+project-root-directory/
+ go.mod
+ modname.go
+ modname_test.go
+ auth/
+ auth.go
+ auth_test.go
+ internal/
+ ... internal packages
+ cmd/
+ prog1/
+ main.go
+ prog2/
+ main.go
+```
+
+Assuming this module is called `github.com/someuser/modname`, users can now both
+import packages from it:
+
+```
+import "github.com/someuser/modname"
+import "github.com/someuser/modname/auth"
+```
+
+And install programs from it:
+
+```
+$ go install github.com/someuser/modname/cmd/prog1@latest
+$ go install github.com/someuser/modname/cmd/prog2@latest
+```
+
+### Server project
+
+Go is a common language choice for implementing *servers*. There is a very large
+variance in the structure of such projects, given the many aspects of server
+development: protocols (REST? gRPC?), deployments, front-end files,
+containerization, scripts and so on. We will focus our guidance here on the
+parts of the project written in Go.
+
+Server projects typically won't have packages for export, since a server is
+usually a self-contained binary (or a group of binaries). Therefore, it's
+recommended to keep the Go packages implementing the server's logic in the
+`internal` directory. Moreover, since the project is likely to have many other
+directories with non-Go files, it's a good idea to keep all Go commands together
+in a `cmd` directory:
+
+```
+project-root-directory/
+ go.mod
+ internal/
+ auth/
+ ...
+ metrics/
+ ...
+ model/
+ ...
+ cmd/
+ api-server/
+ main.go
+ metrics-analyzer/
+ main.go
+ ...
+ ... the project's other directories with non-Go code
+```
+
+In case the server repository grows packages that become useful for sharing with
+other projects, it's best to split these off to separate modules.