如何设计一个优秀的 Go Web 项目目录结构

发布时间 2023-04-07 11:16:42作者: 南昌拌粉的成长

基本原则

  • 可读性和可维护性:设计目录结构应该易于阅读和维护,目录名称要简洁、清晰,最好能达到顾名思义的效果。

  • 可扩展性和模块化:设计目录结构应该易于扩展和模块化,随着时间的推移,项目会不断变大,项目的目录结构应该能够很容易支撑这种变化
  • 规范性和一致性:设计目录结构应该遵循规范和一致性,如无特殊情况,目录名称最好统一使用单数形式(特殊情况可以打破,如 /docs/examples

Go 项目标准布局

Go 应用程序相关目录

/cmd

这个目录主要负责程序的启动、初始化、停止等功能,故主要包含项目的入口文件 main.go,如果一个项目有多个组件,则可以存放多个组件的 main.go,例如:

/internal

存放项目的内部私有代码和库,不允许在项目外部使用。同时这也是 Go 在编译时强制执行的校验规则,如果在其他项目中导入 internal 目录下的内容,Go(1.19) 在编译时会得到如下错误

在项目的目录树中的任意位置都可以有 internal 目录,而不仅仅是在顶级目录中。

在 /internal 内部可以增加额外的包结构来区分组件间共享和私有的内部代码:

/pkg

包含可导出的公共库,可以被其他项目引用。这意味着此目录下的代码可以被导入任何其他项目,被当作库程序来使用,所以将代码放到此目录前要慎重考虑,不要将私有代码放到此目录下。

Travis Jeffery 撰写了一篇文章讲解了 pkg 和 internal 目录使用建议,你可以进一步了解学习。

/configs

此目录存放配置文件模板或默认配置。

前文讲设计项目目录的基本原则时提到目录名最好使用单数形式,不过由于使用 configs 来存放配置已经是约定俗成的事实标准,故此目录名称可以打破这项设计原则。

/test

可以用来存放 e2e 测试和测试数据等。

对于较大的项目,有一个数据子目录更好一些。例如,如果需要 Go 在编译时忽略目录中的内容,则可以使用 /test/data 或 /test/testdata 这样的目录名称。

另外 Go 还会忽略以 . 或 _ 开头的目录或文件,因此可以更具灵活性的来命名测试数据目录。

deployments

用来存放 IaaS、PaaS 系统和容器编排部署所需要的配置及模板(如:Docker-Compose,Kubernetes/Helm,Mesos,Terraform,Bosh)。

如果你的项目作为 Kubernetes 生态中的一员或使用 Kubernetes 部署,则建议命名为 /deploy,更加符合 Kubernetes 社区风格。

/third_party

外部辅助工具目录,fork 的代码和其他第三方工具(例如 Swagger UI)。比如我们修改了某个开源的第三方项目的代码,使其满足当前项目的使用需求,就可以将修改后的代码放到 /third_party/fork 目录下进行维护。

/web

如果你打算在项目目录下包含配套的前端程序代码,则可以存放到此目录。主要包括静态资源、前端代码、路由等。

如果你的项目仅提供 RESTful API,且前后端程序需要分开独立维护,则可以不需要此目录,建议将前端代码作为一个独立的项目存在

项目管理相关目录

/init

包含系统初始化(systemd、upstart、sysv)和进程管理(runit、supervisord)等配置。这在非容器化部署的项目中非常有用。

另外还可以包含初始化代码,如数据库迁移、缓存初始化等。

/scripts

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

根文件 /Makefile 可以引用这些脚本,使其变得更小、更易于维护。

/build

存放程序构建和持续集成相关的文件。例如:

使用 /build/package 目录来存放云(AMI),容器(Docker),操作系统(deb,rpm,pkg)软件包配置和脚本。

使用 /build/ci 目录来存放 CI(travis、circle、drone)配置文件和脚本。

/tools

此项目的支持工具。这些工具可以从 /pkg 和 /internal 目录导入代码。

/assets

项目使用的其他资源 (Image、CSS、JavaScript、SQL 文件等)。

/githooks

Git 相关的钩子存放目录

项目文档相关目录

/api

当前项目对外暴露的 API 文档,如 OpenAPI/Swagger 规范文档、JSON Schema 文件、ProtoBuf 定义文件等

/docs

设计、开发和用户文档等(除 godoc 生成的文档)。

/examples

应用程序或公共库的示例。降低使用者的上手难度。