平铺式

主要用在 Go 包(框架、库)中,相对来说比较简单,如 glog

1
2
# ls
LICENSE README.md glog.go glog_file.go glog_test.go go.mod

结构化

主要用在 Go 应用中,相对来说比较复杂,事实规范:project-layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
├── api
│ ├── openapi
│ └── swagger
├── build
│ ├── ci
│ ├── docker
│ │ ├── iam-apiserver
│ │ ├── iam-authz-server
│ │ └── iam-pump
│ ├── package
├── CHANGELOG
├── cmd
│ ├── iam-apiserver
│ │ └── apiserver.go
│ ├── iam-authz-server
│ │ └── authzserver.go
│ ├── iamctl
│ │ └── iamctl.go
│ └── iam-pump
│ └── pump.go
├── configs
├── CONTRIBUTING.md
├── deployments
├── docs
│ ├── devel
│ │ ├── en-US
│ │ └── zh-CN
│ ├── guide
│ │ ├── en-US
│ │ └── zh-CN
│ ├── images
│ └── README.md
├── examples
├── githooks
├── go.mod
├── go.sum
├── init
├── internal
│ ├── apiserver
│ │ ├── api
│ │ │ └── v1
│ │ │ └── user
│ │ ├── apiserver.go
│ │ ├── options
│ │ ├── service
│ │ ├── store
│ │ │ ├── mysql
│ │ │ ├── fake
│ │ └── testing
│ ├── authzserver
│ │ ├── api
│ │ │ └── v1
│ │ │ └── authorize
│ │ ├── options
│ │ ├── store
│ │ └── testing
│ ├── iamctl
│ │ ├── cmd
│ │ │ ├── completion
│ │ │ ├── user
│ │ └── util
│ ├── pkg
│ │ ├── code
│ │ ├── options
│ │ ├── server
│ │ ├── util
│ │ └── validation
├── LICENSE
├── Makefile
├── _output
│ ├── platforms
│ │ └── linux
│ │ └── amd64
├── pkg
│ ├── util
│ │ └── genutil
├── README.md
├── scripts
│ ├── lib
│ ├── make-rules
├── test
│ ├── testdata
├── third_party
│ └── forked
└── tools

0f494d5c9f706a7564d4d7280093e81f

Go 应用

开发相关

/web

  1. 前端代码存放目录,主要用来存放 Web 静态资源、服务端模板、单页应用

/cmd

  1. 一个项目有很多组件,可以将组件的 main 函数所在的文件夹统一放在 /cmd 目录
  2. 每个组件的目录名应该与预期的可执行文件名一致
  3. 保证 /cmd/<组件> 目录下不要存放太多代码
    • 如果代码可以复用,应该位于 /pkg 目录
    • 如果代码不可复用,应该位于 /internal 目录
1
2
3
4
5
# ls cmd/
gendocs geniamdocs genman genswaggertypedocs genyaml iam-apiserver iam-authz-server iamctl iam-pump

# ls cmd/iam-apiserver/
apiserver.go

/internal

  1. 存放私有应用和库代码
  2. 在引入其他项目 internal 下的包时,会在编译时报错
  3. 建议
    • /internal/apiserver:存放真实的应用代码,这些应用的共享代码存放在 /internal/pkg
    • /internal/pkg:存放项目内可共享,项目外不共享的包,提供一些比较基础通用的功能
    • 一开始将所有的共享代码都放在 /internal/pkg 下,当共享代码做好了对外开放的准备后,再转存到 /pkg
1
An import of a path containing the element “internal” is disallowed if the importing code is outside the tree rooted at the parent of the "internal" directory.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
├── apiserver             # 应用
│ ├── api
│ │ └── v1 # HTTP API 接口的具体实现,主要用来串流程(轻量级)
│ │ └── user
│ ├── options # 应用的 command flag
│ ├── config # 根据命令行参数创建应用配置
│ ├── service # 存放应用复杂业务处理代码
│ │ └── user.go
│ ├── store # 持久化
│ │ ├── mysql
│ │ │ └── user.go
│ │ ├── fake
│ └── testing
├── authzserver # 应用
│ ├── api
│ │ └── v1
│ ├── options
│ ├── store
│ └── testing
├── iamctl # 对于大型项目,一般都会有一个客户端工具
│ ├── cmd
│ │ ├── cmd.go
│ │ ├── info
└── pkg # 内部共享包
├── code # 业务 Code
├── middleware # HTTP 处理链
├── options
└── validation # 通用的验证函数

/pkg

  1. 存放可以被外部应用使用的代码库,其他项目可以直接通过 import 导入,将代码库放在该目录要慎重

/vendor

  1. 项目依赖,可以通过 go mod vendor 创建,如果是一个 Go 库,不要提交 vendor 包

/third_party

  1. 外部帮助工具,分支代码或者其他第三方应用(如 Swagger UI )
  2. /third_party/forked/xxx,与 upstream 保持同步

测试相关

/test

  1. 存放其他外部测试应用和测试数据
  2. Go 会忽略以 ._ 开头的目录或者文件

部署相关

/configs

  1. 存放配置文件模板或者默认配置
  2. 配置中不能携带敏感信息,可以用占位符来替代
1
2
3
4
apiVersion: v1    
user:
username: ${CONFIG_USER_USERNAME}
password: ${CONFIG_USER_PASSWORD}

/deployments

  1. 用来存放 IaaSPaaS 系统和容器编排部署的配置和模板
    • Docker-ComposeKubernetes/HelmMesosTerraformBosh
  2. 用 Kubernetes 部署的项目,目录名可能为 deploy – 容器化是大势所趋

/init

  1. 主要用于非容器化部署的项目,存放初始化系统(systemd 等)和进程管理配置文件(unit 文件等)

项目管理

/Makefile

  1. Makefile 是很老但仍然优秀项目管理工具
  2. Makefile 通常用来:静态代码检查单元测试编译
  3. make 默认操作(推荐):**gen -> format -> lint -> test -> build**

/scripts

  1. 存放脚本文件,用来实现构建安装分析等不同功能
  2. shell 中的函数名,建议采用语义化的命名方式(在 Kubernetes 中大量采用),如:iam::log::info
目录 描述
/scripts/make-rules 存放 makefile 文件,实现 /Makefile 中的各个功能(为了保持 /Makefile 的简洁)
/scripts/lib shell 库,是 shell 脚本的一些通用功能,可以抽象成库
/scripts/install 自动化部署

/build

  1. 存放安装包和 CI 相关的文件
目录 描述
/build/package 存放容器(Docker)、系统(deb, rpm, pkg)的包配置和脚本
/build/ci 存放 CI(travis)的配置文件和脚本
/build/docker 存放子项目各个组件的 Dockerfile

/tools

  1. 存放项目的支持工具(可导入来自于 /pkg 和 /internal 的代码)

/githooks

  1. Git 钩子

/assets

  1. 项目使用到的其他资源:图片、CSS、JS等

/website

  1. 项目网站相关的数据

文档

/README.md

  1. 包含项目的介绍、功能、快速安装、使用指引、开发指引和详细的文档链接
  2. README 可以规范化,通过工具或者脚本生成

/docs

  1. 设计文档、开发文档、用户文档等
  2. /docs/devel/{en-US,zh-CN}
  3. /docs/guide/{en-US,zh-CN}
  4. /docs/images

/CONTRIBUTING.md

  1. 对于开源就绪的项目,需要 /CONTRIBUTING.md
  2. 用途:规范协同流程 + 降低第三方开发者贡献代码的难度

/api

  1. 存放当前项目对外提供的各种不同类型的 API 接口定义文件
  2. API 类型:protobuf、thrift、http、openapi、swagger
1
2
3
4
5
6
├── openapi/
│ └── README.md
└── swagger/
├── docs/
├── README.md
└── swagger.yaml

/LICENSE

  1. 版本文件可以是私有的,也可以是开源
  2. 自动化
    • addlicense:将 LICENSE 头添加到源码文件或者其他文件
    • glice:检查对开源代码的引用

/CHANGELOG

  1. 记录更新记录,自动化: Angular 规范 + git-chglog

/examples

  1. 示例代码,降低使用者的上手门槛

不建议的目录

不符合 Go 的设计哲学

目录 描述
/src/ Java 中有 src 目录,默认情况下,Go 项目都会被放置在 $GOPATH/src 目录下
/model 按功能拆分是 Go 的设计哲学,因此不要将类型定义统一放到 /model 目录
xxs/ 统一使用单数

建议

  1. 对于小型项目,优先考虑:cmd、pkg、internal,其他目录按需创建
  2. 空目录无法提交到 Git 仓库,可以使用 .keep 文件
1
2
3
4
├── cmd
├── internal
├── pkg
└── README.md