1.前言
不管是什么语言,开发什么项目,一个稍大的项目,必然要面临如何管理项目结构布局的问题,因为一个简洁清晰的布局是项目可读的关键。
有些语言自身提供了目录结构规范,但对于较为年轻的 Golang,目前官方团队并未提供权威规范。不过不用担心,我们依然有一个规范可以参考,那就是业界推崇的 Standard Go Project Layout。
2.项目布局
2.1 整体风格
你的项目结构布局看起来应该像下面这个样子。
# Go 代码目录
|--cmd 可执行文件目录
|--internal 私有库代码(仅本项目使用)
|--pkg 公有库代码(外部项目可以使用)
|--vendor 外部依赖库
# 服务应用程序目录
|--api 服务对外接口
# Web 应用程序目录
|--web Web 应用程序的组件
# 通用应用目录
|--configs 配置信息
|--init 初始化信息
|--scripts 执行各种构建、安装、分析等操作的脚本
|--build 打包和持续集成
|-- package 构建依赖包
|-- ci 持续集成配置与脚本
|--deployments 部署相关
|--test 测试相关
|--README.md 项目说明
# 其他目录
|--docs 项目文档
|--tools 项目工具
|--examples 应用程序和公共库的示例
|--third_party 外部辅助工具
|--githooks Git 钩子
|--assets 项目资源文件
|--website 项目网站数据
# 不应该拥有的目录
|--src 源码目录
2.2 Go 代码目录
/cmd
可执行文件目录。
目录可以包含多个可执行文件,子目录名一般与可执行文件名相匹配(如 /cmd/myapp )。
通常只包含一个简单的 main 函数,调用 /internal 和 /pkg 中的代码,作为项目的主应用目录。
不要在该目录下放太多的代码,如果代码可以被其他项目导入使用,请放到 /pkg 目录下,如果代码不可复用或者你不希望其他项目使用,请放到 /internal 目录下。
/internal
私有库代码(仅本项目使用)。
这里放不希望被其他应用程序或者库导入的代码。注意:从 Go1.4 起,从编译器层面限制该目录不可被导出,而且不只是项目根目录下的 internal,所有名为 internal 的子目录都不能被导出。
你还可以在 internal 目录内部增加一些代码结构来区分共享和非共享的。虽然它并不是必须的(尤其是小的项目),但是最好能从视觉上区分包的用途。 你实际的代码可以放在 /internal/app/myapp 中,而应用的共享代码可以放在 /internal/pkg/ 目录下。
/pkg
公有库代码(外部项目可以使用)。
这里放希望被其他应用程序或者库导入的代码,所以在这里放东西之前要三思。
含有 /pkg 目录的项目结构是一种常见的布局模式,但并不是所有人都接受它,一些 Go 社区的人并不推荐它。
/vendor
外部依赖库。
如果手动管理依赖包可以将依赖包放到该目录,当然推荐使用依赖包管理工具 Go Modules 进行自动化管理。
注意,1.11 开始,官方推荐使用新的依赖管理系统 Go Modules。从 1.13 以后,Go 还启用了模块代理功能(默认使用 https://proxy.golang.org 作为他们的模块代理服务器)。使用 Go Modules,我们并不需要 vendor 目录。
2.3 服务应用程序目录
/api
服务对外接口。
这里是服务对外接口的实现,定义接口时,我们应该遵循 OpenAPI Specification。
2.4 Web 应用程序目录
/web
存放 Web 应用程序特定组件,如静态 Web 资源、服务器端模板和 SPA(Single Page Application)。
2.5 通用应用目录
/configs
配置信息。
如不同环境(测试、正式)的服务配置信息。
/init
初始化信息。
系统初始化(systemd, upstart, sysv)和进程管理(runit, supervisord)配置。
/scripts
执行各种构建、安装、分析等操作的脚本。
这些脚本帮助根目录下 Makefile(如果有的话)变得小而简单,例如 github/hashicorp/terraform/Makefile。
/build
打包和持续集成。
将你的云( AMI )、容器( Docker )、操作系统( deb、rpm、pkg )包配置和脚本放在 /build/package 目录下。
将你的 CI (travis、circle、drone)配置和脚本放在 /build/ci 目录下。
/deployments
部署相关。
如 IaaS、PaaS、系统和容器编排部署配置和模板(docker-compose、kubernetes/helm、mesos、terraform、bosh)。注意,在一些存储库中(特别是使用 kubernetes 部署的应用程序),这个目录被称为 /deploy。
/test
测试相关。
如放置测试工具和测试依赖数据。对于较大的项目,有一个数据子目录是有意义的。例如,你可以使用 /test/data 或 /test/testdata。请注意,如果你需要忽略目录中的内容,Go 还会忽略以“.”或“_”开头的目录或文件,因此在如何命名测试数据目录方面有更大的灵活性。
/README.md
项目说明。
Markdown 格式的说明文档,是用户了解一个项目最直观的入口。如果有需要,添加不同语言的 README 将更加人性化,如 简体中文 README_zh-CN.md。
2.6 其他目录
/docs
项目文档。
关于项目的设计文档,用户的使用文档等(除了 godoc 生成的文档之外)均可以放在该目录。
/tools
项目工具。
项目配套工具,实现这些工具可以使用从 /pkg 和 /internal 导入代码。
/examples
应用程序和公共库的示例。
丰富的示例将帮助用户更加便捷快速的了解上手一个项目,再加上 README,相得益彰。
/third_party
外部辅助工具。
项目依赖的第三方工具,比如 Swagger UI。
/githooks
Git 钩子。
使用 Git 钩子,可以帮忙我们在代码提交时完成一些检测,比如分支名称和 commit 信息是否符合规范。
/assets
项目资源文件。
项目用到的相关资源文件,比如项目 Logo,README 中引用的图片等。
/website
项目网站数据。
如果你不使用 Github 页面,则在这里放置项目网站数据。
2.7 不应该拥有的目录
/src
源码目录。
有些 Go 项目确实有一个 src 目,但这通常发生在开发人员有 Java 背景。不同类型的代码应该有自己的目录,而不是全部放到 src 下面,就像不应该拥有 comm 和 util 这样的目录,因为这些名称含义太泛了,违背了单一职责原则。
3.小结
这是 Go 应用程序项目的基本布局,是社区 Gopher 们努力的结果。此项目布局是通用的,建议并非强制,当然我们最好遵守,因为这能让我的项目布局看起来更加规范,易于交流和维护。
如果发现此项目布局规范并不适用自己的项目,可在其基础上适当做出改变,不要泥古拘方。