从零开始做 Go 项目:我的目录设计分享

为什么要先规划目录结构

刚开始写 Go 项目的时候,我对目录结构这件事格外重视。对于刚入门的人来说,开发过程中几乎每件事情都是第一次:

  • 全局配置怎么放?
  • 数据库连接怎么初始化?
  • Model 怎么设计?
  • 路由怎么组织?

每一个点都能让人迷茫。

相比之下,像 Java 的 Spring Boot 或 PHP 的 Laravel 都会给你一套"默认结构",至少能让你知道应该往哪里放东西。

而 Go 更自由,没有强迫你必须怎么做。对老手是好事,对新手却可能会踩坑。

我的经验是:

合理的目录结构 = 清晰的思路 + 舒适的开发体验

规划好结构之后,你可以把问题拆开逐个去实现,而不是一上来就面对一坨混乱的代码。


我的 Go 项目目录结构(Gin 示例)

下面是我常用的目录结构,适合大多数中小型 Web 项目:

复制代码
.
├── cmd/              # 项目入口目录
│   └── main.go       # 主程序入口
├── internal/         # 私有代码目录
│   ├── dto/          # 结构体定义目录
│   ├── handler/      # HTTP处理器(等同于Controller)
│   ├── model/        # 数据模型
│   ├── repository/   # 数据模型访问层
│   ├── router/       # 路由
│   └── service/      # 业务逻辑层
├── pkg/              # 可被外部引用的包
│   ├── config/       # 配置
│   ├── i18n/         # 国际化
│   ├── jwt/          # jwt
│   ├── middleware/   # 中间件
│   └── utils/        # 工具函数
├── api/              # API文档(Swagger)
│   └── swagger.json
├── scripts/          # 构建、部署脚本目录
├── go.mod
├── LICENSE
├── Makefile          # 自动化脚本说明书
└── README.md

cmd/:项目入口

cmd 存放整个项目的入口程序。

通常项目只有一个:

复制代码
cmd/
└── main.go

如果未来拆成多个服务(如 API + Worker),结构可以扩展成:

复制代码
cmd/
├── api/
│   └── main.go
├── worker/
│   └── main.go

这样多服务更好管理。


internal/:项目私有代码

internal​ 是 Go 官方定义的 ​私有代码机制:这里的包只能本项目引用,外部无法导入。

我会把它拆成几个层次,职责分明:

复制代码
internal/
├── dto/          # 请求/响应结构体
├── handler/      # HTTP 层
├── service/      # 业务逻辑层
├── repository/   # 数据访问层
├── model/        # 数据模型
└── router/       # 路由注册

调用链是单向的:

Handler → Service → Repository → Model

下面简单说一下每层负责什么:

  • Handler:接收/解析请求,参数校验,调用 Service
  • Service:业务逻辑处理
  • Repository:数据库读写(纯 CRUD,不写业务)
  • Model:数据库结构体
  • DTO:请求/响应结构(隔离 Model)
  • Router:注册路由,绑定 Handler

这种分层结构很适合 Go,也比 PHP 那种"一个 controller 干到底"的写法更好维护。

另外,Go 的一个特点是:

同一个 package 下多个 ​.go​文件对编译器来说等同于同一个文件。

所以可以自由地按模块拆成多个 user.go​、order.go,对程序来说他们直接就是一个文件不会有任何影响,但分开之后代码的可读性会极大的提高。

如果你有其他面向对象语言的经验,Go会带来全新的编程体验。核心的思维转变可归纳为四点:

  1. 忘掉"类" → 记住"结构体+方法"
  2. 忘掉"继承" → 使用"组合+接口"
  3. 忘掉"设计模式套用" → 关注"解决问题"
  4. 接受显式错误处理 → 不再有try-catch

pkg/:可复用的公共包

pkg 用来放可被其他项目引用的通用模块,例如:

复制代码
pkg/
├── config/
├── i18n/
├── jwt/
├── middleware/
└── utils/

如果只是给当前项目用,不需要放在 pkg​,尽量归到 internal

另外也建议不要堆一个"大 utils",按功能拆分更容易维护。


api/:API 文档

这里一般放 Swagger / OpenAPI 的定义文件(JSON/YAML)。

用这些工具来管理接口文档可以:

  • 自动生成文档
  • 保持前后端对齐

对于多人协作非常有用。


Makefile:常用命令的"快捷键"

我一般会把常用命令写进 Makefile,比如:

makefile 复制代码
run:
    go run cmd/main.go

build:
    go build -o bin/app cmd/main.go

test:
    go test ./...

Makefile 是个好东西,你可以把各种项目会用到的命令像清单一样列出来。

如果你有心思,甚至可以去做一个 help 命令来告诉其他人都有什么命令

makefile 复制代码
help:
	@echo "可用指令:"
	@echo "  make deps          # 安装 / 更新 Go 依赖"
	@echo "  make fmt           # 统一格式化后端 Go 代码"
	@echo "  make test          # 执行全部 Go 单元测试"

对新同事非常友好,哪怕不了解项目,也可以通过阅读 Makefile 快速上手项目。


总结

对我来说,一旦目录结构定下来,剩下的基本就像做"填空题"一样:

  • 中间件怎么写
  • JWT 怎么做
  • 数据库要建哪些表
  • Handler / Service / Repository 各自实现哪些逻辑

这些都能一块一块稳稳推进。

Go 社区里没有唯一正确的结构,但这套分层思路对新手来说非常友好,也足够应对大部分项目。

如果你正在准备写一个 Go 项目,希望这套结构能帮你少踩一些坑,也让你的项目更容易维护。

相关推荐
小蒜学长几秒前
springboot党建云课堂学习与管理系统(代码+数据库+LW)
java·数据库·spring boot·后端·学习
烂蜻蜓2 小时前
Flask入门教程(十二):表单处理——从基础到Flask-WTF完整实践
后端·python·flask
Chester_19998 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
2601_962055979 小时前
跟据spring boot版本,查看对应的tomcat,并查看可支持的tomcat的版本范围
spring boot·后端·tomcat
EXI-小洲9 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
会周易的程序员9 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
机器视觉知识推荐、就业指导10 小时前
为什么老说“纯 Qt 没啥就业市场”?
开发语言·qt
telepan10 小时前
Qt 开发避坑与性能指南:如何优雅、安全地定义全局常量字符串?
开发语言·qt
m0_6952514910 小时前
Qt MaintenanceTool 使用国内镜像加速下载(超详细教程)
开发语言·qt