一架梯子,一头程序猿,仰望星空!
Golang开发规范 > 内容正文

Go项目目录结构规范最佳实践


概述

这是一个针对Go应用程序项目的基本布局。它并不是由Go核心开发团队定义的官方标准;他是社区GO项目比较常用的目录布局。

如果你想学习Go或者正在构建一个概念验证(PoC)或者一个简单的个人项目,这个项目布局就过于复杂了。相反,应该从一个真正简单的布局开始(只有一个 main.go 文件和 go.mod 足够了)。 当你的项目不断发展时,记得确保你的代码结构良好,否则你最终会得到一个混乱的代码,包含大量隐藏的依赖和全局状态。当有更多人参与到项目中时,你需要更多的结构化方式。在这种情况下,引入一种常见的管理包/库的方式就很重要。当你有一个开源项目或者知道其他项目从你的项目仓库导入代码时,拥有私有(也称为internal)的包和代码就变得重要了。克隆仓库,保留所需的部分,删除其他一切!仅仅因为它存在,并不意味着你必须全部使用。这些模式没有一个在每个项目中都被使用。即使是vendor模式也不是普遍的。

这个项目布局是故意设计得很通用,并且不试图强加一个特定的Go包结构。

Go项目目录规范

下面是推荐的Go项目目录规范。

.
├── go.mod
├── api
├── assets
├── build
├── cmd
├── configs
├── deployments
├── docs
├── examples
├── githooks
├── go.mod
├── init
├── internal
├── pkg
├── scripts
├── test
├── third_party
├── tools
├── vendor
├── web
└── website

下面分别介绍各个目录的含义。

/cmd

该项目的主要应用程序,也就是程序入口,这个目录下面的go文件通常会生成一个个的可执行文件,简单的项目里面放一个类似/test/main.go的文件作为入口即可。

每个应用程序的目录名称应与您想要的可执行文件的名称相匹配(例如/cmd/myapp)。

不要在应用程序目录中放置太多代码。如果您认为该代码可以在其他项目中导入和使用,则应将其放在/pkg目录中。如果代码不可重用或者您不希望其他人重用它,请将该代码放在/internal目录中。您会对其他人的行为感到惊讶,所以对您的意图要明确表达!

通常会有一个小的main函数,其从/internal/pkg目录导入和调用代码,除此之外没有其他内容。

/internal

私有应用程序和库代码。这是您不希望其他人在其应用程序或库中导入的代码。请注意,这种布局模式是由Go编译器本身强制执行的。有关更多详细信息,请参阅Go 1.4 发布说明。请注意,并不限于顶层internal目录。您可以在项目树的任何级别上拥有多个internal目录。

您可以选择为内部包添加一些额外的结构,以区分共享和非共享的内部代码。这并不是必需的(特别是对于较小的项目),但视觉上显示出意图的包使用方式是很好的。您的实际应用程序代码可以放在/internal/app目录中(例如,/internal/app/myapp),这些应用程序共享的代码可以放在/internal/pkg目录中(例如,/internal/pkg/myprivlib)。

/pkg

允许外部应用程序使用的库代码(例如,/pkg/mypubliclib)。其他项目将导入这些库,并希望它们能正常工作,因此在将内容放入此处之前请三思 :-) 请注意,internal目录是确保私有包不可导入的更好方法,因为Go自身强制执行该方法。/pkg目录仍然是明确传达该目录中的代码对他人使用是安全的好方法。

如果您的应用程序项目非常小,并且多层嵌套并没有增加太多价值,那么不使用它也是可以的(除非您真的想使用它 :-))。当项目变得足够大,并且根目录变得非常繁忙时,请考虑使用它(特别是如果您有很多非Go应用组件)。

/vendor

应用程序依赖项(手动管理或使用您喜欢的依赖管理工具,如内置的 Go Modules 特性)。go mod vendor 命令将为您创建 /vendor 目录。请注意,如果您不使用默认启用的 Go 1.14 版本,可能需要向 go build 命令添加 -mod=vendor 标志。

如果您正在构建一个库,请不要提交您的应用程序依赖项。

服务应用程序目录

/api

OpenAPI/Swagger 规范,JSON 模式文件,协议定义文件,Api协议目录。

Web 应用程序目录

/web

Web 应用程序的特定组件:静态网站资产,服务器端模板和单页应用程序(SPA)。

通用应用程序目录

/configs

配置文件模板或默认配置。

将您的 confdconsul-template 模板文件放在此处。

/init

系统初始化(systemd,upstart,sysv)和进程管理器/守护进程(runit,supervisord)配置。

/scripts

执行各种构建,安装,分析等操作的脚本。

/build

打包和持续集成。

将云(AMI),容器(Docker),操作系统(deb,rpm,pkg)包配置和脚本放在 /build/package 目录中。

将持续集成(travis,circle,drone)配置和脚本放在 /build/ci 目录中。请注意,某些持续集成工具(例如 Travis CI)对其配置文件的位置非常挑剔。尽量将配置文件放在 /build/ci 目录中,并使用连接将其链接到持续集成工具期望的位置(如果可能)。

/deployments

IaaS,PaaS,系统和容器编排部署配置和模板(docker-compose,kubernetes/helm,terraform)。请注意,在某些存储库中(特别是使用 kubernetes 部署的应用程序),此目录被称为 /deploy

/test

其他外部测试应用程序和测试数据。随意按照您希望的方式构建 /test 目录。对于较大的项目,将数据放入子目录中是有意义的。例如,您可以在 /test 中创建 /test/data/test/testdata 目录,以便让 Go 忽略其中包含的内容。请注意,Go 还将忽略以 “.” 或 “_” 开头的目录或文件,因此您在命名测试数据目录时具有更大的灵活性。

其他目录

/docs

设计和用户文档(除了您生成的 godoc 文档)。

/tools

此项目的支持工具。请注意,这些工具可以导入 /pkg/internal 目录中的代码。

/examples

应用程序和/或公共库的示例。

/third_party

外部辅助工具,fork 的代码和其他第三方实用工具(例如,Swagger UI)。

/githooks

Git 钩子。

/assets

与存储库一起提供的其他资产(图像,标志等)。

/website

如果您没有使用 GitHub 页面,则这是放置项目网站数据的位置。

不应存在的目录

/src

在一些Go项目中会有一个src文件夹,但这通常是由于开发人员来自Java世界,其中这是一个常见的模式。如果可能的话,尽量不要采用这种Java模式。你真的不想让你的Go代码或项目看起来像Java :-)

不要把项目级别的/src目录与Go用于工作区的/src目录搞混,后者在如何编写Go代码中有描述。$GOPATH环境变量指向你的(当前的)工作区(默认情况下,在非Windows系统上它指向$HOME/go目录)。该工作区包括顶级的/pkg/bin/src目录。你的实际项目将成为/src目录下的子目录,所以如果你的项目中有/src目录,项目路径将如下所示:/some/path/to/workspace/src/your_project/src/your_code.go。请注意,从Go 1.11开始,你的项目可以位于GOPATH之外,但这并不意味着使用这种布局模式是个好主意。