Go语言项目布局
参考
Golang项目布局开源项目-29.1K Stars
《Go语言精进之路》第二部分
GopherCon 2018: Kat Zien - How Do You Structure Your Go Apps
1. 前言
在项目中,合理的布局会让项目更加清晰。随着项目的增长,保持良好的项目结构非常重要,否则最终会得到一团混乱的代码。为了便于开发者协作,最好使用通用的结构,下面这个开源项目中介绍了 Go 语言项目布局的最佳实践,目前有接近 3 万个 star,对我后续的开发还是有一定参考价值的。
https://github.com/golang-standards/project-layout
从 Go 1.14
开始,建议Go项目使用Go Modules 进行依赖管理,用 go.mod
来记录特定的依赖信息。
2. Go语言自身结构
作为 Go 语言的创世项目,Go 的项目结构的布局对后续的 Go 语言项目具有重要的参考意义。下面的结构基于 Go 1.16
$ tree -LF 1 /usr/local/go
/usr/local/go
├── AUTHORS
├── CONTRIBUTING.md
├── CONTRIBUTORS
├── LICENSE
├── PATENTS
├── README.md
├── SECURITY.md
├── VERSION
├── api/
├── bin/
├── doc/
├── favicon.ico
├── lib/
├── misc/
├── pkg/
├── robots.txt
├── src/
└── test/
尤其是早期 Go 项目中 src
目录下面的结构,更是在后续被 Go 社区作为 Go 应用项目结构的模板广泛使用。
- 代码构建的脚本源文件放在
src
下面的顶层目录下。 src
下的二级目录cmd
下面存放着 Go 工具链相关的可执行文件(比如go
、gofmt
等)的主目录以及它们的main
包源文件。src
存放着上面cmd
下各工具链程序依赖的包、Go 运行时以及 Go 标准库的源文件。src
下面的二级目录internal
,用于存放无法被外部导入、仅 Go 项目自用的包。src
下面的go.mod
和go.sum
,实现了 Go 项目自身的go module
迁移。Go项目内所有包被放到名为std
的module
下面,其依赖的包依然是golang.org/x
下的各个包。
$ tree -LF 1 /usr/local/go/src
/usr/local/go/src
├── Make.dist
├── README.vendor
├── all.bash*
├── all.bat
├── all.rc*
├── archive/
├── bootstrap.bash*
├── bufio/
├── buildall.bash*
├── builtin/
├── bytes/
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── cmp.bash
├── compress/
├── container/
├── context/
├── crypto/
├── database/
├── debug/
├── embed/
├── encoding/
├── errors/
├── expvar/
├── flag/
├── fmt/
├── go/
├── go.mod
├── go.sum
├── hash/
├── html/
├── image/
├── index/
├── internal/
├── io/
├── log/
├── make.bash*
├── make.bat
├── make.rc*
├── math/
├── mime/
├── net/
├── os/
├── path/
├── plugin/
├── race.bash*
├── race.bat
├── reflect/
├── regexp/
├── run.bash*
├── run.bat
├── run.rc*
├── runtime/
├── sort/
├── strconv/
├── strings/
├── sync/
├── syscall/
├── testdata/
├── testing/
├── text/
├── time/
├── unicode/
├── unsafe/
└── vendor/
3. 以构建二进制可执行文件为目的的 Go 项目结构
下图是一个支持(在 cmd
下)构建二进制可执行文件的典型 Go 项目的结构。

cmd目录
:项目的主干,存放项目要构建的可执行文件对应的main
包的源文件。如果有多个可执行文件需要构建,则将每个可执行文件的main
包单独放在一个子目录中,比如图中的app1、app2
。一些Go项目将cmd
这个名字改为app
,但其功能并没有变。
通常有一个小的main
函数,从/internal
和/pkg
目录导入和调用代码。不要在这个目录中放置太多代码。如果你认为代码可以导入并在其他项目中使用,那么它应该位于/pkg
目录中。如果代码不是可重用的,或者你不希望其他人重用它,请将该代码放到/internal
目录中。pkg目录
:该目录下的包可以被外部项目引用,算是项目导出包的一个聚合。对于一些规模稍大的项目,过多的包会让项目顶层目录不再简洁,显得很拥挤,因此对于复杂的 Go 项目建议保留pkg
目录。internal目录
:对于不想暴露给外部引用,仅限项目内部使用的包,在项目结构上可以通过 Go 1.4 版本中引入的internal
包机制来实现。go.mod
和go.sum
:Go 语言包依赖管理使用的配置文件。Makefile
:项目构建工具所用脚本的“代表”,一般会放在build
目录下。
4. 通用应用目录
configs目录
:配置文件模板或默认配置。init目录
:系统初始化文件目录。scripts目录
:执行各种构建、安装、分析等操作的脚本。build目录
:打包和持续集成。将你的云( AMI )、容器( Docker )、操作系统( deb、rpm、pkg )包配置和脚本放在/build/package
目录下。将你的 CI (travis、circle、drone)配置和脚本放在/build/ci
目录中。test目录
:额外的外部测试应用程序和测试数据。
5. 其他目录
docs目录
:设计和用户文档(除了godoc
生成的文档之外)。tools目录
:这个项目的支持工具。注意,这些工具可以从/pkg
和/internal
目录导入代码。examples目录
:应用程序和/或公共库的示例。third_party目录
:外部辅助工具,分叉代码和其他第三方工具(例如 Swagger UI)。
可以根据项目需求合理添加其他目录结构。
注意:有些 Go 项目确实有一个 src
文件夹,但这通常发生在开发人员有 Java 背景,在那里它是一种常见的模式。如果可以的话,尽量不要采用这种 Java 模式。你真的不希望你的 Go 代码或 Go 项目看起来像 Java