项目结构没有严格标准的划分,项目的结构与项目类型有很大关系,不同的项目类型采用的项目结构也不相同,不同的项目复杂度也应该采用不同项目结构,因此以下内容仅供参考。

目录结构分为结构化目录结构和平铺式目录结构两种。

  • 平铺式目录结构主要用在 Go 包中,相对来说比较简单;
  • 结构化目录结构主要用在 Go 应用中,相对来说比较复杂;

平铺式目录

整个目录结构看起来更像是一层的,例如 log 包 github.com/golang/glog 就是平铺式的,目录如下:

  1. $ ls glog/
  2. glog_file.go glog.go glog_test.go LICENSE README

结构化目录

比较流行的项目结构:https://github.com/golang-standards/project-layout

  1. ├── api
  2. ├── assets
  3. ├── build
  4. ├── cmd
  5. ├── configs
  6. ├── deployments
  7. ├── docs
  8. ├── examples
  9. ├── githooks
  10. ├── go.mod
  11. ├── init
  12. ├── internal
  13. ├── LICENSE.md
  14. ├── Makefile
  15. ├── pkg
  16. ├── README_zh-CN.md
  17. ├── scripts
  18. ├── test
  19. ├── third_party
  20. ├── tools
  21. ├── vendor
  22. ├── web
  23. └── website

image.png
image.pngimage.png

单体简单web项目目录

  1. ├── api
  2. ├── cmd
  3. ├── main.go
  4. ├── configs
  5. ├── controller
  6. ├── middleware
  7. ├── route.go
  8. ├── models(模型包含数据校验)
  9. ├── service
  10. ├── repository
  11. ├── docs
  12. ├── go.mod
  13. ├── internal
  14. ├── consts
  15. ├── response
  16. ├── LICENSE.md
  17. ├── Makefile
  18. ├── pkg
  19. ├── README_zh-CN.md
  20. ├── scripts
  21. ├── test
  22. ├── web

目录功能介绍

/web

前端代码存放目录,主要用来存放 Web 静态资源,服务端模板和单页应用(SPAs)。

/cmd

一个项目有很多组件,可以把组件 main 函数所在的文件夹统一放在 /cmd 目录下,使用 如下格式

/cmd/<组件名>/main.go

组件目录下的文件应该尽可能的少,main.go文件中的内容也应该尽可能的少,main包中只做一些命令行参数解析、资源初始化、日志设施初始化、数据库连接初始化、Web服务启动等工作。

/internal

存放私有应用和库代码。如果一些代码,你不希望在其他应用和库中被导入,可以将这部分代码放在/internal 目录下。
在引入其它项目 internal 下的包时,Go 语言会在编译时报错:

  1. An import of a path containing the element internal is disallowed
  2. if the importing code is outside the tree rooted at the parent of the
  3. "internal" directory.

如果 internal 目录下直接存放每个组件的源码目录(一个项目可以由一个或多个组件组成),当项目变大、组件增多时,可以将新增加的组件代码存放到 internal 目录,这时 internal 目录就是可扩展的。例如:

  1. ├── internal/
  2. ├── app1
  3. ├── app2
  4. ├── pkg

/internal/pkg:存放项目内可共享,项目外不共享的包。这些包提供了比较基础、通用的功能,例如工具、错误码、用户验证等功能。
建议是,一开始将所有的共享代码存放在 /internal/pkg 目录下,当该共享代码做好了对外开发的准备后,再转存到 /pkg 目录下。

/pkg

该目录中存放可以被外部应用使用的代码库,其他项目可以直接通过 import 导入这里的代码。所以,我们在将代码库放入该目录时一定要慎重。

/vendor

项目依赖,可通过 go mod vendor 创建。需要注意的是,如果是一个 Go 库,不要提交 vendor 依赖包。

/third_party

外部帮助工具,分支代码或其他第三方应用(例如 Swagger UI)。比如我们 fork 了一个第三方 go 包,并做了一些小的改动,我们可以放在目录 /third_party/forked 下。一方面可以很清楚的知道该包是 fork 第三方的,另一方面又能够方便地和 upstream 同步。

/test

用于存放其他外部测试应用和测试数据。/test 目录的构建方式比较灵活:对于大的项目,有一个数据子目录是有意义的。例如,如果需要 Go 忽略该目录中的内容,可以使用 /test/data 或 /test/testdata 目录。
需要注意的是,Go 也会忽略以 . 或 _ 开头的目录或文件。这样在命名测试数据目录方面,可以具有更大的灵活性。

/configs

这个目录用来存放配置文件模板或默认配置

/deployments

用来存放 Iaas、PaaS 系统和容器编排部署配置和模板(Docker-Compose,Kubernetes/Helm,Mesos,Terraform,Bosh)。在一些项目,特别是用 Kubernetes 部署的项目中,这个目录可能命名为 deploy。

/init

存放初始化系统(systemd,upstart,sysv)和进程管理配置文件(runit,supervisord)。比如 sysemd 的 unit 文件。这类文件,在非容器化部署的项目中会用到。

Makefile

一个 Go 项目在其根目录下应该有一个 Makefile 工具,用来对项目进行管理,Makefile 通常用来执行静态代码检查、单元测试、编译等功能。其他常见功能:

  • 静态代码检查(lint):推荐用 golangci-lint。
  • 单元测试(test):运行 go test ./…。
  • 编译(build):编译源码,支持不同的平台,不同的 CPU 架构。
  • 镜像打包和发布(image/image.push):现在的系统比较推荐用 Docker/Kubernetes 进行部署,所以一般也要有镜像构建功能。
  • 清理(clean):清理临时文件或者编译后的产物。
  • 代码生成(gen):比如要编译生成 protobuf pb.go 文件。
  • 部署(deploy,可选):一键部署功能,方便测试。
  • 发布(release):发布功能,比如:发布到 Docker Hub、github 等。
  • 帮助(help):告诉 Makefile 有哪些功能,如何执行这些功能。
  • 版权声明(add-copyright):如果是开源项目,可能需要在每个文件中添加版权头,这可以通过 Makefile 来添加。
  • API 文档(swagger):如果使用 swagger 来生成 API 文档,这可以通过 Makefile 来生成。

建议:直接执行 make 时,执行如下各项 format -> lint -> test -> build,如果是有代码生成的操作,还可能需要首先生成代码 gen -> format -> lint -> test -> build。

/scripts

该目录主要用来存放脚本文件,实现构建、安装、分析等不同功能。不同项目,里面可能存放不同的文件,但通常可以考虑包含以下 3 个目录:

  • /scripts/make-rules:用来存放 makefile 文件,实现 /Makefile 文件中的各个功能。Makefile 有很多功能,为了保持它的简洁,我建议你将各个功能的具体实现放在 /scripts/make-rules 文件夹下
  • /scripts/lib:shell 库,用来存放 shell 脚本。一个大型项目中有很多自动化任务,比如发布、更新文档、生成代码等,所以要写很多 shell 脚本,这些 shell 脚本会有一些通用功能,可以抽象成库,存放在 /scripts/lib 目录下,比如 logging.sh,util.sh 等。
  • /scripts/install:如果项目支持自动化部署,可以将自动化部署脚本放在此目录下。如果部署脚本简单,也可以直接放在 /scripts 目录下。

另外,shell 脚本中的函数名,建议采用语义化的命名方式,例如 iam::log::info 这种语义化的命名方式,可以使调用者轻松的辨别出函数的功能类别,便于函数的管理和引用。

/build

这里存放安装包和持续集成相关的文件。这个目录下有 3 个大概率会使用到的目录,在设计目录结构时可以考虑进去。

  • /build/package:存放容器(Docker)、系统(deb, rpm, pkg)的包配置和脚本。
  • /build/ci:存放 CI的配置文件和脚本。
  • /build/docker:存放子项目各个组件的 Dockerfile 文件。

/tools

存放这个项目的支持工具。这些工具可导入来自 /pkg 和 /internal 目录的代码。

/githooks
Git 钩子。比如,我们可以将 commit-msg 存放在该目录。

/assets

项目使用的其他资源 (图片、CSS、JavaScript 等)。

/website

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

/README.md

项目的 README 文件一般包含了项目的介绍、功能、快速安装和使用指引、详细的文档链接以及开发指引等。

/docs

存放设计文档、开发文档和用户文档等(除了 godoc 生成的文档)。推荐存放以下几个子目录:

  • /docs/devel/{en-US,zh-CN}:存放开发文档、hack 文档等。
  • /docs/guide/{en-US,zh-CN}: 存放用户手册,安装、quickstart、产品文档等,分为中文文档和英文文档。
  • /docs/images:存放图片文件。

/CONTRIBUTING.md

开源就绪的项目,用来说明如何贡献代码,如何开源协同等等。CONTRIBUTING.md 不仅能够规范协同流程,还能降低第三方开发者贡献代码的难度。

/api

/api 目录中存放的是当前项目对外提供的各种不同类型的 API 接口定义文件,其中可能包含类似 /api/protobuf-spec、/api/thrift-spec、/api/http-spec、openapi、swagger 的目录,这些目录包含了当前项目对外提供和依赖的所有 API 文件。

/LICENSE

版权文件可以是私有的,也可以是开源的。常用的开源协议有:Apache 2.0、MIT、BSD、GPL、Mozilla、LGPL。

/CHANGELOG

当项目有更新时,为了方便了解当前版本的更新内容或者历史更新内容,需要将更新记录存放到 CHANGELOG 目录。

/examples

存放应用程序或者公共包的示例代码

参考

Go 学习笔记(84)— Go 项目目录结构(开发目录、测试目录、部署目录、项目管理目录 makefile、scripts、build、tools、文档目录、makefile规则)_wohu1104的博客-CSDN博客_go internal目录
GitHub - eddycjy/go-gin-example: An example of gin
https://makeoptim.com/golang/standards/project-layout
project-layout/README_zh-CN.md at master · golang-standards/project-layout
github上有哪些适合新手学习的golang-web开源项目? - 知乎