原文:https://makeoptim.com/golang/standards/project-layout

  • 目录结构
  • Go 目录
    • cmd
    • internal
    • pkg
    • vendor
  • 服务端应用程序目录
    • api
  • Web 应用程序目录
    • web
  • 通用应用程序目录
    • build
    • configs
    • deployments
    • init
    • scripts
    • test
  • 其他目录
    • assets
    • docs
    • examples
    • githooks
    • third_party
    • tools
    • website
  • 不应该出现的目录
    • src
  • 其他文件
    • Makefile
  • 小结
  • 延伸阅读
  • 参考

目录结构

项目的目录结构通常也是门面,内行人通过目录结构基本就能看出开发者是否有经验。

Go 官网并没有给出一个目录结构的标准模板,但是 golang-standards 倒是给出了一个,目录结构如下:

├── api
├── assets
├── build
│   ├── ci
│   └── package
├── cmd
│   └── _your_app_
├── configs
├── deployments
├── docs
├── examples
├── githooks
├── init
├── internal
│   ├── app
│   │   └── _your_app_
│   └── pkg
│       └── _your_private_lib_
├── pkg
│   └── _your_public_lib_
├── scripts
├── test
├── third_party
├── tools
├── vendor
├── web
│   ├── app
│   ├── static
│   └── template
├── website
├── .gitignore
├── LICENSE.md
├── Makefile
├── README.md
└── go.mod

Go 目录

cmd

cmdgrpc
/cmd/pkg/internal/cmd

例子:

  • https://github.com/heptio/ark/tree/master/cmd
  • https://github.com/moby/moby/tree/master/cmd
  • https://github.com/prometheus/prometheus/tree/master/cmd
  • https://github.com/influxdata/influxdb/tree/master/cmd
  • https://github.com/kubernetes/kubernetes/tree/master/cmd
  • https://github.com/satellity/satellity/tree/master/cmd
  • https://github.com/dapr/dapr/tree/master/cmd

internal

私有的应用程序代码库。这些是不希望被其他人导入的代码。请注意:这种模式是 Go 编译器强制执行的。详细内容情况 Go 1.4 的 release notes。并且,在项目的目录树中的任意位置都可以有 internal 目录,而不仅仅是在顶级目录中。

/internal/appinternal/app/myapp/internal/pkginternal/pkg/myprivlib

pkg

/pkg/mypubliclib/pkgpkginernal

当根目录包含大量非 Go 组件和目录时,这也是一种将 Go 代码分组到一个位置的方法,从而使运行各种 Go 工具更加容易(在如下的文章中都有提到:2018 年 GopherCon Best Practices for Industrial Programming,GopherCon 2018: Kat Zien – How Do You Structure Your Go Apps,Golab 2018 Massimiliano Pippi – Project layout patterns in Go。

/pkg 在许多开源项目中都使用了,但未被普遍接受,并且 Go 社区中的某些人不推荐这样做。

/pkg

vendor

go mod vendor/vendorgo build-mod=vendor

构建库文件时,不要提交应用程序依赖项。

请注意,从 1.13 开始,Go 也启动了模块代理特性(使用 https://proxy.golang.org 作为默认的模块代理服务器)。点击这里阅读有关它的更多信息,来了解它是否符合所需要求和约束。如果 Go Module 满足需要,那么就不需要 vendor 目录。

github.com/golang/project/pkg/somepkggithub.com/golang/project

服务端应用程序目录

api

项目对外提供和依赖的 API 文件。比如:OpenAPI/Swagger specs, JSON schema 文件, protocol 定义文件等。

比如,Kubernetes 项目的 api 目录结构如下:

api
├── api-rules
    └── xxx.plist
├── openapi-spec
    └── swagger.json

因此,在 go 中用的比较多的 gRPC proto 文件,也比较适合放在 api 目录下

api
└── protobuf-spec
    └── test
        ├── test.pb.go
        └── test.proto

Web 应用程序目录

web

Web 应用程序特定的组件:静态 Web 资源,服务器端模板和单页应用(Single-Page App,SPA)

通用应用程序目录

build

打包和持续集成所需的文件。

  • build/ci:存放持续集成的配置和脚本,如果持续集成平台对配置文件有路径要求,则可将其 link 到指定位置。
  • build/package:存放 AMI、Docker、系统包(deb、rpm、pkg)的配置和脚本等。

例子:

  • https://github.com/cockroachdb/cockroach/tree/master/build

configs

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

deployments

IaaS,PaaS,系统和容器编排部署配置和模板(docker-compose,kubernetes/helm,mesos,terraform,bosh)。请注意,在某些存储库中(尤其是使用 kubernetes 部署的应用程序),该目录的名字是 /deploy

init

系统初始化(systemd、upstart、sysv)和进程管理(runit、supervisord)配置。

scripts

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

这些脚本使根级别的 Makefile 变得更小更简单,例如:https://github.com/hashicorp/terraform/blob/master/Makefile。

test

/test/test/data/test/testdata

其他目录

assets

项目中使用的其他资源(图像、logo 等)。

docs

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

examples

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

githooks

Git 钩子。

third_party

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

tools

/pkg/internal

例子:

  • https://github.com/istio/istio/tree/master/tools
  • https://github.com/openshift/origin/tree/master/tools
  • https://github.com/dapr/dapr/tree/master/tools

website

如果不使用 Github pages,则在这里放置项目的网站数据。

例子:

  • https://github.com/hashicorp/vault/tree/master/website
  • https://github.com/perkeep/perkeep/tree/master/website

不应该出现的目录

src

src
/src/src$GOPATH/pkg/bin/src/src/src/some/path/to/workspace/src/your_project/src/your_code.goGOPATH

其他文件

Makefile

/scripts

小结

每个公司、组织内部都有自己的组织方式,但每个项目都应该有一定的规范。虽然这种规范的约定没有那么强制,但是只要达成了一致之后,对于团队中组员快速理解和入门项目都是很有帮助的。有时候一些规范,就是团队的共同语言,定好了规范,减少了不必要的重复沟通,有利于提高整体的效率

项目目录也一样,本篇文章讲的是参考 golang-standards 提供的规范。但是,最重要的还是要与自己的团队商量,讨论并整理出适合自己的一套项目目录规范

一致的项目目录规范,有助于组员快速理解其他人的代码,不容易造成团队的”单点故障“;团队团结一致,共同维护和升级项目目录结构,可不断沉淀,不断提高效率,减少犯错

延伸阅读

  • 在 Golang 上使用整洁架构(Clean Architecture)
  • 在 Golang 上使用整洁架构(Clean Architecture)-2
  • 在 Golang 上使用整洁架构(Clean Architecture)-3
  • Effective Go 中文
  • Code Review 规范

参考

  • https://github.com/golang-standards/project-layout