返回首页

Golang / 项目工程 / 架构

一个合理且优雅的 Golang 项目结构

一个开箱即用、适用于大部分 Web 项目的 Golang 项目结构。物美价廉、实用性强、家喻户晓。

4×3 的纸质文件夹网格,中心一只墨蓝色小 Go gopher 剪影

基本要求

对项目结构做一些基本要求:

  • 功能明确:每一层的功能明确,在编写业务逻辑时具有一定的辨识度,能够轻松进行分层
  • 全面:项目结构中包含研发过程中的主要功能,包括文档、脚本、测试、工具等
  • 可扩展性:当项目业务逻辑更复杂、规模变大时,能够支持扩展
  • 可预测性:随着业务逻辑复杂,项目结构变大,但在结构扩展的同时应该保持结构不需要发生大的变动

逻辑架构

按开发—测试—部署三个阶段以及项目管理、文档,总体如下:

Go 应用
├── 开发阶段
│   ├── 前端    /web
│   └── 后端
│       ├── /cmd
│       ├── /internal
│       ├── /pkg
│       ├── /vendor
│       └── /third_party
├── 测试阶段
│   └── /test
└── 部署阶段
    ├── /configs
    ├── /deployments
    └── /init

项目周期管理
├── /Makefile
├── /build
├── /website
├── /tools
├── /githooks
└── /assets

文档
├── /README.md
├── /docs
├── /LICENSE
├── /api
└── /CONTRIBUTING.md

目录说明

前端

/web —— 前端代码存放目录。

后端

/cmd

  • 存放当前项目的可执行文件
  • cmd 目录下的每一个子目录名称都应该匹配可执行文件。例如,把组件 main 函数所在的文件夹统一放在 /cmd 目录下
  • 不要在 /cmd 目录中放置太多代码,我们应该将公有代码放置到 /pkg 中,将私有代码放置到 /internal 中,并在 /cmd 中引入这些包,保证 main 函数中的代码尽可能简单和少

/internal

  • 存放私有应用和库代码
  • 如果一些代码你不希望被其他项目/库导入,可以放至 /internal 目录下。这在代码编译阶段就会被限制,该目录下的代码不可被外部访问到

一般有以下子目录:

  • /router 路由
  • /application 存放命令与查询
    • /command
    • /query
  • /middleware 中间件
  • /model 模型定义
  • /repository 仓储层,封装数据库操作
  • /response 响应
  • /errmsg 错误处理

/internal 目录下应存放每个组件的源码目录。当项目变大、组件增多时,可以将新增的组件代码继续存放到 /internal 下。

internal 目录并不局限在根目录,在各级子目录中也可以有 internal 子目录,同样起到作用。

/pkg

  • 存放可以被外部应用使用的代码
  • /pkg 目录下的包可以被其他项目引用,所以将代码放入该目录时候一定要慎重
  • 在非根目录下也可以加入 pkg 目录。很多项目会在 internal 目录下加入 pkg 表示内部共享包库

个人建议:一开始将所有的共享代码存放在 /internal/pkg 目录下,当确认可以对外开放时,再转至到根目录的 /pkg 目录下。

/vendor

  • 存放项目依赖
  • 可以通过命令 go mod vendor 创建
  • 如果创建的是一个 Go 库,不要提交 vendor 依赖包

/third_party

  • 存放一些第三方的资源工具文件

测试

/test

  • 存放整个应用的测试、测试数据及一些集成测试
  • 相较于单元测试放在每个 Go 文件对应的目录下,test 目录偏向于整体
  • 在某些子项目内也会有局部的测试放在子项目的 test
  • 需要 Go 忽略该目录中的内容,可以使用 /test/data/test/testdata 目录
  • Go 会忽略 ._ 开头的目录或文件

部署

/config/configs

  • 配置文件或者配置文件模板所在的文件夹
  • 配置中不能携带敏感信息,可用占位符代替

/init

  • 存放初始化系统和进程管理配置文件

/deployments/deploy

  • 存放 IaaS、PaaS 系统和容器编排部署配置和模板

文档

/README.md

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

/docs

各类文档所在目录。存放设计文档、开发文档和用户文档等。

/LICENSE

版权文件。可以是私有的,也可以是开源的。

常用的开源协议:Apache 2.0MITBSDGPLMozillaLGPL

/api

当前项目对外提供的各种不同类型的 API 接口定义文件。其中可能包含类似 OpenAPI、Swagger 的目录,包含了当前项目对外提供和依赖的所有 API 文件。

/CONTRIBUTING.md

说明如何贡献代码,如何开源协同:

  • 规范协同流程
  • 降低第三方开发者贡献代码的难度

项目管理

/Makefile

对项目进行管理。执行静态代码检查、单元测试、编译等功能。

/build

存放安装包和持续集成相关的文件

/website

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

/assets

项目使用的其他资源(如图片等)。

/tools

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

/githooks

Git 钩子。

小结

这个结构不是”必须遵守的教条”,而是一份可预测的默认排布——让新加入的人打开仓库就能猜到”我要改的东西大概在哪个目录”,省去阅读项目文档的时间。

对于小型服务,可以只保留 /cmd/internal/pkg/configs/deployments 这五个即可,其他等到真正需要时再加。不要为了结构完整而制造空目录,那反而增加认知负担。