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

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

Go 语言作为一门高效、简洁、并发安全的语言,越来越受到开发者们的青睐,特别是在 Web 开发及云原生领域。而对于一个大型的 Go Web 项目而言,一个优秀的目录结构设计是必不可少的。它可以帮助我们更好地组织代码、减少冗余、提高可维护性和可扩展性。在本文中,我们将讨论如何设计一个优秀的 Go Web 项目目录结构。

基本原则

在开始设计项目目录结构之前,我们需要先了解一些设计目录的基本原则:

  • 可读性和可维护性:设计目录结构应该易于阅读和维护,目录名称要简洁、清晰,最好能达到顾名思义的效果。
  • 可扩展性和模块化:设计目录结构应该易于扩展和模块化,随着时间的推移,项目会不断变大,项目的目录结构应该能够很容易支撑这种变化。
  • 规范性和一致性:设计目录结构应该遵循规范和一致性,如无特殊情况,目录名称最好统一使用单数形式(特殊情况可以打破,如 /docs/examples)。

Go 项目标准布局

早期的 Go 项目目录结构设计五花八门,因为大多数 Go 开发者都有其他编程语言基础,比如 Java、Python 等,这些开发者在设计 Go 项目时,目录结构往往会携带一些其他编程语言、框架所惯用的风格。

但很多情况下,直接套用其他编程语言风格的目录所设计出来的 Go 项目都会有很多不合理之处,为了改变现状,慢慢的 Go 语言社区诞生了很多更符合 Go 哲学的项目目录风格。而这其中,最著名的项目当属 golang-standards/project-layout

golang-standards/project-layout 是一个 Go 社区维护的 Go 项目目录结构标准,它的目标是提供一种一致性的、易于理解和使用的目录结构,从而帮助开发者更好地组织和管理自己的代码。

该项目的目录结构基于功能和约定进行组织,通过提供一种标准化的目录结构,可以使得不同的项目之间具有一致的代码组织方式,便于开发者理解和使用。

该项目的目录结构包括以下几个部分:

Go 应用程序相关目录

/cmd

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

1
2
3
4
5
6
7
cmd
├── ctl
│   └── main.go
├── server
│   └── main.go
└── task
    └── main.go

不要在这个目录中放太多的代码,更不要放业务逻辑代码,保持整洁。

/internal

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

1
use of internal package xxx not allowed

注:xxx 为包含 internal 的包路径

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

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

1
2
3
4
5
6
internal
├── app
│   ├── ctl
│   ├── server
│   └── task
└── pkg

其中 /internal/app 下存放各个组件的逻辑代码,/internal/pkg 下存放各组件间的共享代码。

/pkg

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

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

/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 定义文件等。

1
2
3
api
└── openapi
    └── openapi.yaml
/docs

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

/examples

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

不建议使用的目录

/src

一些有 Java 或 Python 开发经验的开发者习惯在项目中设计一个 /src 目录,但在 Go 语言中这是不推荐的做法。

早期的 Go 语言的项目都会被放置到 $GOPATH/src 目录下,如果项目中再有一个 /src 目录,那么项目最终的存放的路径就显得比较奇怪:

1
$GOPATH/src/your_project/src/your_code.go

因此,请不要在一个 Go 项目中设计 /src 目录。

一些放在项目根目录下的文件

/README.md

README.md 是学习并使用项目的入口,是让用户了解项目的第一手资料。一个项目的 README.md 通常包含项目名称和简介、安装说明、使用说明、贡献方式、版权和许可等。

GitHub 也会默认解析 README.md 文件并渲染成 HTML 文档。

/Makefile

Makefile 是一个老牌的项目管理工具,建议在 Go 项目中都集成它。Makefile 语法可以参考 跟我一起写 Makefile

/CHANGELOG

用于存放项目的更新记录,如版本号、作者、更新内容等。如果嫌麻烦,还可以使用 git-chglog 或类似工具自动生成。

/CONTRIBUTING.md

如果你的项目是开源项目,则建议包含 /CONTRIBUTING.md 文件,用来说明如何贡献代码、项目规范等,让第三方开发者更容易参与进来。

/LICENSE

开源项目一定要包含 /LICENSE,即开源许可证。没有开源许可证的项目,严格来讲不叫开源项目,如何选择开源许可证可以参考我的另一篇文章 开源协议简介

总结

经过上面的讲解,最终我们得到的项目目录结构如下:

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
project
├── CHANGELOG
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── api
│   └── openapi
│       └── openapi.yaml
├── assets
├── build
├── cmd
│   ├── ctl
│   │   └── main.go
│   ├── server
│   │   └── main.go
│   └── task
│       └── main.go
├── configs
├── deployments
├── docs
├── examples
├── githooks
├── init
├── internal
│   ├── app
│   │   ├── ctl
│   │   ├── server
│   │   └── task
│   └── pkg
├── pkg
├── scripts
├── test
├── third_party
├── tools
└── web

此目录结构主要参考 golang-standards/project-layout 项目,和一些我自己的思考,最终总结出来。

通过使用以上提供的项目目录结构,可以帮助开发者更好地管理和组织自己的代码,提高代码的可维护性和可扩展性。

以上介绍的目录结构比较适合中大型项目,如果你的项目比较小,则可以只使用 /cmd/internal/configs 等几个少量目录,其他目录根据需要再来创建。如果你的项目足够小,甚至不需要什么目录,直接采用平铺式代码结构(将所有文件都放在项目根目录下)即可。

另外,随着技术的不断迭代发展,如 DDD 正在流行起来,Go 社区对项目目录结构的探索也仍在继续,在可预见的未来,一个优秀的 Go Web 项目目录结构的定义一定会被更新,期待下次能够分享更优秀的目录结构设计。

P.S.

本文部分内容由 ChatGPT 生成,体验科技乐趣 :)。

参考

Standard Go Project Layout:https://github.com/golang-standards/project-layout

Standard Go Project Layout 中文文档:https://github.com/golang-standards/project-layout/blob/master/README_zh-CN.md

Go 面向包的设计和架构分层:https://github.com/danceyoung/paper-code/blob/master/package-oriented-design/packageorienteddesign.md

pkg 和 internal 目录使用建议:https://travisjeffery.com/b/2019/11/i-ll-take-pkg-over-internal/

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
10月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
678 4
|
11月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
844 1
|
JavaScript Java 微服务
现代化 Java Web 在线商城项目技术方案与实战开发流程及核心功能实现详解
本项目基于Spring Boot 3与Vue 3构建现代化在线商城系统,采用微服务架构,整合Spring Cloud、Redis、MySQL等技术,涵盖用户认证、商品管理、购物车功能,并支持Docker容器化部署与Kubernetes编排。提供完整CI/CD流程,助力高效开发与扩展。
1164 64
|
10月前
|
开发框架 前端开发 Go
【GoGin】(0)基于Go的WEB开发框架,GO Gin是什么?怎么启动?本文给你答案
Gin:Go语言编写的Web框架,以更好的性能实现类似Martini框架的APInet/http、Beego:开源的高性能Go语言Web框架、Iris:最快的Go语言Web框架,完备的MVC支持。
727 1
|
监控 Java 编译器
限流、控并发、减GC!一文搞懂Go项目资源优化的正确姿势
本章介绍Go语言项目在构建与部署阶段的性能调优和资源控制策略,涵盖编译优化、程序性能提升、并发与系统资源管理、容器化部署及自动化测试等内容,助力开发者打造高效稳定的生产级应用。
|
测试技术 Go 开发工具
Go语言项目工程化 — 常见开发工具与 CI/CD 支持
Go语言项目工程化实践中的开发工具与CI/CD支持,涵盖格式化、静态检查、依赖管理、构建打包、自动化测试及部署策略。内容包括常用工具如gofmt、go vet、golangci-lint、Docker、GitHub Actions等,并提供实战建议与总结,提升团队协作效率与项目质量。
|
NoSQL 中间件 Go
Go语言项目工程化 — 项目结构与模块划分
本章讲解Go语言项目工程化中的结构设计与模块划分,涵盖单体及分层架构方案,指导如何按功能组织代码,提升项目的可维护性、扩展性,适用于不同规模的开发场景。
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
JSON 安全 Go
Go语言项目工程化 —— 日志、配置、错误处理规范
本章详解Go语言项目工程化核心规范,涵盖日志、配置与错误处理三大关键领域。在日志方面,强调其在问题排查、性能优化和安全审计中的作用,推荐使用高性能结构化日志库zap,并介绍日志级别与结构化输出的最佳实践。配置管理部分讨论了配置分离的必要性,对比多种配置格式如JSON、YAML及环境变量,并提供viper库实现多环境配置的示例。错误处理部分阐述Go语言显式返回error的设计哲学,讲解标准处理方式、自定义错误类型、错误封装与堆栈追踪技巧,并提出按调用层级进行错误处理的建议。最后,总结各模块的工程化最佳实践,助力构建可维护、可观测且健壮的Go应用。
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。

热门文章

最新文章