Contents

Go项目惯用结构

前言

无论我们用什么语言,做什么项目,都应该事先对项目的整体文件夹布局做长远考虑:什么文件应该放哪里,这其实十分重要,一个清晰简洁的项目结构让其他贡献者更容易上手,也让自身的维护与拓展更加方便(还能让开发者显得专业懂行)。Go生态圈里有一个项目的常用结构,它十分普遍且广受认可,今天在这里记录一下,以后新建项目时好当个cheatsheet来用。

顶层文件目录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.
├── Makefile
├── README.MD
├── api/  # api接口定义文件(protobuf-spec, http-spec, swagger.yaml...)
├── build/ # 安装包、容器与ci构建文件(Dockerfile, DEBIAN, travis...)
├── cmd/ # 入口代码
├── configs/ # 配置文件的模板
├── deployments/ # 部署相关配置和模板(Docker-Compose, K8s/Helm...)
├── docs/ # 文档
├── go.mod
├── internal/ # 具体业务代码
├── pkg/ # 可复用代码
├── scripts/ # 脚本
└── web/ # 前端工程目录

基本上挺self-explanatory的,下面介绍在结合整洁架构的理念时几个文件里面具体的内容。

cmd/

1
2
3
cmd
└── apiserver/
    └── apiserver.go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main
import (
	"math/rand"
	"os"
	"runtime"
	"time"

	"github.com/midk9t/goproject/internal/apiserver"
)
func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	if len(os.Getenv("GOMAXPROCS")) == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}
	apiserver.NewApp("goproject").Run()
}

cmd目录负责存放每个可编译成可执行程序的入口代码,如上面的apiserver就负责启动api进程。每个cmd里的包都必须是main包,且不包含太多具体业务逻辑,而是负责调用internal/和pkg/里具体的包来使服务运行。

pkg/

1
2
3
pkg
├── app/
└── log/

pkg目录负责存放一些可以给其他项目调用的,足够通用的包,如上面的app与log就是业务无关的项目工具包。

internal/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiserver/
├── config/ # apiserver启动配置
├── controller/ # controller层
│   └── banana/
│       └── crud.go
├── domain/ # 领域层
│   └── banana.go # 模型定义
├── repo/ # 持久层
│   ├── fake/
│   └── mysql/
└── service/ # service层
    └── banana/
        └── bananaSrv.go

/posts/go-clean-layout/images/uncle_bob.png

internal目录存放的就是项目核心代码啦,这里假设是常规的后端项目,并遵循Uncle Bob的整洁架构:

  • controller层负责暴露接口并调用service和domain,处理输入校验与输出等对外的工作
  • service层与domain层负责核心业务逻辑的执行
  • domain层还负责存放领域对象的定义
  • repo层负责持久化存储

Reference

本文主要用来当cheatsheet,方便随用随读,一些子目录(如api,deployment等)下具体的结构和整个项目结构的详细说明在这里:

06 | 目录结构设计:如何组织一个可维护、可扩展的代码目录?-极客时间

https://github.com/bxcodec/go-clean-arch

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